同步PD:日志系统
同步PD:6.7.1
This commit is contained in:
@@ -258,4 +258,6 @@ dependencies {
|
||||
//声网SDK
|
||||
//api 'io.agora.rtc:agora-special-full:4.2.6.245'
|
||||
api 'com.xj.marqueeView:marqueeView:0.1.20'
|
||||
|
||||
api rootProject.ext.dependencies["blank-utilcode"]
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ public abstract class AbsActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
create();
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
isFullWindow = getIntent().getBooleanExtra("isFull", false);
|
||||
@@ -68,6 +67,7 @@ public abstract class AbsActivity extends AppCompatActivity {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
}
|
||||
}
|
||||
create();
|
||||
super.onCreate(savedInstanceState);
|
||||
mTag = this.getClass().getSimpleName();
|
||||
setStatusBar();
|
||||
@@ -133,7 +133,7 @@ public abstract class AbsActivity extends AppCompatActivity {
|
||||
/**
|
||||
* 设置透明状态栏
|
||||
*/
|
||||
private void setStatusBar() {
|
||||
public void setStatusBar() {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getWindow();
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
@@ -12,6 +13,7 @@ import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
@@ -82,6 +84,15 @@ public class WebViewActivity extends AbsActivity {
|
||||
return R.layout.activity_webview;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void setStatusBar() {
|
||||
getWindow().setStatusBarColor(Color.parseColor("#FFFFFF"));
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void main() {
|
||||
String url = getIntent().getStringExtra(Constants.URL);
|
||||
|
||||
16
common/src/main/java/com/yunbao/common/bean/QiniuLog.java
Normal file
16
common/src/main/java/com/yunbao/common/bean/QiniuLog.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.yunbao.common.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
|
||||
public class QiniuLog extends BaseModel{
|
||||
@JSONField(name = "log_type")
|
||||
private int log_type;
|
||||
|
||||
public int getLog_type() {
|
||||
return log_type;
|
||||
}
|
||||
|
||||
public void setLog_type(int log_type) {
|
||||
this.log_type = log_type;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import android.util.Log;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.blankj.utilcode.util.DeviceUtils;
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.callback.Callback;
|
||||
import com.lzy.okgo.callback.StringCallback;
|
||||
@@ -29,6 +30,7 @@ import com.yunbao.common.utils.AppManager;
|
||||
import com.yunbao.common.utils.DialogUitl;
|
||||
import com.yunbao.common.utils.L;
|
||||
import com.yunbao.common.utils.SpUtil;
|
||||
import com.yunbao.common.utils.StringUtil;
|
||||
import com.yunbao.common.utils.ToastUtil;
|
||||
import com.yunbao.common.utils.VersionUtil;
|
||||
import com.yunbao.common.utils.WordUtil;
|
||||
@@ -487,6 +489,20 @@ public class CommonHttpUtil {
|
||||
HttpClient.getInstance().get("User.getUserBaseinfo", CommonHttpConsts.GET_USER_BASEINFO)
|
||||
.params("touid", touid)
|
||||
.execute(callback);
|
||||
} /**
|
||||
* 上传文件 获取七牛云token的接口
|
||||
*/
|
||||
public static void getUploadQiNiuTokenLog(HttpCallback callback,String fileName) {
|
||||
String uid = CommonAppConfig.getInstance().getUid();
|
||||
if(StringUtil.isEmpty(uid)){
|
||||
uid="NotLogin_"+ DeviceUtils.getUniqueDeviceId();
|
||||
}
|
||||
HttpClient.getInstance().get("Pdluserhome.getQiNiuToken3", "Pdluserhome.getQiNiuToken3")
|
||||
.params("uid",uid)
|
||||
.params("token", CommonAppConfig.getInstance().getToken())
|
||||
.params("file_name", fileName)
|
||||
.params("ext", ".zip")
|
||||
.execute(callback);
|
||||
}
|
||||
//
|
||||
// //埋点唯一性
|
||||
|
||||
@@ -36,7 +36,6 @@ public abstract class HttpCallback extends AbsCallback<JsonBean> {
|
||||
public void onSuccess(Response<JsonBean> response) {
|
||||
JsonBean bean = response.body();
|
||||
String gson = new Gson().toJson(bean);
|
||||
Log.e("onSuccess", gson);
|
||||
if (bean != null) {
|
||||
|
||||
if (200 == bean.getRet()) {
|
||||
|
||||
@@ -133,15 +133,18 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
ResponseBody responseBody = clone.body();
|
||||
boolean logBody = (printLevel == Level.BODY);
|
||||
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
|
||||
|
||||
StringBuilder sb=new StringBuilder();
|
||||
try {
|
||||
log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)");
|
||||
sb.append("<-- ").append(clone.code())
|
||||
.append(' ').append(clone.message())
|
||||
.append(' ').append(clone.request().url())
|
||||
.append(" (").append(tookMs).append("ms)\n");
|
||||
if (logHeaders) {
|
||||
Headers headers = clone.headers();
|
||||
for (int i = 0, count = headers.size(); i < count; i++) {
|
||||
log("\t" + headers.name(i) + ": " + headers.value(i));
|
||||
sb.append("\t").append(headers.name(i)).append(": ").append(headers.value(i)).append("\n");
|
||||
}
|
||||
log(" ");
|
||||
sb.append("\n");
|
||||
if (logBody && HttpHeaders.hasBody(clone)) {
|
||||
if (responseBody == null) return response;
|
||||
|
||||
@@ -149,18 +152,19 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
byte[] bytes = IOUtils.toByteArray(responseBody.byteStream());
|
||||
MediaType contentType = responseBody.contentType();
|
||||
String body = new String(bytes, getCharset(contentType));
|
||||
log("\tbody:" + body);
|
||||
sb.append("\tbody:").append(body).append("\n");
|
||||
responseBody = ResponseBody.create(responseBody.contentType(), bytes);
|
||||
return response.newBuilder().body(responseBody).build();
|
||||
} else {
|
||||
log("\tbody: maybe [binary body], omitted!");
|
||||
sb.append("\tbody: maybe [binary body], omitted!").append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
OkLogger.printStackTrace(e);
|
||||
} finally {
|
||||
log("<-- END HTTP");
|
||||
sb.append("<-- END HTTP").append("\n");
|
||||
log(sb.toString());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import com.yunbao.common.bean.PrankGiftBean;
|
||||
import com.yunbao.common.bean.PrankGiftResultBean;
|
||||
import com.yunbao.common.bean.PrankHttpTurntableBean;
|
||||
import com.yunbao.common.bean.PrankProgressBean;
|
||||
import com.yunbao.common.bean.QiniuLog;
|
||||
import com.yunbao.common.bean.QuickGiftSendGiftModel;
|
||||
import com.yunbao.common.bean.RandomPkUserBean;
|
||||
import com.yunbao.common.bean.RankPkInfoBean;
|
||||
@@ -1405,4 +1406,8 @@ public interface PDLiveApi {
|
||||
@Query("anchor_id")String anchor_id,
|
||||
@Query("gift_id")String gift_id
|
||||
);
|
||||
@GET("/api/public/?service=Tx.androidQiniuLog")
|
||||
Observable<ResponseModel<QiniuLog>> getPrankList(
|
||||
@Query("type")String type
|
||||
);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import com.yunbao.common.bean.PrankGiftBean;
|
||||
import com.yunbao.common.bean.PrankGiftResultBean;
|
||||
import com.yunbao.common.bean.PrankHttpTurntableBean;
|
||||
import com.yunbao.common.bean.PrankProgressBean;
|
||||
import com.yunbao.common.bean.QiniuLog;
|
||||
import com.yunbao.common.bean.QuickGiftSendGiftModel;
|
||||
import com.yunbao.common.bean.RandomPkUserBean;
|
||||
import com.yunbao.common.bean.RankPkInfoBean;
|
||||
@@ -3298,6 +3299,32 @@ public class LiveNetManager {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报日志相关
|
||||
* @param type 1为查询,3为删除
|
||||
* @param callback
|
||||
*/
|
||||
public void getLogUpdateStatus(String type, HttpCallback<QiniuLog>callback) {
|
||||
API.get().pdLiveApi(mContext)
|
||||
.getPrankList(type)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(listResponseModel -> {
|
||||
if (callback != null) {
|
||||
callback.onSuccess(listResponseModel.getData().getInfo());
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
throwable.printStackTrace();
|
||||
if (callback != null) {
|
||||
callback.onError(mContext.getString(R.string.net_error));
|
||||
}
|
||||
}
|
||||
}).isDisposed();
|
||||
|
||||
}
|
||||
|
||||
public void getPdluserFriend(int p, HttpCallback<List<MessageChatUserBean>> callback) {
|
||||
API.get().pdLiveApi(mContext)
|
||||
.getPdluserFriend(p)
|
||||
@@ -3551,7 +3578,6 @@ public class LiveNetManager {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void updateFile(File file, HttpCallback<AvatarBean> callback) {
|
||||
MultipartBody.Part uploadFile = createUploadFile(file);
|
||||
API.get().pdLiveApi(mContext)
|
||||
|
||||
@@ -11,6 +11,7 @@ public class UploadBean {
|
||||
public static final int IMG = 0;
|
||||
public static final int VIDEO = 1;
|
||||
public static final int VOICE = 2;
|
||||
public static final int LOG = 3;
|
||||
private File mOriginFile;//要被上传的源文件
|
||||
private File mCompressFile;//压缩后的图片文件
|
||||
private String mRemoteFileName;//上传成功后在云存储上的文件名字
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.yunbao.common.upload;
|
||||
|
||||
import static java.text.DateFormat.DEFAULT;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -11,6 +13,7 @@ import com.qiniu.android.storage.UpCompletionHandler;
|
||||
import com.qiniu.android.storage.UploadManager;
|
||||
import com.yunbao.common.http.CommonHttpUtil;
|
||||
import com.yunbao.common.http.HttpCallback;
|
||||
import com.yunbao.common.manager.IMLoginManager;
|
||||
import com.yunbao.common.utils.L;
|
||||
import com.yunbao.common.utils.StringUtil;
|
||||
|
||||
@@ -18,7 +21,10 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import top.zibin.luban.Luban;
|
||||
|
||||
@@ -52,7 +58,9 @@ public class UploadQnImpl implements UploadStrategy {
|
||||
assert response != null;
|
||||
mList.get(mIndex).setRemoteAccessUrl(response.getString("key"));
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
// throw new RuntimeException(e);
|
||||
L.e(e);
|
||||
return;
|
||||
}
|
||||
if (mList == null || mList.size() == 0) {
|
||||
if (mUploadCallback != null) {
|
||||
@@ -72,6 +80,8 @@ public class UploadQnImpl implements UploadStrategy {
|
||||
compressedFile.delete();
|
||||
}
|
||||
}
|
||||
} else if (uploadBean.getType() == UploadBean.LOG) {
|
||||
uploadBean.getOriginFile().delete();
|
||||
}
|
||||
mIndex++;
|
||||
if (mIndex < mList.size()) {
|
||||
@@ -90,6 +100,10 @@ public class UploadQnImpl implements UploadStrategy {
|
||||
|
||||
@Override
|
||||
public void upload(List<UploadBean> list, boolean needCompress, UploadCallback callback, boolean isImg) {
|
||||
upload(list, needCompress, callback, isImg, false);
|
||||
}
|
||||
|
||||
public void upload(List<UploadBean> list, boolean needCompress, UploadCallback callback, boolean isImg, boolean isLog) {
|
||||
System.err.println("-------upload------>" + list.size());
|
||||
if (callback == null) {
|
||||
return;
|
||||
@@ -127,7 +141,11 @@ public class UploadQnImpl implements UploadStrategy {
|
||||
}
|
||||
};
|
||||
}
|
||||
CommonHttpUtil.getUploadQiNiuTokenNew(mGetUploadTokenCallback, isImg);
|
||||
if (isLog) {
|
||||
CommonHttpUtil.getUploadQiNiuTokenLog(mGetUploadTokenCallback, list.get(0).getOriginFile().getName());
|
||||
} else {
|
||||
CommonHttpUtil.getUploadQiNiuToken(mGetUploadTokenCallback, isImg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,8 +177,16 @@ public class UploadQnImpl implements UploadStrategy {
|
||||
bean.setRemoteFileName(StringUtil.contact(StringUtil.generateFileName(), ".mp4"));
|
||||
} else if (bean.getType() == UploadBean.VOICE) {
|
||||
bean.setRemoteFileName(StringUtil.contact(StringUtil.generateFileName(), ".m4a"));
|
||||
} else if (bean.getType() == UploadBean.LOG) {
|
||||
bean.setRemoteFileName("logs/"
|
||||
+ IMLoginManager.get(mContext).getUserInfo().getId()
|
||||
+ "/"
|
||||
+ SimpleDateFormat.getDateInstance(DEFAULT, Locale.CHINA).format(new Date())
|
||||
+ "/"
|
||||
+ bean.getOriginFile().getName()
|
||||
);
|
||||
}
|
||||
System.err.println("-------mIndex >= bean.getType() == UploadBean.IMG------>" + bean);
|
||||
System.err.println("-------mIndex >= bean.getType() == " + bean.getType() + "------>" + bean);
|
||||
upload(bean);
|
||||
/*if (bean.getType() == UploadBean.IMG && mNeedCompress) {
|
||||
System.err.println("-------UploadBean.IMG && mNeedCompress------>" + bean + "UploadBean.IMG:" + UploadBean.IMG + "__mNeedCompress" + mNeedCompress);
|
||||
|
||||
@@ -2,6 +2,13 @@ package com.yunbao.common.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Created by cxf on 2017/8/3.
|
||||
*/
|
||||
@@ -24,13 +31,23 @@ public class L {
|
||||
}
|
||||
}
|
||||
|
||||
final static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
|
||||
|
||||
public static void e(String tag, String s) {
|
||||
if (sDeBug) {
|
||||
Log.e(tag, s);
|
||||
} else {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
Log.e(tag, uuid);
|
||||
LogUtils.addSafeLog(dateFormat.format(new Date()) + " [" + uuid + "|" + tag + "] " + s);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setDeBug(boolean deBug) {
|
||||
sDeBug = deBug;
|
||||
}
|
||||
|
||||
public static void e(Exception e) {
|
||||
Log.e("Exception", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,28 +24,25 @@ import com.lzy.okgo.request.PostRequest;
|
||||
import com.lzy.okserver.OkUpload;
|
||||
import com.lzy.okserver.upload.UploadListener;
|
||||
import com.lzy.okserver.upload.UploadTask;
|
||||
import com.yunbao.common.BuildConfig;
|
||||
import com.yunbao.common.CommonAppConfig;
|
||||
import com.yunbao.common.bean.IMLoginModel;
|
||||
import com.yunbao.common.manager.IMLoginManager;
|
||||
import com.yunbao.common.http.live.LiveNetManager;
|
||||
import com.yunbao.common.upload.UploadBean;
|
||||
import com.yunbao.common.upload.UploadCallback;
|
||||
import com.yunbao.common.upload.UploadQnImpl;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
@@ -149,91 +146,56 @@ public class LogUtil {
|
||||
|
||||
|
||||
public static void shareFile(Context context) {
|
||||
try {
|
||||
IMLoginModel bean = IMLoginManager.get(context).getUserInfo();
|
||||
boolean isAnchor = false;
|
||||
if (bean != null) {
|
||||
isAnchor = bean.anchorUserType();
|
||||
}
|
||||
//有debug文件或主播才允许
|
||||
if (!new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "pdlive.debug").exists() && !isAnchor) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
/* if (PermissionChecker.checkCallingOrSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
|
||||
return;
|
||||
}*/
|
||||
String title = "[PDLIVE]" + CommonAppConfig.getInstance().getUid() + "_";
|
||||
String title = "[Pandorapan]" + CommonAppConfig.getInstance().getUid() + "_";
|
||||
String today = title + SimpleDateFormat.getDateInstance(DEFAULT, Locale.CHINA).format(new Date());
|
||||
File dir = new File(context.getDir("files", Context.MODE_PRIVATE).getAbsolutePath() + File.separator);
|
||||
File dir = new File("/data/data/" + context.getPackageName() + File.separator);
|
||||
File zip = new File(context.getDir("files", Context.MODE_PRIVATE).getAbsolutePath() + File.separator + today + ".zip");
|
||||
|
||||
try {
|
||||
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zip)));
|
||||
FileInputStream fis = null;
|
||||
WritableByteChannel writableByteChannel = Channels.newChannel(zos);
|
||||
if (dir.listFiles() != null) {
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.getName().endsWith(".log")) {
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
zos.putNextEntry(entry);
|
||||
fis = new FileInputStream(file);
|
||||
FileChannel channel = fis.getChannel();
|
||||
channel.transferTo(0, file.length() - 1, writableByteChannel);
|
||||
fis.close();
|
||||
List<String> filters = getFiltersList(context.getPackageName());
|
||||
filters.add(context.getPackageName() + File.separator + "app_files" + File.separator + today + ".zip");
|
||||
List<String> srcList = new ArrayList<>();
|
||||
srcList.add(dir.getAbsolutePath());
|
||||
srcList.add(context.getExternalFilesDir("").getAbsolutePath());
|
||||
LogUtils.endSafeLog();
|
||||
ZipUtils.zipFolder(srcList, zip.getAbsolutePath(), filters, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// return;
|
||||
}
|
||||
UploadQnImpl mUploadStrategy = new UploadQnImpl(context);
|
||||
List<UploadBean> list = new ArrayList<>();
|
||||
list.add(new UploadBean(zip, UploadBean.LOG));
|
||||
mUploadStrategy.upload(list, false, new UploadCallback() {
|
||||
@Override
|
||||
public void onFinish(List<UploadBean> list, boolean success) {
|
||||
if (success) {
|
||||
LiveNetManager.get(context).getLogUpdateStatus("3", null);
|
||||
}
|
||||
LogUtils.startSafeLog(context);
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
}
|
||||
zos.close();
|
||||
writableByteChannel.close();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (zip.exists()) {
|
||||
DialogUitl.showSimpleDialog(context, "上报日志", new DialogUitl.SimpleCallback() {
|
||||
@Override
|
||||
public void onConfirmClick(Dialog dialog, String content) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
uploadLog(zip);
|
||||
}
|
||||
}).start();
|
||||
dialog.dismiss();
|
||||
ToastUtil.show("OK");
|
||||
Intent share = new Intent(Intent.ACTION_SEND);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", zip);
|
||||
share.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
} else {
|
||||
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(zip));
|
||||
}
|
||||
share.setType("application/vnd.ms-excel");
|
||||
share.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
context.startActivity(Intent.createChooser(share, "分享文件"));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && CommonAppConfig.IS_GOOGLE_PLAY == 0) {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
Intent intent = new Intent(ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
File out = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + zip.getName());
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Files.copy(zip.toPath(), out.toPath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
private static @NonNull List<String> getFiltersList(String packageName) {
|
||||
List<String> filters = new ArrayList<>();
|
||||
filters.add(packageName + File.separator + "files" + File.separator + "gif");
|
||||
filters.add(packageName + File.separator + "app_textures");
|
||||
filters.add(packageName + File.separator + "app_webview");
|
||||
filters.add(packageName + File.separator + "code_cache");
|
||||
filters.add(packageName + File.separator + "databases");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "https");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "image");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "jtechCache");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "picasso-cache");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "svga");
|
||||
filters.add(packageName + File.separator + "cache" + File.separator + "WebView");
|
||||
return filters;
|
||||
}
|
||||
|
||||
private static String TAG = "Upload";
|
||||
@@ -271,5 +233,36 @@ public class LogUtil {
|
||||
});
|
||||
}
|
||||
|
||||
private static void openShareDialog(Context context, File zip) {
|
||||
Intent share = new Intent(Intent.ACTION_SEND);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", zip);
|
||||
share.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
} else {
|
||||
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(zip));
|
||||
}
|
||||
share.setType("application/vnd.ms-excel");
|
||||
share.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
context.startActivity(Intent.createChooser(share, "分享文件"));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && CommonAppConfig.IS_GOOGLE_PLAY == 0) {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
Intent intent = new Intent(ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
File out = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + zip.getName());
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Files.copy(zip.toPath(), out.toPath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
141
common/src/main/java/com/yunbao/common/utils/LogUtils.java
Normal file
141
common/src/main/java/com/yunbao/common/utils/LogUtils.java
Normal file
@@ -0,0 +1,141 @@
|
||||
package com.yunbao.common.utils;
|
||||
|
||||
import static java.text.DateFormat.DEFAULT;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.yunbao.common.CommonAppConfig;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class LogUtils {
|
||||
private static final LinkedBlockingQueue<String> QUEUE = new LinkedBlockingQueue<>();
|
||||
|
||||
/**
|
||||
* 采集所有日志
|
||||
*/
|
||||
public static void start(Context context) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
String[] exec = new String[]{"logcat", "-c"};
|
||||
Runtime.getRuntime().exec(exec).waitFor();
|
||||
|
||||
exec = new String[]{"logcat", "-v", "color", "UTC-8"};
|
||||
|
||||
Process process = Runtime.getRuntime().exec(exec);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
PrintWriter writer = null;
|
||||
String title = "[Pandorapan]" + CommonAppConfig.getInstance().getUid() + "_";
|
||||
String today = title + SimpleDateFormat.getDateInstance(DEFAULT, Locale.CHINA).format(new Date());
|
||||
File dir = new File(context.getDir("files", Context.MODE_PRIVATE).getAbsolutePath() + File.separator);
|
||||
if (dir.listFiles() != null) {
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.getName().endsWith(".log") && !"error.log".equals(file.getName())) {
|
||||
String fileName = file.getName().replace(".log", "").split("_")[1];
|
||||
if (isDelLog(fileName)) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File saveFile = new File(context.getDir("files", Context.MODE_PRIVATE).getAbsolutePath() + File.separator + today + ".log");
|
||||
FileOutputStream os = new FileOutputStream(saveFile, true);
|
||||
writer = new PrintWriter(os);
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
writer.append(line).write("\n");
|
||||
writer.flush();
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
exec = new String[]{"logcat", "-c"};
|
||||
Runtime.getRuntime().exec(exec).waitFor();
|
||||
bufferedReader.close();
|
||||
start(context);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
startSafeLog(context);
|
||||
}
|
||||
|
||||
private static Thread safeThread;
|
||||
private static boolean writerSafeLog = true;
|
||||
|
||||
public static void startSafeLog(Context context) {
|
||||
if (safeThread != null && safeThread.isAlive()) {
|
||||
return;
|
||||
}
|
||||
safeThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
String title = CommonAppConfig.getInstance().getUid() + "_";
|
||||
String today = title + SimpleDateFormat.getDateInstance(DEFAULT, Locale.CHINA).format(new Date());
|
||||
File saveFile = new File(context.getDir("files", Context.MODE_PRIVATE).getAbsolutePath() + File.separator + today + ".safe");
|
||||
saveFile.createNewFile();
|
||||
FileOutputStream os = new FileOutputStream(saveFile, true);
|
||||
PrintWriter writer = new PrintWriter(os);
|
||||
while (writerSafeLog) {
|
||||
if (!QUEUE.isEmpty()) {
|
||||
writer.append(QUEUE.poll()).write("\n");
|
||||
writer.flush();
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
while (!QUEUE.isEmpty()){
|
||||
writer.append(QUEUE.poll()).write("\n");
|
||||
writer.flush();
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
safeThread.setName("safeLog");
|
||||
safeThread.start();
|
||||
}
|
||||
|
||||
public static void addSafeLog(String log) {
|
||||
QUEUE.offer(log);
|
||||
}
|
||||
|
||||
public static void endSafeLog() {
|
||||
writerSafeLog = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是要删除的日志
|
||||
**/
|
||||
private static boolean isDelLog(String time) {
|
||||
try {
|
||||
Calendar timeCal = Calendar.getInstance(Locale.CHINA);
|
||||
timeCal.setTime(Objects.requireNonNull(SimpleDateFormat.getDateInstance(DEFAULT, Locale.CHINA).parse(time)));
|
||||
Calendar calendar = Calendar.getInstance(Locale.CHINA);
|
||||
calendar.setTime(new Date());
|
||||
calendar.add(Calendar.DATE, -3);
|
||||
return calendar.after(timeCal);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class MessageSayHiNotifyManager {
|
||||
}
|
||||
data.setOldTime(hiBean.getNextTime());
|
||||
hiBean = data;
|
||||
if (data.getUser() == null || data.getStatus()==0) {
|
||||
if (data.getUser() == null || data.getStatus() == 0) {
|
||||
timer.postDelayed(createTask(), data.getNextTime() * 1000L);
|
||||
return;
|
||||
}
|
||||
@@ -126,6 +126,11 @@ public class MessageSayHiNotifyManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
hiBean = null;
|
||||
isInit = false;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
Log.i(TAG, "stop: 停止定时器,当前Activity:" + AppManager.getInstance().getLastActivity() + "|" + hiBean);
|
||||
isStopShow = true;
|
||||
@@ -196,6 +201,12 @@ public class MessageSayHiNotifyManager {
|
||||
hiBean.setStatus(-2);
|
||||
return;
|
||||
}
|
||||
if (hiBean.getUser().getId() == 0 || hiBean.getUser().getUser() == null) {
|
||||
Log.i(TAG, "showDialog: 数据为空,不展示");
|
||||
isRun = false;
|
||||
hiBean.setStatus(-2);
|
||||
return;
|
||||
}
|
||||
isShowDialog = true;
|
||||
Log.i(TAG, "showDialog: 打开本轮打招呼弹框 " + hiBean);
|
||||
lastActivity = AppManager.getInstance().getLastActivity().getClass().getSimpleName();
|
||||
|
||||
278
common/src/main/java/com/yunbao/common/utils/ZipUtils.java
Normal file
278
common/src/main/java/com/yunbao/common/utils/ZipUtils.java
Normal file
@@ -0,0 +1,278 @@
|
||||
package com.yunbao.common.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* @author: lijuan
|
||||
* @description: 解压ZIP文件
|
||||
* @date: 2017-04-11
|
||||
* @time: 09:22
|
||||
*/
|
||||
public class ZipUtils {
|
||||
public static final String TAG = "ZIP";
|
||||
|
||||
/**
|
||||
* 解压zip到指定的路径
|
||||
*
|
||||
* @param zipFileString ZIP的名称
|
||||
* @param outPathString 要解压缩路径
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void unZipFolder(String zipFileString, String outPathString) throws Exception {
|
||||
ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));
|
||||
ZipEntry zipEntry;
|
||||
String szName = "";
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
szName = zipEntry.getName();
|
||||
if (zipEntry.isDirectory()) {
|
||||
//获取部件的文件夹名
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(outPathString + File.separator + szName);
|
||||
folder.mkdirs();
|
||||
} else {
|
||||
Log.i(TAG, outPathString + File.separator + szName);
|
||||
File file = new File(outPathString + File.separator + szName);
|
||||
if (!file.exists()) {
|
||||
Log.i(TAG, "Create the file:" + outPathString + File.separator + szName);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
// 获取文件的输出流
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
int len;
|
||||
byte[] buffer = new byte[1024];
|
||||
// 读取(字节)字节到缓冲区
|
||||
while ((len = inZip.read(buffer)) != -1) {
|
||||
// 从缓冲区(0)位置写入(字节)字节
|
||||
out.write(buffer, 0, len);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
inZip.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压zip到指定的路径
|
||||
*
|
||||
* @param zipFileString ZIP的名称
|
||||
* @param outPathString 要解压缩路径
|
||||
* @throws Exception
|
||||
*/
|
||||
public static ArrayList<String> unZipFolderWithFileName(String zipFileString, String outPathString) throws Exception {
|
||||
//记录所有文件名
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));
|
||||
ZipEntry zipEntry;
|
||||
String szName = "";
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
szName = zipEntry.getName();
|
||||
if (zipEntry.isDirectory()) {
|
||||
//获取部件的文件夹名
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(outPathString + File.separator + szName);
|
||||
folder.mkdirs();
|
||||
} else {
|
||||
Log.i(TAG, outPathString + File.separator + szName);
|
||||
list.add(szName);
|
||||
File file = new File(outPathString + File.separator + szName);
|
||||
if (!file.exists()) {
|
||||
Log.i(TAG, "Create the file:" + outPathString + File.separator + szName);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
// 获取文件的输出流
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
int len;
|
||||
byte[] buffer = new byte[1024];
|
||||
// 读取(字节)字节到缓冲区
|
||||
while ((len = inZip.read(buffer)) != -1) {
|
||||
// 从缓冲区(0)位置写入(字节)字节
|
||||
out.write(buffer, 0, len);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
inZip.close();
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void unZipFolder(String zipFileString, String outPathString, String szName) throws Exception {
|
||||
ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
//szName = zipEntry.getName();
|
||||
if (zipEntry.isDirectory()) {
|
||||
//获取部件的文件夹名
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(outPathString + File.separator + szName);
|
||||
folder.mkdirs();
|
||||
} else {
|
||||
Log.i(TAG, outPathString + File.separator + szName);
|
||||
File file = new File(outPathString + File.separator + szName);
|
||||
if (!file.exists()) {
|
||||
Log.i(TAG, "Create the file:" + outPathString + File.separator + szName);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
// 获取文件的输出流
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
int len;
|
||||
byte[] buffer = new byte[1024];
|
||||
// 读取(字节)字节到缓冲区
|
||||
while ((len = inZip.read(buffer)) != -1) {
|
||||
// 从缓冲区(0)位置写入(字节)字节
|
||||
out.write(buffer, 0, len);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
inZip.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩文件和文件夹
|
||||
*
|
||||
* @param srcFileString 要压缩的文件或文件夹
|
||||
* @param zipFileString 解压完成的Zip路径
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void zipFolder(List<String> srcFileString, String zipFileString, List<String> filters, Runnable runnable) throws Exception {
|
||||
if (filters == null) {
|
||||
filters = new ArrayList<>();
|
||||
}
|
||||
filters.add(new File(zipFileString).getAbsolutePath());
|
||||
final List<String> tmp = new ArrayList<>(filters);
|
||||
//创建ZIP
|
||||
ZipOutputStream outZip = new ZipOutputStream(new FileOutputStream(zipFileString));
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (String src : srcFileString) {
|
||||
File file = new File(src);
|
||||
//压缩
|
||||
zipFiles(file.getParent() + File.separator, file.getName(), outZip, tmp);
|
||||
}
|
||||
//创建文件
|
||||
//完成和关闭
|
||||
outZip.finish();
|
||||
outZip.close();
|
||||
runnable.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩文件
|
||||
*
|
||||
* @param folderString
|
||||
* @param fileString
|
||||
* @param zipOutputSteam
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void zipFiles(String folderString, String fileString, ZipOutputStream zipOutputSteam, List<String> filters) throws Exception {
|
||||
if (zipOutputSteam == null)
|
||||
return;
|
||||
for (String filter : filters) {
|
||||
if (fileString.startsWith(filter)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.out.println("压缩文件:" + folderString + "|" + fileString);
|
||||
File file = new File(folderString + fileString);
|
||||
if (file.isFile()) {
|
||||
ZipEntry zipEntry = new ZipEntry(fileString);
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
zipOutputSteam.putNextEntry(zipEntry);
|
||||
int len;
|
||||
byte[] buffer = new byte[4096];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
zipOutputSteam.write(buffer, 0, len);
|
||||
}
|
||||
zipOutputSteam.closeEntry();
|
||||
} else {
|
||||
//文件夹
|
||||
String fileList[] = file.list();
|
||||
//没有子文件和压缩
|
||||
if (fileList.length <= 0) {
|
||||
ZipEntry zipEntry = new ZipEntry(fileString + File.separator);
|
||||
zipOutputSteam.putNextEntry(zipEntry);
|
||||
zipOutputSteam.closeEntry();
|
||||
}
|
||||
//子文件和递归
|
||||
for (int i = 0; i < fileList.length; i++) {
|
||||
zipFiles(folderString, fileString + File.separator + fileList[i], zipOutputSteam, filters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回zip的文件输入流
|
||||
*
|
||||
* @param zipFileString zip的名称
|
||||
* @param fileString ZIP的文件名
|
||||
* @return InputStream
|
||||
* @throws Exception
|
||||
*/
|
||||
public static InputStream upZip(String zipFileString, String fileString) throws Exception {
|
||||
ZipFile zipFile = new ZipFile(zipFileString);
|
||||
ZipEntry zipEntry = zipFile.getEntry(fileString);
|
||||
return zipFile.getInputStream(zipEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ZIP中的文件列表(文件和文件夹)
|
||||
*
|
||||
* @param zipFileString ZIP的名称
|
||||
* @param bContainFolder 是否包含文件夹
|
||||
* @param bContainFile 是否包含文件
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static List<File> getFileList(String zipFileString, boolean bContainFolder, boolean bContainFile) throws Exception {
|
||||
List<File> fileList = new ArrayList<File>();
|
||||
ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFileString));
|
||||
ZipEntry zipEntry;
|
||||
String szName = "";
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
szName = zipEntry.getName();
|
||||
if (zipEntry.isDirectory()) {
|
||||
// 获取部件的文件夹名
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(szName);
|
||||
if (bContainFolder) {
|
||||
fileList.add(folder);
|
||||
}
|
||||
} else {
|
||||
File file = new File(szName);
|
||||
if (bContainFile) {
|
||||
fileList.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
inZip.close();
|
||||
return fileList;
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
|
||||
android:background="@color/white"
|
||||
android:paddingTop="24dp"
|
||||
android:background="@color/white">
|
||||
tools:visibility="gone">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user