pakstr 0.5.0 → 0.7.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/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/MainActivity.kt +103 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsAccessManager.kt +14 -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/SupportUnlock.kt +44 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/SupportUnlockGestureLayout.kt +87 -0
- 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 +11 -2
- package/android-template/app/src/main/res/values/dimes.xml +1 -0
- package/android-template/app/src/main/res/values/strings.xml +44 -0
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
<application>
|
|
4
|
+
<activity-alias
|
|
5
|
+
android:name=".debug.DeveloperToolsDebugLauncher"
|
|
6
|
+
android:enabled="true"
|
|
7
|
+
android:exported="true"
|
|
8
|
+
android:label="@string/developer_tools_title"
|
|
9
|
+
android:targetActivity=".debug.DeveloperToolsActivity" />
|
|
10
|
+
</application>
|
|
11
|
+
</manifest>
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
android:supportsRtl="true"
|
|
29
29
|
android:usesCleartextTraffic="true">
|
|
30
30
|
|
|
31
|
+
<activity
|
|
32
|
+
android:name=".debug.DeveloperToolsActivity"
|
|
33
|
+
android:exported="false"
|
|
34
|
+
android:label="@string/developer_tools_title"
|
|
35
|
+
android:theme="@style/Theme.NostrAppShell" />
|
|
36
|
+
|
|
31
37
|
<activity
|
|
32
38
|
android:name=".MainActivity"
|
|
33
39
|
android:exported="true"
|
|
@@ -3,11 +3,14 @@ package com.pakstr.app
|
|
|
3
3
|
import android.Manifest
|
|
4
4
|
import android.content.Intent
|
|
5
5
|
import android.os.Bundle
|
|
6
|
+
import android.os.Handler
|
|
7
|
+
import android.os.Looper
|
|
6
8
|
|
|
7
9
|
import android.view.View
|
|
8
10
|
import android.webkit.PermissionRequest
|
|
9
11
|
import android.webkit.WebView
|
|
10
12
|
import android.widget.FrameLayout
|
|
13
|
+
import android.widget.Toast
|
|
11
14
|
import androidx.activity.OnBackPressedCallback
|
|
12
15
|
import androidx.activity.enableEdgeToEdge
|
|
13
16
|
import androidx.activity.result.ActivityResultLauncher
|
|
@@ -17,11 +20,16 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
|
17
20
|
import androidx.core.view.ViewCompat
|
|
18
21
|
import androidx.core.view.WindowInsetsCompat
|
|
19
22
|
import androidx.core.view.updatePadding
|
|
23
|
+
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
20
24
|
import com.pakstr.app.debug.AppDebugLogger
|
|
21
25
|
import com.pakstr.app.debug.CrashHandler
|
|
22
26
|
|
|
23
27
|
import com.pakstr.app.debug.DebugReportShare
|
|
28
|
+
import com.pakstr.app.debug.DeveloperToolsAccessManager
|
|
29
|
+
import com.pakstr.app.debug.DeveloperToolsActivity
|
|
24
30
|
import com.pakstr.app.debug.DeveloperToolsManager
|
|
31
|
+
import com.pakstr.app.debug.SupportUnlock
|
|
32
|
+
import com.pakstr.app.debug.SupportUnlockGestureLayout
|
|
25
33
|
import com.pakstr.app.debug.WebViewDebugManager
|
|
26
34
|
|
|
27
35
|
import com.pakstr.app.permissions.PermissionManager
|
|
@@ -43,6 +51,14 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
43
51
|
private lateinit var amberLauncher:
|
|
44
52
|
ActivityResultLauncher<Intent>
|
|
45
53
|
|
|
54
|
+
private lateinit var fab: FloatingActionButton
|
|
55
|
+
private lateinit var supportUnlockGestureLayout: SupportUnlockGestureLayout
|
|
56
|
+
|
|
57
|
+
private val diagnosticsHandler = Handler(Looper.getMainLooper())
|
|
58
|
+
private val diagnosticsExpiryCheck = Runnable {
|
|
59
|
+
showDebugFab()
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
override fun onCreate(
|
|
47
63
|
|
|
48
64
|
savedInstanceState: Bundle?
|
|
@@ -88,6 +104,8 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
88
104
|
)
|
|
89
105
|
|
|
90
106
|
initViews()
|
|
107
|
+
setupSupportUnlockGesture()
|
|
108
|
+
showDebugFab()
|
|
91
109
|
|
|
92
110
|
amberLauncher =
|
|
93
111
|
|
|
@@ -145,6 +163,62 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
145
163
|
|
|
146
164
|
}
|
|
147
165
|
|
|
166
|
+
private fun showDebugFab() {
|
|
167
|
+
diagnosticsHandler.removeCallbacks(diagnosticsExpiryCheck)
|
|
168
|
+
|
|
169
|
+
if (DeveloperToolsAccessManager.canOpenDeveloperTools(this)) {
|
|
170
|
+
|
|
171
|
+
fab.visibility = View.VISIBLE
|
|
172
|
+
|
|
173
|
+
fab.setOnClickListener {
|
|
174
|
+
if (DeveloperToolsAccessManager.canOpenDeveloperTools(this)) {
|
|
175
|
+
startActivity(
|
|
176
|
+
|
|
177
|
+
Intent(
|
|
178
|
+
|
|
179
|
+
this,
|
|
180
|
+
|
|
181
|
+
DeveloperToolsActivity::class.java
|
|
182
|
+
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
)
|
|
186
|
+
} else {
|
|
187
|
+
showDebugFab()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
val remainingDuration = SupportUnlock.remainingDuration(this)
|
|
192
|
+
if (!BuildConfig.DEBUG &&
|
|
193
|
+
!RuntimeConfig.debugEnabled(this) &&
|
|
194
|
+
remainingDuration > 0L
|
|
195
|
+
) {
|
|
196
|
+
diagnosticsHandler.postDelayed(
|
|
197
|
+
diagnosticsExpiryCheck,
|
|
198
|
+
remainingDuration
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
} else {
|
|
203
|
+
|
|
204
|
+
fab.visibility = View.GONE
|
|
205
|
+
fab.setOnClickListener(null)
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private fun setupSupportUnlockGesture() {
|
|
211
|
+
supportUnlockGestureLayout.onUnlock = {
|
|
212
|
+
SupportUnlock.unlock(this)
|
|
213
|
+
Toast.makeText(
|
|
214
|
+
this,
|
|
215
|
+
R.string.diagnostics_mode_enabled,
|
|
216
|
+
Toast.LENGTH_LONG
|
|
217
|
+
).show()
|
|
218
|
+
showDebugFab()
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
148
222
|
private fun setupBackNavigation() {
|
|
149
223
|
onBackPressedDispatcher.addCallback(
|
|
150
224
|
this,
|
|
@@ -187,6 +261,9 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
187
261
|
container =
|
|
188
262
|
findViewById(R.id.mainContainer)
|
|
189
263
|
|
|
264
|
+
supportUnlockGestureLayout =
|
|
265
|
+
container as SupportUnlockGestureLayout
|
|
266
|
+
|
|
190
267
|
webView =
|
|
191
268
|
findViewById(R.id.webView)
|
|
192
269
|
|
|
@@ -197,6 +274,10 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
197
274
|
permissionManager =
|
|
198
275
|
PermissionManager(this)
|
|
199
276
|
|
|
277
|
+
fab = findViewById(
|
|
278
|
+
|
|
279
|
+
R.id.developerToolsFab)
|
|
280
|
+
|
|
200
281
|
}
|
|
201
282
|
|
|
202
283
|
private fun handleSignerSetup() {
|
|
@@ -206,7 +287,29 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
206
287
|
)
|
|
207
288
|
}
|
|
208
289
|
|
|
290
|
+
override fun onResume() {
|
|
291
|
+
super.onResume()
|
|
292
|
+
|
|
293
|
+
if (::fab.isInitialized) {
|
|
294
|
+
showDebugFab()
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
override fun onStop() {
|
|
299
|
+
if (::supportUnlockGestureLayout.isInitialized) {
|
|
300
|
+
supportUnlockGestureLayout.cancelHold()
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
super.onStop()
|
|
304
|
+
}
|
|
305
|
+
|
|
209
306
|
override fun onDestroy() {
|
|
307
|
+
diagnosticsHandler.removeCallbacks(diagnosticsExpiryCheck)
|
|
308
|
+
|
|
309
|
+
if (::supportUnlockGestureLayout.isInitialized) {
|
|
310
|
+
supportUnlockGestureLayout.cancelHold()
|
|
311
|
+
supportUnlockGestureLayout.onUnlock = null
|
|
312
|
+
}
|
|
210
313
|
|
|
211
314
|
if (::runtime.isInitialized) {
|
|
212
315
|
|
package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsAccessManager.kt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.pakstr.app.BuildConfig
|
|
5
|
+
import com.pakstr.app.RuntimeConfig
|
|
6
|
+
|
|
7
|
+
object DeveloperToolsAccessManager {
|
|
8
|
+
|
|
9
|
+
fun canOpenDeveloperTools(context: Context): Boolean {
|
|
10
|
+
return BuildConfig.DEBUG ||
|
|
11
|
+
RuntimeConfig.debugEnabled(context) ||
|
|
12
|
+
SupportUnlock.isActive(context)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
|
|
5
|
+
object SupportUnlock {
|
|
6
|
+
|
|
7
|
+
const val UNLOCK_DURATION_MS = 60 * 60 * 1000L
|
|
8
|
+
|
|
9
|
+
private const val PREFERENCES_NAME = "pakstr_support_unlock"
|
|
10
|
+
private const val EXPIRES_AT_KEY = "expires_at"
|
|
11
|
+
|
|
12
|
+
fun unlock(context: Context) {
|
|
13
|
+
preferences(context)
|
|
14
|
+
.edit()
|
|
15
|
+
.putLong(EXPIRES_AT_KEY, System.currentTimeMillis() + UNLOCK_DURATION_MS)
|
|
16
|
+
.apply()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fun isActive(context: Context): Boolean {
|
|
20
|
+
val remainingDuration = remainingDuration(context)
|
|
21
|
+
|
|
22
|
+
if (remainingDuration <= 0L) {
|
|
23
|
+
clear(context)
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fun clear(context: Context) {
|
|
31
|
+
preferences(context)
|
|
32
|
+
.edit()
|
|
33
|
+
.remove(EXPIRES_AT_KEY)
|
|
34
|
+
.apply()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fun remainingDuration(context: Context): Long {
|
|
38
|
+
val expiresAt = preferences(context).getLong(EXPIRES_AT_KEY, 0L)
|
|
39
|
+
return (expiresAt - System.currentTimeMillis()).coerceAtLeast(0L)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun preferences(context: Context) =
|
|
43
|
+
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
|
|
44
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
package com.pakstr.app.debug
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import android.util.AttributeSet
|
|
7
|
+
import android.view.MotionEvent
|
|
8
|
+
import android.view.ViewConfiguration
|
|
9
|
+
import android.widget.FrameLayout
|
|
10
|
+
import kotlin.math.abs
|
|
11
|
+
|
|
12
|
+
class SupportUnlockGestureLayout @JvmOverloads constructor(
|
|
13
|
+
context: Context,
|
|
14
|
+
attrs: AttributeSet? = null,
|
|
15
|
+
defStyleAttr: Int = 0
|
|
16
|
+
) : FrameLayout(context, attrs, defStyleAttr) {
|
|
17
|
+
|
|
18
|
+
var onUnlock: (() -> Unit)? = null
|
|
19
|
+
|
|
20
|
+
private val handler = Handler(Looper.getMainLooper())
|
|
21
|
+
private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
|
|
22
|
+
private val cornerSize = CORNER_SIZE_DP * resources.displayMetrics.density
|
|
23
|
+
|
|
24
|
+
private var tracking = false
|
|
25
|
+
private var downX = 0f
|
|
26
|
+
private var downY = 0f
|
|
27
|
+
|
|
28
|
+
private val unlockRunnable = Runnable {
|
|
29
|
+
if (tracking) {
|
|
30
|
+
tracking = false
|
|
31
|
+
onUnlock?.invoke()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
36
|
+
observeTouch(event)
|
|
37
|
+
return super.dispatchTouchEvent(event)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fun cancelHold() {
|
|
41
|
+
tracking = false
|
|
42
|
+
handler.removeCallbacks(unlockRunnable)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun onDetachedFromWindow() {
|
|
46
|
+
cancelHold()
|
|
47
|
+
super.onDetachedFromWindow()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private fun observeTouch(event: MotionEvent) {
|
|
51
|
+
when (event.actionMasked) {
|
|
52
|
+
MotionEvent.ACTION_DOWN -> {
|
|
53
|
+
if (isInTopRightCorner(event.x, event.y)) {
|
|
54
|
+
tracking = true
|
|
55
|
+
downX = event.x
|
|
56
|
+
downY = event.y
|
|
57
|
+
handler.postDelayed(unlockRunnable, HOLD_DURATION_MS)
|
|
58
|
+
} else {
|
|
59
|
+
cancelHold()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
MotionEvent.ACTION_MOVE -> {
|
|
64
|
+
if (tracking && hasMovedBeyondTouchSlop(event.x, event.y)) {
|
|
65
|
+
cancelHold()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
MotionEvent.ACTION_POINTER_DOWN,
|
|
70
|
+
MotionEvent.ACTION_UP,
|
|
71
|
+
MotionEvent.ACTION_CANCEL -> cancelHold()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun isInTopRightCorner(x: Float, y: Float): Boolean {
|
|
76
|
+
return x >= width - cornerSize && y <= paddingTop + cornerSize
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun hasMovedBeyondTouchSlop(x: Float, y: Float): Boolean {
|
|
80
|
+
return abs(x - downX) > touchSlop || abs(y - downY) > touchSlop
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private companion object {
|
|
84
|
+
const val HOLD_DURATION_MS = 10_000L
|
|
85
|
+
const val CORNER_SIZE_DP = 72
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
4
|
+
android:layout_width="match_parent"
|
|
5
|
+
android:layout_height="match_parent"
|
|
6
|
+
android:paddingBottom="56dp"
|
|
7
|
+
android:background="?android:attr/colorBackground"
|
|
8
|
+
android:orientation="vertical">
|
|
9
|
+
|
|
10
|
+
<com.google.android.material.appbar.MaterialToolbar
|
|
11
|
+
android:id="@+id/developerToolsToolbar"
|
|
12
|
+
android:layout_width="match_parent"
|
|
13
|
+
android:layout_height="?attr/actionBarSize"
|
|
14
|
+
android:background="?attr/colorSurface"
|
|
15
|
+
android:elevation="4dp"
|
|
16
|
+
app:navigationIcon="?attr/homeAsUpIndicator"
|
|
17
|
+
app:title="@string/developer_tools_title" />
|
|
18
|
+
|
|
19
|
+
<androidx.core.widget.NestedScrollView
|
|
20
|
+
android:layout_width="match_parent"
|
|
21
|
+
android:layout_height="0dp"
|
|
22
|
+
android:layout_weight="1"
|
|
23
|
+
android:fillViewport="true">
|
|
24
|
+
|
|
25
|
+
<LinearLayout
|
|
26
|
+
android:layout_width="match_parent"
|
|
27
|
+
android:layout_height="wrap_content"
|
|
28
|
+
android:orientation="vertical"
|
|
29
|
+
android:padding="16dp">
|
|
30
|
+
|
|
31
|
+
<com.google.android.material.card.MaterialCardView
|
|
32
|
+
android:layout_width="match_parent"
|
|
33
|
+
android:layout_height="wrap_content"
|
|
34
|
+
android:layout_marginBottom="16dp"
|
|
35
|
+
app:cardCornerRadius="12dp"
|
|
36
|
+
app:cardElevation="1dp">
|
|
37
|
+
|
|
38
|
+
<LinearLayout
|
|
39
|
+
android:layout_width="match_parent"
|
|
40
|
+
android:layout_height="wrap_content"
|
|
41
|
+
android:orientation="vertical"
|
|
42
|
+
android:padding="16dp">
|
|
43
|
+
|
|
44
|
+
<TextView
|
|
45
|
+
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
46
|
+
android:layout_width="wrap_content"
|
|
47
|
+
android:layout_height="wrap_content"
|
|
48
|
+
android:layout_marginBottom="16dp"
|
|
49
|
+
android:text="@string/developer_tools_runtime" />
|
|
50
|
+
|
|
51
|
+
<TextView
|
|
52
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
53
|
+
android:layout_width="wrap_content"
|
|
54
|
+
android:layout_height="wrap_content"
|
|
55
|
+
android:text="@string/developer_tools_session_id" />
|
|
56
|
+
|
|
57
|
+
<TextView
|
|
58
|
+
android:id="@+id/runtimeSessionIdValue"
|
|
59
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
60
|
+
android:layout_width="match_parent"
|
|
61
|
+
android:layout_height="wrap_content"
|
|
62
|
+
android:layout_marginBottom="12dp"
|
|
63
|
+
android:textIsSelectable="true" />
|
|
64
|
+
|
|
65
|
+
<TextView
|
|
66
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
67
|
+
android:layout_width="wrap_content"
|
|
68
|
+
android:layout_height="wrap_content"
|
|
69
|
+
android:text="@string/developer_tools_app_version" />
|
|
70
|
+
|
|
71
|
+
<TextView
|
|
72
|
+
android:id="@+id/runtimeAppVersionValue"
|
|
73
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
74
|
+
android:layout_width="match_parent"
|
|
75
|
+
android:layout_height="wrap_content"
|
|
76
|
+
android:layout_marginBottom="12dp" />
|
|
77
|
+
|
|
78
|
+
<TextView
|
|
79
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
80
|
+
android:layout_width="wrap_content"
|
|
81
|
+
android:layout_height="wrap_content"
|
|
82
|
+
android:text="@string/developer_tools_android_version" />
|
|
83
|
+
|
|
84
|
+
<TextView
|
|
85
|
+
android:id="@+id/runtimeAndroidVersionValue"
|
|
86
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
87
|
+
android:layout_width="match_parent"
|
|
88
|
+
android:layout_height="wrap_content"
|
|
89
|
+
android:layout_marginBottom="12dp" />
|
|
90
|
+
|
|
91
|
+
<TextView
|
|
92
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
93
|
+
android:layout_width="wrap_content"
|
|
94
|
+
android:layout_height="wrap_content"
|
|
95
|
+
android:text="@string/developer_tools_device_model" />
|
|
96
|
+
|
|
97
|
+
<TextView
|
|
98
|
+
android:id="@+id/runtimeDeviceModelValue"
|
|
99
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
100
|
+
android:layout_width="match_parent"
|
|
101
|
+
android:layout_height="wrap_content"
|
|
102
|
+
android:layout_marginBottom="12dp" />
|
|
103
|
+
|
|
104
|
+
<TextView
|
|
105
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
106
|
+
android:layout_width="wrap_content"
|
|
107
|
+
android:layout_height="wrap_content"
|
|
108
|
+
android:text="@string/developer_tools_app_uptime" />
|
|
109
|
+
|
|
110
|
+
<TextView
|
|
111
|
+
android:id="@+id/runtimeUptimeValue"
|
|
112
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
113
|
+
android:layout_width="match_parent"
|
|
114
|
+
android:layout_height="wrap_content" />
|
|
115
|
+
</LinearLayout>
|
|
116
|
+
</com.google.android.material.card.MaterialCardView>
|
|
117
|
+
|
|
118
|
+
<com.google.android.material.card.MaterialCardView
|
|
119
|
+
android:layout_width="match_parent"
|
|
120
|
+
android:layout_height="wrap_content"
|
|
121
|
+
android:layout_marginBottom="16dp"
|
|
122
|
+
app:cardCornerRadius="12dp"
|
|
123
|
+
app:cardElevation="1dp">
|
|
124
|
+
|
|
125
|
+
<LinearLayout
|
|
126
|
+
android:layout_width="match_parent"
|
|
127
|
+
android:layout_height="wrap_content"
|
|
128
|
+
android:orientation="vertical"
|
|
129
|
+
android:padding="16dp">
|
|
130
|
+
|
|
131
|
+
<TextView
|
|
132
|
+
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
133
|
+
android:layout_width="wrap_content"
|
|
134
|
+
android:layout_height="wrap_content"
|
|
135
|
+
android:layout_marginBottom="8dp"
|
|
136
|
+
android:text="@string/developer_tools_debug" />
|
|
137
|
+
|
|
138
|
+
<com.google.android.material.switchmaterial.SwitchMaterial
|
|
139
|
+
android:id="@+id/debugModeSwitch"
|
|
140
|
+
android:layout_width="match_parent"
|
|
141
|
+
android:layout_height="wrap_content"
|
|
142
|
+
android:text="@string/developer_tools_enable_debug_mode" />
|
|
143
|
+
|
|
144
|
+
<com.google.android.material.switchmaterial.SwitchMaterial
|
|
145
|
+
android:id="@+id/apiEnabledSwitch"
|
|
146
|
+
android:layout_width="match_parent"
|
|
147
|
+
android:layout_height="wrap_content"
|
|
148
|
+
android:enabled="false"
|
|
149
|
+
android:text="@string/developer_tools_enable_api" />
|
|
150
|
+
|
|
151
|
+
<TextView
|
|
152
|
+
style="@style/TextAppearance.MaterialComponents.Caption"
|
|
153
|
+
android:layout_width="match_parent"
|
|
154
|
+
android:layout_height="wrap_content"
|
|
155
|
+
android:layout_marginStart="4dp"
|
|
156
|
+
android:layout_marginBottom="16dp"
|
|
157
|
+
android:text="@string/developer_tools_api_read_only" />
|
|
158
|
+
|
|
159
|
+
<LinearLayout
|
|
160
|
+
android:layout_width="match_parent"
|
|
161
|
+
android:layout_height="wrap_content"
|
|
162
|
+
android:gravity="center_vertical"
|
|
163
|
+
android:orientation="horizontal">
|
|
164
|
+
|
|
165
|
+
<TextView
|
|
166
|
+
style="@style/TextAppearance.MaterialComponents.Body1"
|
|
167
|
+
android:layout_width="0dp"
|
|
168
|
+
android:layout_height="wrap_content"
|
|
169
|
+
android:layout_weight="1"
|
|
170
|
+
android:text="@string/developer_tools_webview_debug" />
|
|
171
|
+
|
|
172
|
+
<TextView
|
|
173
|
+
android:id="@+id/debugWebViewStatus"
|
|
174
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
175
|
+
android:layout_width="wrap_content"
|
|
176
|
+
android:layout_height="wrap_content" />
|
|
177
|
+
</LinearLayout>
|
|
178
|
+
</LinearLayout>
|
|
179
|
+
</com.google.android.material.card.MaterialCardView>
|
|
180
|
+
|
|
181
|
+
<com.google.android.material.card.MaterialCardView
|
|
182
|
+
android:layout_width="match_parent"
|
|
183
|
+
android:layout_height="wrap_content"
|
|
184
|
+
android:layout_marginBottom="16dp"
|
|
185
|
+
app:cardCornerRadius="12dp"
|
|
186
|
+
app:cardElevation="1dp">
|
|
187
|
+
|
|
188
|
+
<LinearLayout
|
|
189
|
+
android:layout_width="match_parent"
|
|
190
|
+
android:layout_height="wrap_content"
|
|
191
|
+
android:orientation="vertical"
|
|
192
|
+
android:padding="16dp">
|
|
193
|
+
|
|
194
|
+
<TextView
|
|
195
|
+
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
196
|
+
android:layout_width="wrap_content"
|
|
197
|
+
android:layout_height="wrap_content"
|
|
198
|
+
android:layout_marginBottom="8dp"
|
|
199
|
+
android:text="@string/developer_tools_logs" />
|
|
200
|
+
|
|
201
|
+
<com.google.android.material.button.MaterialButton
|
|
202
|
+
android:id="@+id/viewLogsButton"
|
|
203
|
+
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
204
|
+
android:layout_width="match_parent"
|
|
205
|
+
android:layout_height="wrap_content"
|
|
206
|
+
android:text="@string/developer_tools_view_logs" />
|
|
207
|
+
|
|
208
|
+
<com.google.android.material.button.MaterialButton
|
|
209
|
+
android:id="@+id/clearLogsButton"
|
|
210
|
+
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
211
|
+
android:layout_width="match_parent"
|
|
212
|
+
android:layout_height="wrap_content"
|
|
213
|
+
android:text="@string/developer_tools_clear_logs" />
|
|
214
|
+
|
|
215
|
+
<com.google.android.material.button.MaterialButton
|
|
216
|
+
android:id="@+id/exportDebugReportButton"
|
|
217
|
+
android:layout_width="match_parent"
|
|
218
|
+
android:layout_height="wrap_content"
|
|
219
|
+
android:text="@string/developer_tools_export_debug_report" />
|
|
220
|
+
|
|
221
|
+
<com.google.android.material.button.MaterialButton
|
|
222
|
+
android:id="@+id/shareReportButton"
|
|
223
|
+
android:layout_width="match_parent"
|
|
224
|
+
android:layout_height="wrap_content"
|
|
225
|
+
android:text="@string/developer_tools_share_report" />
|
|
226
|
+
</LinearLayout>
|
|
227
|
+
</com.google.android.material.card.MaterialCardView>
|
|
228
|
+
|
|
229
|
+
<com.google.android.material.card.MaterialCardView
|
|
230
|
+
android:layout_width="match_parent"
|
|
231
|
+
android:layout_height="wrap_content"
|
|
232
|
+
android:layout_marginBottom="16dp"
|
|
233
|
+
app:cardCornerRadius="12dp"
|
|
234
|
+
app:cardElevation="1dp">
|
|
235
|
+
|
|
236
|
+
<LinearLayout
|
|
237
|
+
android:layout_width="match_parent"
|
|
238
|
+
android:layout_height="wrap_content"
|
|
239
|
+
android:orientation="vertical"
|
|
240
|
+
android:padding="16dp">
|
|
241
|
+
|
|
242
|
+
<TextView
|
|
243
|
+
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
244
|
+
android:layout_width="wrap_content"
|
|
245
|
+
android:layout_height="wrap_content"
|
|
246
|
+
android:layout_marginBottom="8dp"
|
|
247
|
+
android:text="@string/developer_tools_crash_testing" />
|
|
248
|
+
|
|
249
|
+
<com.google.android.material.button.MaterialButton
|
|
250
|
+
android:id="@+id/throwTestExceptionButton"
|
|
251
|
+
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
252
|
+
android:layout_width="match_parent"
|
|
253
|
+
android:layout_height="wrap_content"
|
|
254
|
+
android:text="@string/developer_tools_throw_test_exception" />
|
|
255
|
+
</LinearLayout>
|
|
256
|
+
</com.google.android.material.card.MaterialCardView>
|
|
257
|
+
|
|
258
|
+
<com.google.android.material.card.MaterialCardView
|
|
259
|
+
android:layout_width="match_parent"
|
|
260
|
+
android:layout_height="wrap_content"
|
|
261
|
+
app:cardCornerRadius="12dp"
|
|
262
|
+
app:cardElevation="1dp">
|
|
263
|
+
|
|
264
|
+
<LinearLayout
|
|
265
|
+
android:layout_width="match_parent"
|
|
266
|
+
android:layout_height="wrap_content"
|
|
267
|
+
android:orientation="vertical"
|
|
268
|
+
android:padding="16dp">
|
|
269
|
+
|
|
270
|
+
<TextView
|
|
271
|
+
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
272
|
+
android:layout_width="wrap_content"
|
|
273
|
+
android:layout_height="wrap_content"
|
|
274
|
+
android:layout_marginBottom="12dp"
|
|
275
|
+
android:text="@string/developer_tools_webview" />
|
|
276
|
+
|
|
277
|
+
<LinearLayout
|
|
278
|
+
android:layout_width="match_parent"
|
|
279
|
+
android:layout_height="wrap_content"
|
|
280
|
+
android:layout_marginBottom="12dp"
|
|
281
|
+
android:gravity="center_vertical"
|
|
282
|
+
android:orientation="horizontal">
|
|
283
|
+
|
|
284
|
+
<TextView
|
|
285
|
+
style="@style/TextAppearance.MaterialComponents.Body1"
|
|
286
|
+
android:layout_width="0dp"
|
|
287
|
+
android:layout_height="wrap_content"
|
|
288
|
+
android:layout_weight="1"
|
|
289
|
+
android:text="@string/developer_tools_current_status" />
|
|
290
|
+
|
|
291
|
+
<TextView
|
|
292
|
+
android:id="@+id/webViewStatus"
|
|
293
|
+
style="@style/TextAppearance.MaterialComponents.Body2"
|
|
294
|
+
android:layout_width="wrap_content"
|
|
295
|
+
android:layout_height="wrap_content" />
|
|
296
|
+
</LinearLayout>
|
|
297
|
+
|
|
298
|
+
<com.google.android.material.button.MaterialButton
|
|
299
|
+
android:id="@+id/openChromeInspectDocsButton"
|
|
300
|
+
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
301
|
+
android:layout_width="match_parent"
|
|
302
|
+
android:layout_height="wrap_content"
|
|
303
|
+
android:text="@string/developer_tools_open_chrome_inspect_docs" />
|
|
304
|
+
</LinearLayout>
|
|
305
|
+
</com.google.android.material.card.MaterialCardView>
|
|
306
|
+
</LinearLayout>
|
|
307
|
+
</androidx.core.widget.NestedScrollView>
|
|
308
|
+
</LinearLayout>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<
|
|
2
|
+
<com.pakstr.app.debug.SupportUnlockGestureLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
3
|
android:id="@+id/mainContainer"
|
|
4
4
|
android:layout_width="match_parent"
|
|
5
5
|
android:layout_height="match_parent"
|
|
@@ -18,4 +18,13 @@
|
|
|
18
18
|
android:layout_gravity="center"
|
|
19
19
|
android:indeterminateDrawable="@drawable/custom_loader" />
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
22
|
+
android:id="@+id/developerToolsFab"
|
|
23
|
+
android:layout_width="wrap_content"
|
|
24
|
+
android:layout_height="wrap_content"
|
|
25
|
+
android:layout_gravity="bottom|end"
|
|
26
|
+
android:layout_margin="24dp"
|
|
27
|
+
android:contentDescription="@string/developer_tools"
|
|
28
|
+
android:src="@android:drawable/ic_menu_info_details" />
|
|
29
|
+
|
|
30
|
+
</com.pakstr.app.debug.SupportUnlockGestureLayout>
|
|
@@ -1,3 +1,47 @@
|
|
|
1
1
|
<resources>
|
|
2
2
|
<string name="app_name">Pakstr</string>
|
|
3
|
+
|
|
4
|
+
<string name="developer_tools_title">Developer Tools</string>
|
|
5
|
+
<string name="developer_tools_runtime">Runtime</string>
|
|
6
|
+
<string name="developer_tools_session_id">Session ID</string>
|
|
7
|
+
<string name="developer_tools_app_version">App version</string>
|
|
8
|
+
<string name="developer_tools_android_version">Android version</string>
|
|
9
|
+
<string name="developer_tools_device_model">Device model</string>
|
|
10
|
+
<string name="developer_tools_app_uptime">App uptime</string>
|
|
11
|
+
<string name="developer_tools_version_value">%1$s (%2$d)</string>
|
|
12
|
+
<string name="developer_tools_device_value">%1$s %2$s</string>
|
|
13
|
+
|
|
14
|
+
<string name="developer_tools_debug">Debug</string>
|
|
15
|
+
<string name="developer_tools_enable_debug_mode">Enable Debug Mode</string>
|
|
16
|
+
<string name="developer_tools_enable_api">Enable API</string>
|
|
17
|
+
<string name="developer_tools_api_read_only">Controlled by the packaged runtime configuration.</string>
|
|
18
|
+
<string name="developer_tools_webview_debug">WebView Debug</string>
|
|
19
|
+
<string name="developer_tools_enabled">Enabled</string>
|
|
20
|
+
<string name="developer_tools_disabled">Disabled</string>
|
|
21
|
+
|
|
22
|
+
<string name="developer_tools_logs">Logs</string>
|
|
23
|
+
<string name="developer_tools_view_logs">View Logs</string>
|
|
24
|
+
<string name="developer_tools_clear_logs">Clear Logs</string>
|
|
25
|
+
<string name="developer_tools_export_debug_report">Export Debug Report</string>
|
|
26
|
+
<string name="developer_tools_share_report">Share Report</string>
|
|
27
|
+
<string name="developer_tools_no_logs">No logs recorded.</string>
|
|
28
|
+
<string name="developer_tools_clear_logs_confirmation">Clear all stored debug logs?</string>
|
|
29
|
+
<string name="developer_tools_clear">Clear</string>
|
|
30
|
+
<string name="developer_tools_logs_cleared">Logs cleared.</string>
|
|
31
|
+
<string name="developer_tools_report_exported">Report exported to %1$s</string>
|
|
32
|
+
<string name="developer_tools_report_export_failed">Unable to export the debug report.</string>
|
|
33
|
+
|
|
34
|
+
<string name="developer_tools_crash_testing">Crash Testing</string>
|
|
35
|
+
<string name="developer_tools_throw_test_exception">Throw Test Exception</string>
|
|
36
|
+
<string name="developer_tools_crash_confirmation_title">Crash Pakstr?</string>
|
|
37
|
+
<string name="developer_tools_crash_confirmation_message">This intentionally throws an uncaught RuntimeException and closes the app so CrashHandler can capture it.</string>
|
|
38
|
+
<string name="developer_tools_crash">Crash</string>
|
|
39
|
+
|
|
40
|
+
<string name="developer_tools_webview">WebView</string>
|
|
41
|
+
<string name="developer_tools_current_status">Current WebView Debug status</string>
|
|
42
|
+
<string name="developer_tools_open_chrome_inspect_docs">Open Chrome Inspect documentation</string>
|
|
43
|
+
<string name="developer_tools_browser_unavailable">No browser is available.</string>
|
|
44
|
+
|
|
45
|
+
<string name="developer_tools">Open Developer Tools</string>
|
|
46
|
+
<string name="diagnostics_mode_enabled">Diagnostics mode enabled</string>
|
|
3
47
|
</resources>
|