parent
a465db092a
commit
fda3600046
@ -0,0 +1,187 @@ |
|||||||
|
package xyz.fycz.myreader.ui.activity; |
||||||
|
|
||||||
|
import android.app.Application; |
||||||
|
import android.content.Intent; |
||||||
|
import android.content.pm.PackageInfo; |
||||||
|
import android.content.pm.PackageManager; |
||||||
|
import android.content.res.Configuration; |
||||||
|
import android.content.res.Resources; |
||||||
|
import android.os.Build; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.text.SpannableStringBuilder; |
||||||
|
import android.text.Spanned; |
||||||
|
import android.text.style.ForegroundColorSpan; |
||||||
|
import android.text.style.UnderlineSpan; |
||||||
|
import android.util.DisplayMetrics; |
||||||
|
|
||||||
|
import androidx.appcompat.widget.Toolbar; |
||||||
|
import androidx.core.view.GravityCompat; |
||||||
|
|
||||||
|
import com.gyf.immersionbar.ImmersionBar; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.PrintWriter; |
||||||
|
import java.io.StringWriter; |
||||||
|
import java.text.SimpleDateFormat; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.Locale; |
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
import xyz.fycz.myreader.R; |
||||||
|
import xyz.fycz.myreader.application.App; |
||||||
|
import xyz.fycz.myreader.base.BaseActivity; |
||||||
|
import xyz.fycz.myreader.databinding.ActivityCrashBinding; |
||||||
|
import xyz.fycz.myreader.util.ShareUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/1/22 9:15 |
||||||
|
*/ |
||||||
|
public class CrashActivity extends BaseActivity { |
||||||
|
private ActivityCrashBinding binding; |
||||||
|
|
||||||
|
/** |
||||||
|
* 报错代码行数正则表达式 |
||||||
|
*/ |
||||||
|
private static final Pattern CODE_REGEX = Pattern.compile("\\(\\w+\\.\\w+:\\d+\\)"); |
||||||
|
public static final String INTENT_CRASH_KEY = "crash_exception"; |
||||||
|
public static final String INTENT_LOG_KEY = "log_file_path"; |
||||||
|
private String mStackTrace; |
||||||
|
private String logFilePath; |
||||||
|
|
||||||
|
public static void start(Application application, Throwable throwable, String logFilePath) { |
||||||
|
if (throwable == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
Intent intent = new Intent(application, CrashActivity.class); |
||||||
|
intent.putExtra(INTENT_CRASH_KEY, throwable); |
||||||
|
intent.putExtra(INTENT_LOG_KEY, logFilePath); |
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||||
|
application.startActivity(intent); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void bindView() { |
||||||
|
binding = ActivityCrashBinding.inflate(getLayoutInflater()); |
||||||
|
setContentView(binding.getRoot()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void setUpToolbar(Toolbar toolbar) { |
||||||
|
// 设置状态栏沉浸
|
||||||
|
ImmersionBar.setTitleBar(this, binding.llCrashBar); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean initSwipeBackEnable() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initData(Bundle savedInstanceState) { |
||||||
|
Throwable throwable = (Throwable) getIntent().getSerializableExtra(INTENT_CRASH_KEY); |
||||||
|
logFilePath = getIntent().getStringExtra(INTENT_LOG_KEY); |
||||||
|
if (throwable == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
binding.tvCrashTitle.setText(throwable.getClass().getSimpleName()); |
||||||
|
|
||||||
|
StringWriter stringWriter = new StringWriter(); |
||||||
|
PrintWriter printWriter = new PrintWriter(stringWriter); |
||||||
|
throwable.printStackTrace(printWriter); |
||||||
|
Throwable cause = throwable.getCause(); |
||||||
|
if (cause != null) { |
||||||
|
cause.printStackTrace(printWriter); |
||||||
|
} |
||||||
|
mStackTrace = stringWriter.toString(); |
||||||
|
Matcher matcher = CODE_REGEX.matcher(mStackTrace); |
||||||
|
SpannableStringBuilder spannable = new SpannableStringBuilder(mStackTrace); |
||||||
|
if (spannable.length() > 0) { |
||||||
|
for (int index = 0; matcher.find(); index++) { |
||||||
|
// 不包含左括号(
|
||||||
|
int start = matcher.start() + "(".length(); |
||||||
|
// 不包含右括号 )
|
||||||
|
int end = matcher.end() - ")".length(); |
||||||
|
// 设置前景
|
||||||
|
spannable.setSpan(new ForegroundColorSpan(index < 3 ? 0xFF287BDE : 0xFF999999), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); |
||||||
|
// 设置下划线
|
||||||
|
spannable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); |
||||||
|
} |
||||||
|
binding.tvCrashMessage.setText(spannable); |
||||||
|
} |
||||||
|
|
||||||
|
Resources res = getResources(); |
||||||
|
DisplayMetrics displayMetrics = res.getDisplayMetrics(); |
||||||
|
int screenWidth = displayMetrics.widthPixels; |
||||||
|
int screenHeight = displayMetrics.heightPixels; |
||||||
|
|
||||||
|
String targetResource; |
||||||
|
if (displayMetrics.densityDpi > 480) { |
||||||
|
targetResource = "xxxhdpi"; |
||||||
|
} else if (displayMetrics.densityDpi > 320) { |
||||||
|
targetResource = "xxhdpi"; |
||||||
|
} else if (displayMetrics.densityDpi > 240) { |
||||||
|
targetResource = "xhdpi"; |
||||||
|
} else if (displayMetrics.densityDpi > 160) { |
||||||
|
targetResource = "hdpi"; |
||||||
|
} else if (displayMetrics.densityDpi > 120) { |
||||||
|
targetResource = "mdpi"; |
||||||
|
} else { |
||||||
|
targetResource = "ldpi"; |
||||||
|
} |
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder(); |
||||||
|
builder.append("设备品牌:\t").append(Build.BRAND) |
||||||
|
.append("\n设备型号:\t").append(Build.MODEL) |
||||||
|
.append("\n设备类型:\t").append(isTablet() ? "平板" : "手机"); |
||||||
|
|
||||||
|
builder.append("\n屏幕宽高:\t").append(screenWidth).append(" x ").append(screenHeight) |
||||||
|
.append("\n屏幕密度:\t").append(displayMetrics.densityDpi) |
||||||
|
.append("\n目标资源:\t").append(targetResource); |
||||||
|
|
||||||
|
builder.append("\n安卓版本:\t").append(Build.VERSION.RELEASE) |
||||||
|
.append("\nAPI 版本:\t").append(Build.VERSION.SDK_INT) |
||||||
|
.append("\nCPU 架构:\t").append(Build.SUPPORTED_ABIS[0]); |
||||||
|
|
||||||
|
builder.append("\n应用版本:\t").append(App.getStrVersionName()) |
||||||
|
.append("\n版本代码:\t").append(App.getVersionCode()); |
||||||
|
|
||||||
|
try { |
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm", Locale.getDefault()); |
||||||
|
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS); |
||||||
|
builder.append("\n首次安装:\t").append(dateFormat.format(new Date(packageInfo.firstInstallTime))) |
||||||
|
.append("\n最近安装:\t").append(dateFormat.format(new Date(packageInfo.lastUpdateTime))) |
||||||
|
.append("\n崩溃时间:\t").append(dateFormat.format(new Date())); |
||||||
|
} catch (PackageManager.NameNotFoundException ignored) { |
||||||
|
} |
||||||
|
binding.tvCrashInfo.setText(builder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initClick() { |
||||||
|
binding.ivCrashInfo.setOnClickListener(v -> binding.dlCrashDrawer.openDrawer(GravityCompat.START)); |
||||||
|
binding.ivCrashShare.setOnClickListener(v -> { |
||||||
|
File logFile; |
||||||
|
if (logFilePath != null && (logFile = new File(logFilePath)).exists()) { |
||||||
|
ShareUtils.share(this, logFile, "崩溃日志", "text/plain"); |
||||||
|
} else { |
||||||
|
ShareUtils.share(this, mStackTrace); |
||||||
|
} |
||||||
|
}); |
||||||
|
binding.ivCrashRestart.setOnClickListener(v -> { |
||||||
|
// 重启应用
|
||||||
|
RestartActivity.Companion.restart(this); |
||||||
|
finish(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断当前设备是否是平板 |
||||||
|
*/ |
||||||
|
public boolean isTablet() { |
||||||
|
return (getResources().getConfiguration().screenLayout |
||||||
|
& Configuration.SCREENLAYOUT_SIZE_MASK) |
||||||
|
>= Configuration.SCREENLAYOUT_SIZE_LARGE; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
package xyz.fycz.myreader.ui.activity |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import xyz.fycz.myreader.base.BaseActivity |
||||||
|
import android.content.Intent |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.content.Context |
||||||
|
import xyz.fycz.myreader.util.ToastUtils |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/1/22 8:57 |
||||||
|
*/ |
||||||
|
class RestartActivity : BaseActivity() { |
||||||
|
override fun bindView() {} |
||||||
|
|
||||||
|
companion object { |
||||||
|
fun start(context: Context) { |
||||||
|
val intent = Intent(context, RestartActivity::class.java) |
||||||
|
if (context !is Activity) { |
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
||||||
|
} |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
fun restart(context: Context) { |
||||||
|
val intent = Intent(context, MainActivity::class.java) |
||||||
|
if (context !is Activity) { |
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
||||||
|
} |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
override fun initData(savedInstanceState: Bundle?) { |
||||||
|
restart(this) |
||||||
|
finish() |
||||||
|
ToastUtils.showInfo("正在重启应用") |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:pathData="M512,822c171.21,0 310,-138.79 310,-310s-138.79,-310 -310,-310 -310,138.79 -310,310 138.79,310 310,310zM512,912c-220.91,0 -400,-179.09 -400,-400S291.09,112 512,112s400,179.09 400,400 -179.09,400 -400,400z" |
||||||
|
android:fillColor="#ffffff"/> |
||||||
|
<path |
||||||
|
android:pathData="M468,505c0,-24.85 20.15,-45 45,-45s45,20.15 45,45v150c0,24.85 -20.15,45 -45,45S468,679.85 468,655v-150zM468,373c0,-24.85 20.15,-45 45,-45s45,20.15 45,45v1c0,24.85 -20.15,45 -45,45S468,398.85 468,374v-1z" |
||||||
|
android:fillColor="#ffffff"/> |
||||||
|
</vector> |
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
|
||||||
|
<path |
||||||
|
android:fillColor="#FFFFFF" |
||||||
|
android:pathData="M510.887,350.362 A25.536554,25.536554,0,0,0,536.424,324.825 L536.424,25.5366 |
||||||
|
A25.536554,25.536554,0,0,0,485.351,25.5366 L485.351,324.825 |
||||||
|
A25.536554,25.536554,0,0,0,510.888,350.362 Z" /> |
||||||
|
<path |
||||||
|
android:fillColor="#FFFFFF" |
||||||
|
android:pathData="M782.085,80.4401 A25.536554,25.536554,0,0,0,755.017,123.852 |
||||||
|
A459.65798,459.65798,0,1,1,51.2291,512.263 |
||||||
|
A455.827497,455.827497,0,0,1,266.758,123.852 |
||||||
|
A25.536554,25.536554,0,1,0,239.689,80.4399 |
||||||
|
A510.731089,510.731089,0,1,0,1021.62,512.263 |
||||||
|
A506.389874,506.389874,0,0,0,782.085,80.44 Z" /> |
||||||
|
</vector> |
@ -0,0 +1,121 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:id="@+id/dl_crash_drawer" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="@color/white" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingHorizontal="20dp" |
||||||
|
android:paddingVertical="10dp" |
||||||
|
tools:context=".ui.activity.CrashActivity"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_crash_bar" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_crash_info" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginHorizontal="10dp" |
||||||
|
app:srcCompat="@drawable/ic_info" |
||||||
|
app:tint="@color/textPrimary"/> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/tv_crash_title" |
||||||
|
android:layout_width="0px" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginStart="30dp" |
||||||
|
android:layout_marginEnd="10dp" |
||||||
|
android:layout_weight="1" |
||||||
|
android:gravity="center_horizontal" |
||||||
|
android:lineSpacingExtra="5dp" |
||||||
|
android:text="应用程序发生崩溃" |
||||||
|
android:textSize="@dimen/text_medium_size" |
||||||
|
android:textStyle="bold" |
||||||
|
app:tint="@color/textPrimary"/> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_crash_share" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginHorizontal="10dp" |
||||||
|
app:srcCompat="@drawable/ic_share" |
||||||
|
app:tint="@color/textPrimary"/> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_crash_restart" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginHorizontal="10dp" |
||||||
|
app:srcCompat="@drawable/ic_exit" |
||||||
|
app:tint="@color/textPrimary"/> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_marginHorizontal="10dp" |
||||||
|
android:layout_marginTop="15dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/tv_crash_message" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:lineSpacingExtra="5dp" |
||||||
|
android:textColor="#FF4444" |
||||||
|
android:textSize="16sp" |
||||||
|
tools:text="我是错误信息" /> |
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView |
||||||
|
android:layout_width="240dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_gravity="start" |
||||||
|
android:background="@color/white"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_crash_info" |
||||||
|
android:layout_width="240dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:gravity="center" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center" |
||||||
|
android:layout_marginTop="10dp" |
||||||
|
android:text="详细信息" |
||||||
|
android:textColor="@color/black80" |
||||||
|
android:textSize="16sp" |
||||||
|
android:textStyle="bold" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/tv_crash_info" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginVertical="15dp" |
||||||
|
android:lineSpacingExtra="5dp" |
||||||
|
android:textColor="@color/black60" |
||||||
|
android:textSize="14sp" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView> |
||||||
|
|
||||||
|
</androidx.drawerlayout.widget.DrawerLayout> |
Loading…
Reference in new issue