mirror of
https://github.com/tateisu/SubwayTooter
synced 2025-01-30 18:44:52 +01:00
「アプリ設定/開発者オプション/Exit Reasons」を追加。
This commit is contained in:
parent
02504fdda1
commit
1bd00a6abf
@ -263,6 +263,11 @@
|
||||
android:name=".ActMediaViewer"
|
||||
android:theme="@style/AppTheme.Dark.NoActionBar" />
|
||||
|
||||
<activity
|
||||
android:name=".ActExitReasons"
|
||||
android:label="@string/exit_reasons"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="100.0" />
|
||||
|
156
app/src/main/java/jp/juggler/subwaytooter/ActExitReasons.kt
Normal file
156
app/src/main/java/jp/juggler/subwaytooter/ActExitReasons.kt
Normal file
@ -0,0 +1,156 @@
|
||||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.ApplicationExitInfo
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ListView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.decodeUTF8
|
||||
import jp.juggler.util.withCaption
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
class ActExitReasons : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
val log = LogCategory("ActExitReasons")
|
||||
|
||||
fun reasonString(v : Int) = when(v) {
|
||||
ApplicationExitInfo.REASON_ANR ->
|
||||
"REASON_ANR Application process was killed due to being unresponsive (ANR)."
|
||||
|
||||
ApplicationExitInfo.REASON_CRASH ->
|
||||
"REASON_CRASH Application process died because of an unhandled exception in Java code."
|
||||
|
||||
ApplicationExitInfo.REASON_CRASH_NATIVE ->
|
||||
"REASON_CRASH_NATIVE Application process died because of a native code crash."
|
||||
|
||||
ApplicationExitInfo.REASON_DEPENDENCY_DIED ->
|
||||
"REASON_DEPENDENCY_DIED Application process was killed because its dependency was going away, for example, a stable content provider connection's client will be killed if the provider is killed."
|
||||
|
||||
ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE ->
|
||||
"REASON_EXCESSIVE_RESOURCE_USAGE Application process was killed by the system due to excessive resource usage."
|
||||
|
||||
ApplicationExitInfo.REASON_EXIT_SELF ->
|
||||
"REASON_EXIT_SELF Application process exit normally by itself, for example, via java.lang.System#exit; getStatus will specify the exit code."
|
||||
|
||||
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE ->
|
||||
"REASON_INITIALIZATION_FAILURE Application process was killed because of initialization failure, for example, it took too long to attach to the system during the start, or there was an error during initialization."
|
||||
|
||||
ApplicationExitInfo.REASON_LOW_MEMORY ->
|
||||
"REASON_LOW_MEMORY Application process was killed by the system low memory killer, meaning the system was under memory pressure at the time of kill."
|
||||
|
||||
ApplicationExitInfo.REASON_OTHER ->
|
||||
"REASON_OTHER Application process was killed by the system for various other reasons which are not by problems in apps and not actionable by apps, for example, the system just finished updates; getDescription will specify the cause given by the system."
|
||||
|
||||
ApplicationExitInfo.REASON_PERMISSION_CHANGE ->
|
||||
"REASON_PERMISSION_CHANGE Application process was killed due to a runtime permission change."
|
||||
|
||||
ApplicationExitInfo.REASON_SIGNALED ->
|
||||
"REASON_SIGNALED Application process died due to the result of an OS signal; for example, android.system.OsConstants#SIGKILL; getStatus will specify the signal number."
|
||||
|
||||
ApplicationExitInfo.REASON_UNKNOWN ->
|
||||
"REASON_UNKNOWN Application process died due to unknown reason."
|
||||
|
||||
ApplicationExitInfo.REASON_USER_REQUESTED ->
|
||||
"REASON_USER_REQUESTED Application process was killed because of the user request, for example, user clicked the \"Force stop\" button of the application in the Settings, or removed the application away from Recents."
|
||||
|
||||
ApplicationExitInfo.REASON_USER_STOPPED ->
|
||||
"REASON_USER_STOPPED Application process was killed, because the user it is running as on devices with mutlple users, was stopped."
|
||||
|
||||
else -> "?($v)"
|
||||
}
|
||||
|
||||
fun readStream(inStream : InputStream?) =
|
||||
if(inStream == null)
|
||||
"(null)"
|
||||
else try {
|
||||
val bao = ByteArrayOutputStream()
|
||||
IOUtils.copy(inStream, bao)
|
||||
bao.toByteArray().decodeUTF8()
|
||||
} catch(ex : Throwable) {
|
||||
ex.withCaption("readStream failed.")
|
||||
} finally {
|
||||
inStream.close()
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var listView : ListView
|
||||
private lateinit var adapter : MyAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState : Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
App1.setActivityTheme(this)
|
||||
setContentView(R.layout.act_exit_reasons)
|
||||
App1.initEdgeToEdge(this)
|
||||
|
||||
val am = getSystemService(ActivityManager::class.java)
|
||||
if(am == null) {
|
||||
log.e("can't find ActivityManager")
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
this.listView = findViewById(R.id.listView)
|
||||
this.adapter = MyAdapter()
|
||||
adapter.list = am.getHistoricalProcessExitReasons(null, 0, 200)
|
||||
.filterNotNull()
|
||||
.toList()
|
||||
|
||||
listView.adapter = adapter
|
||||
|
||||
}
|
||||
|
||||
class MyViewHolder(val viewRoot : View) {
|
||||
|
||||
private val textView : TextView = viewRoot.findViewById(R.id.textView)
|
||||
|
||||
fun bind(context : Context, info : ApplicationExitInfo) {
|
||||
|
||||
textView.text = """
|
||||
timestamp=${TootStatus.formatTime(context, info.timestamp, bAllowRelative = false)}
|
||||
importance=${info.importance}
|
||||
pss=${info.pss}
|
||||
rss=${info.rss}
|
||||
reason=${reasonString(info.reason)}
|
||||
status=${info.status}
|
||||
description=${info.description}
|
||||
trace=${readStream(info.traceInputStream)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
fun genView(parent : ViewGroup?) : View =
|
||||
layoutInflater.inflate(R.layout.lv_exit_reason, parent, false)
|
||||
.also { it.tag = MyViewHolder(it) }
|
||||
|
||||
inner class MyAdapter : BaseAdapter() {
|
||||
|
||||
var list : List<ApplicationExitInfo> = emptyList()
|
||||
|
||||
override fun getCount() : Int = list.size
|
||||
override fun getItem(position : Int) : Any? = list[position]
|
||||
override fun getItemId(position : Int) : Long = 0
|
||||
override fun getView(
|
||||
position : Int,
|
||||
convertView : View?,
|
||||
parent : ViewGroup?
|
||||
) : View =
|
||||
(convertView ?: genView(parent)).also { view ->
|
||||
(view.tag as? MyViewHolder)?.bind(this@ActExitReasons, list[position])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -939,10 +939,20 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
|
||||
}
|
||||
|
||||
section(R.string.developer_options) {
|
||||
sw(Pref.bpCheckBetaVersion, R.string.check_beta_release)
|
||||
|
||||
action(R.string.drawable_list) {
|
||||
action = { startActivity(Intent(this, ActDrawableList::class.java)) }
|
||||
}
|
||||
sw(Pref.bpCheckBetaVersion, R.string.check_beta_release)
|
||||
action(R.string.exit_reasons) {
|
||||
action = {
|
||||
if(Build.VERSION.SDK_INT >= 30 ){
|
||||
startActivity(Intent(this, ActExitReasons::class.java))
|
||||
}else{
|
||||
showToast(false, "this feature requires Android 11")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
10
app/src/main/res/layout/act_exit_reasons.xml
Normal file
10
app/src/main/res/layout/act_exit_reasons.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:id="@+id/listView"
|
||||
/>
|
||||
|
11
app/src/main/res/layout/lv_exit_reason.xml
Normal file
11
app/src/main/res/layout/lv_exit_reason.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/textView"/>
|
||||
|
||||
</LinearLayout>
|
@ -1044,4 +1044,5 @@
|
||||
<string name="release_note_with_assets">Release note (Please find the APK file in assets section.)</string>
|
||||
<string name="release_note">Release note</string>
|
||||
<string name="check_beta_release">Check beta release</string>
|
||||
<string name="exit_reasons" translatable="false">Exit reasons</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user