pakstr 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android-template/app/build.gradle.kts +71 -4
- package/android-template/app/proguard-rules.pro +21 -18
- package/android-template/app/src/debug/AndroidManifest.xml +11 -0
- package/android-template/app/src/main/AndroidManifest.xml +6 -0
- package/android-template/app/src/main/java/com/pakstr/app/ApplicationClass.kt +14 -0
- package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +55 -5
- package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +1 -1
- package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +135 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +78 -5
- package/android-template/app/src/main/java/com/pakstr/app/debug/CrashHandler.kt +32 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigProvider.kt +8 -3
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugLogStorage.kt +43 -11
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugPreferences.kt +85 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportExporter.kt +42 -32
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugRuntimeOverride.kt +30 -4
- package/android-template/app/src/main/java/com/pakstr/app/debug/DebugSession.kt +16 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsActivity.kt +234 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsManager.kt +42 -13
- package/android-template/app/src/main/java/com/pakstr/app/debug/WebViewDebugManager.kt +30 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLog.kt +16 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLogger.kt +154 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +1 -1
- package/android-template/app/src/main/res/layout/activity_developer_tools.xml +308 -0
- package/android-template/app/src/main/res/layout/activity_layout.xml +9 -0
- package/android-template/app/src/main/res/values/dimes.xml +1 -0
- package/android-template/app/src/main/res/values/strings.xml +43 -0
- package/android-template/gradle/libs.versions.toml +1 -0
- package/android-template/gradle.properties +2 -1
- package/package.json +1 -1
|
@@ -11,6 +11,8 @@ object DebugLogStorage {
|
|
|
11
11
|
private const val MAX_FILE_SIZE =
|
|
12
12
|
1024 * 1024 // 1 MB
|
|
13
13
|
|
|
14
|
+
private const val MAX_LINES = 5000
|
|
15
|
+
|
|
14
16
|
fun append(
|
|
15
17
|
context: Context,
|
|
16
18
|
entry: String
|
|
@@ -26,9 +28,13 @@ object DebugLogStorage {
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
file.appendText(
|
|
31
|
+
|
|
29
32
|
entry + "\n"
|
|
33
|
+
|
|
30
34
|
)
|
|
31
35
|
|
|
36
|
+
trimFile(file)
|
|
37
|
+
|
|
32
38
|
} catch (_: Exception) {
|
|
33
39
|
|
|
34
40
|
// Logging must never crash the app
|
|
@@ -38,27 +44,21 @@ object DebugLogStorage {
|
|
|
38
44
|
|
|
39
45
|
fun read(
|
|
40
46
|
context: Context
|
|
41
|
-
): String {
|
|
47
|
+
): List<String> {
|
|
42
48
|
|
|
43
49
|
return try {
|
|
44
50
|
|
|
45
|
-
val file =
|
|
46
|
-
getFile(context)
|
|
47
|
-
|
|
51
|
+
val file = getFile(context)
|
|
48
52
|
|
|
49
53
|
if (file.exists()) {
|
|
50
|
-
|
|
51
|
-
file.readText()
|
|
52
|
-
|
|
54
|
+
file.readLines()
|
|
53
55
|
} else {
|
|
54
|
-
|
|
55
|
-
""
|
|
56
|
-
|
|
56
|
+
emptyList()
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
} catch (_: Exception) {
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
emptyList()
|
|
62
62
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -104,4 +104,36 @@ object DebugLogStorage {
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
private fun trimFile(
|
|
109
|
+
|
|
110
|
+
file: File
|
|
111
|
+
|
|
112
|
+
) {
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
|
|
116
|
+
val lines =
|
|
117
|
+
|
|
118
|
+
file.readLines()
|
|
119
|
+
|
|
120
|
+
if (lines.size > MAX_LINES) {
|
|
121
|
+
|
|
122
|
+
file.writeText(
|
|
123
|
+
|
|
124
|
+
lines
|
|
125
|
+
|
|
126
|
+
.takeLast(MAX_LINES)
|
|
127
|
+
|
|
128
|
+
.joinToString("\n") + "\n"
|
|
129
|
+
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
} catch (_: Exception) {
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
|
107
139
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
|
|
5
|
+
object DebugPreferences {
|
|
6
|
+
|
|
7
|
+
private const val PREFS_NAME = "pakstr_debug"
|
|
8
|
+
|
|
9
|
+
private const val KEY_ENABLED = "enabled"
|
|
10
|
+
private const val KEY_NETWORK = "networkLogs"
|
|
11
|
+
private const val KEY_WEBVIEW = "webViewLogs"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
private fun prefs(context: Context) =
|
|
15
|
+
context.getSharedPreferences(
|
|
16
|
+
PREFS_NAME,
|
|
17
|
+
Context.MODE_PRIVATE
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
fun save(
|
|
22
|
+
context: Context,
|
|
23
|
+
config: DebugConfig
|
|
24
|
+
) {
|
|
25
|
+
|
|
26
|
+
prefs(context)
|
|
27
|
+
.edit()
|
|
28
|
+
.putBoolean(
|
|
29
|
+
KEY_ENABLED,
|
|
30
|
+
config.enabled
|
|
31
|
+
)
|
|
32
|
+
.putBoolean(
|
|
33
|
+
KEY_NETWORK,
|
|
34
|
+
config.networkLogs
|
|
35
|
+
)
|
|
36
|
+
.putBoolean(
|
|
37
|
+
KEY_WEBVIEW,
|
|
38
|
+
config.webViewLogs
|
|
39
|
+
)
|
|
40
|
+
.apply()
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
fun load(
|
|
46
|
+
context: Context
|
|
47
|
+
): DebugConfig {
|
|
48
|
+
|
|
49
|
+
val prefs = prefs(context)
|
|
50
|
+
|
|
51
|
+
return DebugConfig(
|
|
52
|
+
|
|
53
|
+
enabled =
|
|
54
|
+
prefs.getBoolean(
|
|
55
|
+
KEY_ENABLED,
|
|
56
|
+
false
|
|
57
|
+
),
|
|
58
|
+
|
|
59
|
+
networkLogs =
|
|
60
|
+
prefs.getBoolean(
|
|
61
|
+
KEY_NETWORK,
|
|
62
|
+
false
|
|
63
|
+
),
|
|
64
|
+
|
|
65
|
+
webViewLogs =
|
|
66
|
+
prefs.getBoolean(
|
|
67
|
+
KEY_WEBVIEW,
|
|
68
|
+
false
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
fun clear(
|
|
76
|
+
context: Context
|
|
77
|
+
) {
|
|
78
|
+
|
|
79
|
+
prefs(context)
|
|
80
|
+
.edit()
|
|
81
|
+
.clear()
|
|
82
|
+
.apply()
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -38,7 +38,7 @@ object DebugReportExporter {
|
|
|
38
38
|
val file =
|
|
39
39
|
File(
|
|
40
40
|
context.cacheDir,
|
|
41
|
-
"pakstr-debug-report.txt"
|
|
41
|
+
"pakstr-debug-report-${DebugSession.sessionId}.txt"
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
|
|
@@ -57,19 +57,8 @@ object DebugReportExporter {
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
val rawLogs =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
DebugLogStorage.read(context)
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
|
|
66
|
-
DebugLogStorage.read(context)
|
|
67
|
-
.lines()
|
|
68
|
-
.filter {
|
|
69
|
-
it.contains("[ERROR]")
|
|
70
|
-
}
|
|
71
|
-
.joinToString("\n")
|
|
72
|
-
}
|
|
60
|
+
DebugLogStorage.read(context)
|
|
61
|
+
.joinToString("\n")
|
|
73
62
|
|
|
74
63
|
|
|
75
64
|
val logs =
|
|
@@ -77,32 +66,53 @@ object DebugReportExporter {
|
|
|
77
66
|
|
|
78
67
|
|
|
79
68
|
return """
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
Pakstr Debug Report
|
|
70
|
+
===================
|
|
71
|
+
|
|
72
|
+
Session:
|
|
73
|
+
-------------------
|
|
74
|
+
ID:
|
|
75
|
+
${DebugSession.sessionId}
|
|
76
|
+
|
|
77
|
+
Started:
|
|
78
|
+
${java.util.Date(DebugSession.startedAt)}
|
|
79
|
+
|
|
80
|
+
Uptime:
|
|
81
|
+
${DebugSession.uptime()} ms
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Application:
|
|
85
|
+
-------------------
|
|
86
|
+
${BuildConfig.APPLICATION_ID}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
Version:
|
|
90
|
+
${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
Device:
|
|
94
|
+
${Build.MANUFACTURER} ${Build.MODEL}
|
|
95
|
+
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
Android:
|
|
98
|
+
${Build.VERSION.RELEASE}
|
|
85
99
|
|
|
86
|
-
Version:
|
|
87
|
-
${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})
|
|
88
100
|
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
Debug:
|
|
102
|
+
$debugEnabled
|
|
91
103
|
|
|
92
|
-
Android:
|
|
93
|
-
${Build.VERSION.RELEASE}
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
API Enabled:
|
|
106
|
+
${RuntimeConfig.apiEnabled(context)}
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
WebView Debug:
|
|
109
|
+
${BuildConfig.DEBUG || RuntimeConfig.debugEnabled(context)}
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
111
|
+
Logs:
|
|
112
|
+
-------------------
|
|
113
|
+
$logs
|
|
104
114
|
|
|
105
|
-
|
|
115
|
+
""".trimIndent()
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
|
|
@@ -1,29 +1,55 @@
|
|
|
1
1
|
package com.pakstr.app.debug
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
4
|
+
|
|
5
|
+
|
|
3
6
|
object DebugRuntimeOverride {
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
|
|
9
|
+
private var overrideConfig:
|
|
10
|
+
DebugConfig? = null
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
fun set(
|
|
14
|
+
context: Context,
|
|
9
15
|
config: DebugConfig
|
|
10
16
|
) {
|
|
11
17
|
|
|
12
18
|
overrideConfig = config
|
|
13
19
|
|
|
20
|
+
DebugPreferences.save(
|
|
21
|
+
context,
|
|
22
|
+
config
|
|
23
|
+
)
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
|
|
17
|
-
fun clear(
|
|
27
|
+
fun clear(
|
|
28
|
+
context: Context
|
|
29
|
+
) {
|
|
18
30
|
|
|
19
31
|
overrideConfig = null
|
|
20
32
|
|
|
33
|
+
DebugPreferences.clear(
|
|
34
|
+
context
|
|
35
|
+
)
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
|
|
24
|
-
fun get(
|
|
39
|
+
fun get(
|
|
40
|
+
context: Context
|
|
41
|
+
): DebugConfig? {
|
|
25
42
|
|
|
26
|
-
|
|
43
|
+
if (overrideConfig == null) {
|
|
44
|
+
|
|
45
|
+
val saved =
|
|
46
|
+
DebugPreferences.load(context)
|
|
27
47
|
|
|
48
|
+
if (saved.enabled) {
|
|
49
|
+
overrideConfig = saved
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return overrideConfig
|
|
28
54
|
}
|
|
29
55
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import java.util.UUID
|
|
4
|
+
|
|
5
|
+
object DebugSession {
|
|
6
|
+
|
|
7
|
+
val sessionId: String =
|
|
8
|
+
UUID.randomUUID().toString()
|
|
9
|
+
|
|
10
|
+
val startedAt: Long =
|
|
11
|
+
System.currentTimeMillis()
|
|
12
|
+
|
|
13
|
+
fun uptime(): Long {
|
|
14
|
+
return System.currentTimeMillis() - startedAt
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.ActivityNotFoundException
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.graphics.Typeface
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.os.Bundle
|
|
9
|
+
import android.os.Handler
|
|
10
|
+
import android.os.Looper
|
|
11
|
+
import android.text.format.DateUtils
|
|
12
|
+
import android.view.ViewGroup
|
|
13
|
+
import android.widget.ScrollView
|
|
14
|
+
import android.widget.TextView
|
|
15
|
+
import android.widget.Toast
|
|
16
|
+
import androidx.activity.enableEdgeToEdge
|
|
17
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
18
|
+
import com.google.android.material.appbar.MaterialToolbar
|
|
19
|
+
import com.google.android.material.button.MaterialButton
|
|
20
|
+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
21
|
+
import com.google.android.material.switchmaterial.SwitchMaterial
|
|
22
|
+
import com.pakstr.app.BuildConfig
|
|
23
|
+
import com.pakstr.app.R
|
|
24
|
+
import com.pakstr.app.RuntimeConfig
|
|
25
|
+
|
|
26
|
+
class DeveloperToolsActivity : AppCompatActivity() {
|
|
27
|
+
|
|
28
|
+
private val uptimeHandler = Handler(Looper.getMainLooper())
|
|
29
|
+
|
|
30
|
+
private lateinit var uptimeValue: TextView
|
|
31
|
+
private lateinit var debugModeSwitch: SwitchMaterial
|
|
32
|
+
private lateinit var apiSwitch: SwitchMaterial
|
|
33
|
+
private lateinit var debugWebViewStatus: TextView
|
|
34
|
+
private lateinit var webViewStatus: TextView
|
|
35
|
+
|
|
36
|
+
private val uptimeUpdater = object : Runnable {
|
|
37
|
+
override fun run() {
|
|
38
|
+
uptimeValue.text = DateUtils.formatElapsedTime(DebugSession.uptime() / 1000)
|
|
39
|
+
uptimeHandler.postDelayed(this, UPTIME_REFRESH_INTERVAL_MS)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
44
|
+
enableEdgeToEdge()
|
|
45
|
+
super.onCreate(savedInstanceState)
|
|
46
|
+
setContentView(R.layout.activity_developer_tools)
|
|
47
|
+
|
|
48
|
+
setupToolbar()
|
|
49
|
+
bindViews()
|
|
50
|
+
populateRuntimeDetails()
|
|
51
|
+
setupDebugControls()
|
|
52
|
+
setupLogActions()
|
|
53
|
+
setupCrashTesting()
|
|
54
|
+
setupWebViewActions()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override fun onStart() {
|
|
58
|
+
super.onStart()
|
|
59
|
+
refreshStatuses()
|
|
60
|
+
uptimeHandler.post(uptimeUpdater)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun onStop() {
|
|
64
|
+
uptimeHandler.removeCallbacks(uptimeUpdater)
|
|
65
|
+
super.onStop()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private fun setupToolbar() {
|
|
69
|
+
findViewById<MaterialToolbar>(R.id.developerToolsToolbar).setNavigationOnClickListener {
|
|
70
|
+
finish()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private fun bindViews() {
|
|
75
|
+
uptimeValue = findViewById(R.id.runtimeUptimeValue)
|
|
76
|
+
debugModeSwitch = findViewById(R.id.debugModeSwitch)
|
|
77
|
+
apiSwitch = findViewById(R.id.apiEnabledSwitch)
|
|
78
|
+
debugWebViewStatus = findViewById(R.id.debugWebViewStatus)
|
|
79
|
+
webViewStatus = findViewById(R.id.webViewStatus)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private fun populateRuntimeDetails() {
|
|
83
|
+
findViewById<TextView>(R.id.runtimeSessionIdValue).text = DebugSession.sessionId
|
|
84
|
+
findViewById<TextView>(R.id.runtimeAppVersionValue).text = getString(
|
|
85
|
+
R.string.developer_tools_version_value,
|
|
86
|
+
BuildConfig.VERSION_NAME,
|
|
87
|
+
BuildConfig.VERSION_CODE
|
|
88
|
+
)
|
|
89
|
+
findViewById<TextView>(R.id.runtimeAndroidVersionValue).text = Build.VERSION.RELEASE
|
|
90
|
+
findViewById<TextView>(R.id.runtimeDeviceModelValue).text = getString(
|
|
91
|
+
R.string.developer_tools_device_value,
|
|
92
|
+
Build.MANUFACTURER,
|
|
93
|
+
Build.MODEL
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun setupDebugControls() {
|
|
98
|
+
apiSwitch.isChecked = RuntimeConfig.apiEnabled(this)
|
|
99
|
+
|
|
100
|
+
debugModeSwitch.setOnCheckedChangeListener { _, isChecked ->
|
|
101
|
+
if (isChecked) {
|
|
102
|
+
DeveloperToolsManager.enableDebug(this)
|
|
103
|
+
} else {
|
|
104
|
+
DeveloperToolsManager.disableDebug(this)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
WebViewDebugManager.enable(this)
|
|
108
|
+
refreshStatuses()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private fun refreshStatuses() {
|
|
113
|
+
debugModeSwitch.isChecked = DeveloperToolsManager.isEnabled(this)
|
|
114
|
+
apiSwitch.isChecked = RuntimeConfig.apiEnabled(this)
|
|
115
|
+
|
|
116
|
+
val status = if (isWebViewDebugEnabled()) {
|
|
117
|
+
R.string.developer_tools_enabled
|
|
118
|
+
} else {
|
|
119
|
+
R.string.developer_tools_disabled
|
|
120
|
+
}
|
|
121
|
+
debugWebViewStatus.setText(status)
|
|
122
|
+
webViewStatus.setText(status)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private fun isWebViewDebugEnabled(): Boolean {
|
|
126
|
+
return BuildConfig.DEBUG || RuntimeConfig.debugEnabled(this)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private fun setupLogActions() {
|
|
130
|
+
findViewById<MaterialButton>(R.id.viewLogsButton).setOnClickListener {
|
|
131
|
+
showLogs()
|
|
132
|
+
}
|
|
133
|
+
findViewById<MaterialButton>(R.id.clearLogsButton).setOnClickListener {
|
|
134
|
+
confirmClearLogs()
|
|
135
|
+
}
|
|
136
|
+
findViewById<MaterialButton>(R.id.exportDebugReportButton).setOnClickListener {
|
|
137
|
+
exportDebugReport()
|
|
138
|
+
}
|
|
139
|
+
findViewById<MaterialButton>(R.id.shareReportButton).setOnClickListener {
|
|
140
|
+
DebugReportShare.share(this)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private fun showLogs() {
|
|
145
|
+
val logs = DebugLogStorage.read(this)
|
|
146
|
+
val content = if (logs.isEmpty()) {
|
|
147
|
+
getString(R.string.developer_tools_no_logs)
|
|
148
|
+
} else {
|
|
149
|
+
logs.joinToString("\n")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
val textView = TextView(this).apply {
|
|
153
|
+
text = content
|
|
154
|
+
typeface = Typeface.MONOSPACE
|
|
155
|
+
setTextIsSelectable(true)
|
|
156
|
+
val padding = resources.getDimensionPixelSize(
|
|
157
|
+
R.dimen.developer_tools_dialog_padding
|
|
158
|
+
)
|
|
159
|
+
setPadding(padding, padding, padding, padding)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
val scrollView = ScrollView(this).apply {
|
|
163
|
+
addView(textView)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
MaterialAlertDialogBuilder(this)
|
|
167
|
+
.setTitle(R.string.developer_tools_view_logs)
|
|
168
|
+
.setView(scrollView)
|
|
169
|
+
.setPositiveButton(android.R.string.ok, null)
|
|
170
|
+
.show()
|
|
171
|
+
.window
|
|
172
|
+
?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private fun confirmClearLogs() {
|
|
176
|
+
MaterialAlertDialogBuilder(this)
|
|
177
|
+
.setTitle(R.string.developer_tools_clear_logs)
|
|
178
|
+
.setMessage(R.string.developer_tools_clear_logs_confirmation)
|
|
179
|
+
.setNegativeButton(android.R.string.cancel, null)
|
|
180
|
+
.setPositiveButton(R.string.developer_tools_clear) { _, _ ->
|
|
181
|
+
AppDebugLogger.clear(this)
|
|
182
|
+
showMessage(R.string.developer_tools_logs_cleared)
|
|
183
|
+
}
|
|
184
|
+
.show()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private fun exportDebugReport() {
|
|
188
|
+
runCatching {
|
|
189
|
+
DebugReportExporter.export(this)
|
|
190
|
+
}.onSuccess { report ->
|
|
191
|
+
Toast.makeText(
|
|
192
|
+
this,
|
|
193
|
+
getString(R.string.developer_tools_report_exported, report.absolutePath),
|
|
194
|
+
Toast.LENGTH_LONG
|
|
195
|
+
).show()
|
|
196
|
+
}.onFailure {
|
|
197
|
+
showMessage(R.string.developer_tools_report_export_failed)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private fun setupCrashTesting() {
|
|
202
|
+
findViewById<MaterialButton>(R.id.throwTestExceptionButton).setOnClickListener {
|
|
203
|
+
MaterialAlertDialogBuilder(this)
|
|
204
|
+
.setTitle(R.string.developer_tools_crash_confirmation_title)
|
|
205
|
+
.setMessage(R.string.developer_tools_crash_confirmation_message)
|
|
206
|
+
.setNegativeButton(android.R.string.cancel, null)
|
|
207
|
+
.setPositiveButton(R.string.developer_tools_crash) { _, _ ->
|
|
208
|
+
throw RuntimeException(TEST_EXCEPTION_MESSAGE)
|
|
209
|
+
}
|
|
210
|
+
.show()
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private fun setupWebViewActions() {
|
|
215
|
+
findViewById<MaterialButton>(R.id.openChromeInspectDocsButton).setOnClickListener {
|
|
216
|
+
try {
|
|
217
|
+
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(CHROME_INSPECT_DOCS_URL)))
|
|
218
|
+
} catch (_: ActivityNotFoundException) {
|
|
219
|
+
showMessage(R.string.developer_tools_browser_unavailable)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private fun showMessage(message: Int) {
|
|
225
|
+
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private companion object {
|
|
229
|
+
const val UPTIME_REFRESH_INTERVAL_MS = 1000L
|
|
230
|
+
const val TEST_EXCEPTION_MESSAGE = "Developer Tools test exception"
|
|
231
|
+
const val CHROME_INSPECT_DOCS_URL =
|
|
232
|
+
"https://developer.chrome.com/docs/devtools/remote-debugging/webviews/"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -1,34 +1,63 @@
|
|
|
1
1
|
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
|
|
5
|
+
|
|
2
6
|
object DeveloperToolsManager {
|
|
3
7
|
|
|
4
|
-
fun enableDebug() {
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
fun enableDebug(
|
|
10
|
+
context: Context
|
|
11
|
+
) {
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
val config = DebugConfig(
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
enabled = true,
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
networkLogs = true,
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
webViewLogs = true
|
|
20
|
+
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
DebugRuntimeOverride.set(context,
|
|
26
|
+
config
|
|
27
|
+
)
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
DebugPreferences.save(
|
|
30
|
+
context,
|
|
31
|
+
config
|
|
17
32
|
)
|
|
18
33
|
|
|
19
34
|
}
|
|
20
35
|
|
|
21
|
-
fun disableDebug() {
|
|
22
36
|
|
|
23
|
-
|
|
37
|
+
fun disableDebug(
|
|
38
|
+
context: Context
|
|
39
|
+
) {
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
DebugRuntimeOverride.clear(context)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
DebugPreferences.clear(
|
|
46
|
+
context
|
|
47
|
+
)
|
|
24
48
|
|
|
25
49
|
}
|
|
26
50
|
|
|
27
|
-
fun isEnabled(): Boolean {
|
|
28
51
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
fun isEnabled(
|
|
53
|
+
context: Context
|
|
54
|
+
): Boolean {
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
return DebugPreferences
|
|
58
|
+
.load(context)
|
|
59
|
+
.enabled
|
|
32
60
|
|
|
33
61
|
}
|
|
62
|
+
|
|
34
63
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.R.attr.enabled
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.webkit.WebView
|
|
6
|
+
import com.pakstr.app.BuildConfig
|
|
7
|
+
import com.pakstr.app.RuntimeConfig
|
|
8
|
+
|
|
9
|
+
object WebViewDebugManager {
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
fun enable(
|
|
13
|
+
context: Context
|
|
14
|
+
) {
|
|
15
|
+
|
|
16
|
+
WebView.setWebContentsDebuggingEnabled(
|
|
17
|
+
BuildConfig.DEBUG ||
|
|
18
|
+
RuntimeConfig.debugEnabled(context)
|
|
19
|
+
)
|
|
20
|
+
AppDebugLogger.log(
|
|
21
|
+
|
|
22
|
+
context,
|
|
23
|
+
|
|
24
|
+
"WEBVIEW",
|
|
25
|
+
|
|
26
|
+
"WebView debugging enabled: $enabled"
|
|
27
|
+
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
}
|