Skip to content

Commit 3eaf993

Browse files
committed
Record debug logs without foreground service
Some overhaul of log recording to get rid of the `FOREGROUND_SERVICE_SPECIAL_USE` which is a headache with Google
1 parent 0ee7915 commit 3eaf993

File tree

44 files changed

+97
-245
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+97
-245
lines changed

app/src/main/AndroidManifest.xml

-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
1111

1212
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
13-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
1413

1514
<uses-feature
1615
android:name="android.hardware.bluetooth_le"
@@ -77,14 +76,6 @@
7776
android:name=".common.debug.recording.ui.RecorderActivity"
7877
android:theme="@style/AppThemeFloating" />
7978

80-
<service
81-
android:name=".common.debug.recording.core.RecorderService"
82-
android:foregroundServiceType="specialUse">
83-
<property
84-
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
85-
android:value="Users can record a debug log to help developers with bugs. The debug log recording is controlled via notifications and hosted in a foreground service." />
86-
</service>
87-
8879
<!-- Worker stuff-->
8980
<service
9081
android:name="androidx.work.impl.foreground.SystemForegroundService"

app/src/main/java/eu/darken/capod/common/debug/recording/core/RecorderModule.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ import eu.darken.capod.common.debug.logging.log
1414
import eu.darken.capod.common.debug.logging.logTag
1515
import eu.darken.capod.common.debug.recording.ui.RecorderActivity
1616
import eu.darken.capod.common.flow.DynamicStateFlow
17-
import eu.darken.capod.common.startServiceCompat
1817
import kotlinx.coroutines.CoroutineScope
19-
import kotlinx.coroutines.flow.*
18+
import kotlinx.coroutines.flow.Flow
19+
import kotlinx.coroutines.flow.filter
20+
import kotlinx.coroutines.flow.first
21+
import kotlinx.coroutines.flow.launchIn
22+
import kotlinx.coroutines.flow.onEach
2023
import kotlinx.coroutines.plus
2124
import java.io.File
2225
import javax.inject.Inject
@@ -55,8 +58,6 @@ class RecorderModule @Inject constructor(
5558
newRecorder.start(createRecordingFilePath())
5659
triggerFile.createNewFile()
5760

58-
context.startServiceCompat(Intent(context, RecorderService::class.java))
59-
6061
log(TAG, INFO) { "Build.Fingerprint: ${Build.FINGERPRINT}" }
6162
log(TAG, INFO) { "BuildConfig.Versions: ${BuildConfigWrap.VERSION_DESCRIPTION_LONG}" }
6263

app/src/main/java/eu/darken/capod/common/debug/recording/core/RecorderService.kt

-115
This file was deleted.

app/src/main/java/eu/darken/capod/common/debug/recording/ui/RecorderActivityVM.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class RecorderActivityVM @Inject constructor(
9595
}
9696

9797

98-
val chooserIntent = Intent.createChooser(intent, context.getString(R.string.debug_debuglog_file_label))
98+
val chooserIntent = Intent.createChooser(intent, context.getString(R.string.support_debuglog_label))
9999
shareEvent.postValue(chooserIntent)
100100
}
101101

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package eu.darken.capod.common.debug.recording.ui
2+
3+
import android.content.Context
4+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
5+
import eu.darken.capod.R
6+
import eu.darken.capod.common.PrivacyPolicy
7+
import eu.darken.capod.common.WebpageTool
8+
9+
class RecorderConsentDialog(
10+
private val context: Context,
11+
private val webpageTool: WebpageTool
12+
) {
13+
fun showDialog(onStartRecord: () -> Unit) {
14+
MaterialAlertDialogBuilder(context).apply {
15+
setTitle(R.string.support_debuglog_label)
16+
setMessage(R.string.settings_debuglog_explanation)
17+
setPositiveButton(R.string.debug_debuglog_record_action) { _, _ -> onStartRecord() }
18+
setNegativeButton(R.string.general_cancel_action) { _, _ -> }
19+
setNeutralButton(R.string.settings_privacy_policy_label) { _, _ ->
20+
webpageTool.open(PrivacyPolicy.URL)
21+
}
22+
}.show()
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
package eu.darken.capod.main.ui.settings.general.debug
22

3-
import android.os.Bundle
4-
import android.view.View
53
import androidx.annotation.Keep
64
import androidx.fragment.app.viewModels
7-
import androidx.preference.Preference
85
import dagger.hilt.android.AndroidEntryPoint
96
import eu.darken.capod.R
107
import eu.darken.capod.common.debug.DebugSettings
11-
import eu.darken.capod.common.observe2
128
import eu.darken.capod.common.uix.PreferenceFragment3
139
import javax.inject.Inject
1410

@@ -25,17 +21,4 @@ class DebugSettingsFragment : PreferenceFragment3() {
2521

2622
override val preferenceFile: Int = R.xml.preferences_debug
2723

28-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29-
val logPref = findPreference<Preference>("debug.log.record")!!
30-
vm.state.observe2(this) {
31-
logPref.summary = it.currentLogPath?.path
32-
}
33-
logPref.setOnPreferenceClickListener {
34-
vm.toggleRecorder()
35-
true
36-
}
37-
38-
super.onViewCreated(view, savedInstanceState)
39-
}
40-
4124
}

app/src/main/java/eu/darken/capod/main/ui/settings/general/debug/DebugSettingsFragmentVM.kt

-12
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,20 @@ import eu.darken.capod.common.coroutine.DispatcherProvider
66
import eu.darken.capod.common.debug.DebugSettings
77
import eu.darken.capod.common.debug.logging.log
88
import eu.darken.capod.common.debug.logging.logTag
9-
import eu.darken.capod.common.debug.recording.core.RecorderModule
109
import eu.darken.capod.common.uix.ViewModel3
1110
import eu.darken.capod.main.core.GeneralSettings
1211
import kotlinx.coroutines.flow.distinctUntilChanged
13-
import kotlinx.coroutines.flow.first
1412
import kotlinx.coroutines.flow.onEach
1513
import javax.inject.Inject
1614

1715
@HiltViewModel
1816
class DebugSettingsFragmentVM @Inject constructor(
1917
private val handle: SavedStateHandle,
2018
dispatcherProvider: DispatcherProvider,
21-
private val recorderModule: RecorderModule,
2219
private val generalSettings: GeneralSettings,
2320
private val debugSettings: DebugSettings,
2421
) : ViewModel3(dispatcherProvider) {
2522

26-
val state = recorderModule.state.asLiveData2()
27-
2823
init {
2924
debugSettings.showUnfiltered.flow
3025
.distinctUntilChanged()
@@ -37,13 +32,6 @@ class DebugSettingsFragmentVM @Inject constructor(
3732
.launchInViewModel()
3833
}
3934

40-
fun toggleRecorder() = launch {
41-
if (recorderModule.state.first().isRecording) {
42-
recorderModule.stopRecorder()
43-
} else {
44-
recorderModule.startRecorder()
45-
}
46-
}
4735

4836
companion object {
4937
private val TAG = logTag("Settings", "Debug", "VM")

app/src/main/java/eu/darken/capod/main/ui/settings/support/SupportFragment.kt

+29-9
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import android.os.Bundle
44
import android.view.View
55
import androidx.annotation.Keep
66
import androidx.fragment.app.viewModels
7-
import com.google.android.material.snackbar.Snackbar
7+
import androidx.preference.Preference
88
import dagger.hilt.android.AndroidEntryPoint
99
import eu.darken.capod.R
10-
import eu.darken.capod.common.ClipboardHelper
10+
import eu.darken.capod.common.WebpageTool
11+
import eu.darken.capod.common.debug.recording.ui.RecorderConsentDialog
1112
import eu.darken.capod.common.observe2
1213
import eu.darken.capod.common.uix.PreferenceFragment3
1314
import eu.darken.capod.main.core.GeneralSettings
@@ -24,17 +25,36 @@ class SupportFragment : PreferenceFragment3() {
2425

2526
override val settings: GeneralSettings by lazy { generalSettings }
2627

27-
@Inject lateinit var clipboardHelper: ClipboardHelper
28+
@Inject lateinit var webpageTool: WebpageTool
29+
30+
private val debugLogPref by lazy { findPreference<Preference>("support.debuglog")!! }
2831

2932
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
30-
vm.clipboardEvent.observe2(this) { installId ->
31-
Snackbar.make(requireView(), installId, Snackbar.LENGTH_INDEFINITE)
32-
.setAction(R.string.general_copy_action) {
33-
clipboardHelper.copyToClipboard(installId)
33+
vm.recorderState.observe2(this) { state ->
34+
debugLogPref.setIcon(
35+
if (state.isRecording) R.drawable.ic_cancel
36+
else R.drawable.ic_baseline_bug_report_24
37+
)
38+
debugLogPref.setTitle(
39+
if (state.isRecording) R.string.debug_debuglog_stop_action
40+
else R.string.debug_debuglog_record_action
41+
)
42+
debugLogPref.summary = when {
43+
state.isRecording -> state.currentLogPath?.path
44+
else -> getString(R.string.debug_debuglog_record_action)
45+
}
46+
47+
debugLogPref.setOnPreferenceClickListener {
48+
if (state.isRecording) {
49+
vm.stopDebugLog()
50+
} else {
51+
RecorderConsentDialog(requireContext(), webpageTool).showDialog {
52+
vm.startDebugLog()
53+
}
3454
}
35-
.show()
55+
true
56+
}
3657
}
37-
3858
super.onViewCreated(view, savedInstanceState)
3959
}
4060
}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
package eu.darken.capod.main.ui.settings.support
22

3-
import androidx.lifecycle.SavedStateHandle
43
import dagger.hilt.android.lifecycle.HiltViewModel
5-
import eu.darken.capod.common.InstallId
64
import eu.darken.capod.common.coroutine.DispatcherProvider
7-
import eu.darken.capod.common.livedata.SingleLiveEvent
5+
import eu.darken.capod.common.debug.logging.log
6+
import eu.darken.capod.common.debug.recording.core.RecorderModule
87
import eu.darken.capod.common.uix.ViewModel3
98
import javax.inject.Inject
109

1110
@HiltViewModel
1211
class SupportFragmentVM @Inject constructor(
13-
private val handle: SavedStateHandle,
1412
private val dispatcherProvider: DispatcherProvider,
15-
private val installId: InstallId,
13+
private val recorderModule: RecorderModule,
1614
) : ViewModel3(dispatcherProvider) {
1715

18-
val clipboardEvent = SingleLiveEvent<String>()
16+
val recorderState = recorderModule.state.asLiveData2()
1917

20-
fun copyInstallID() = launch {
21-
clipboardEvent.postValue(installId.id)
18+
fun startDebugLog() = launch {
19+
log(TAG) { "startDebugLog()" }
20+
recorderModule.startRecorder()
21+
}
22+
23+
fun stopDebugLog() = launch {
24+
log(TAG) { "stopDebugLog()" }
25+
recorderModule.stopRecorder()
2226
}
2327
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorControlNormal"
5+
android:viewportWidth="24.0"
6+
android:viewportHeight="24.0">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z" />
10+
</vector>

app/src/main/res/values-ar/strings.xml

-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@
4444
<string name="debug_debuglog_size_label">الحجم</string>
4545
<string name="debug_debuglog_size_compressed_label">الحجم المضغوط</string>
4646
<string name="debug_notification_channel_label">اشعارات التصحيح</string>
47-
<string name="debug_debuglog_file_label">ملف مسجل</string>
48-
<string name="debug_debuglog_record_action">ملف التصحيح مسجل</string>
4947
<string name="settings_support_installid_label">مُعرف التثبيت</string>
5048
<string name="settings_support_installid_desc">تقارير الأخطاء والمشاكل التلقائية تكون مجهول المصدر. شارك مُعرف التثبيت الخاص بك إذا احتاج المطور إلى العثور على الأخطاء والمشاكل الخاصة بك.</string>
5149
<string name="settings_support_label">الدعم</string>

app/src/main/res/values-az/strings.xml

-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040
<string name="debug_debuglog_size_label">Həcm</string>
4141
<string name="debug_debuglog_size_compressed_label">Sıxışdırılmış həcm</string>
4242
<string name="debug_notification_channel_label">Sazlama bildirişləri</string>
43-
<string name="debug_debuglog_file_label">Yazılmış jurnal faylı</string>
44-
<string name="debug_debuglog_record_action">Sazlama jurnalına yaz</string>
4543
<string name="settings_support_installid_label">Quraşdırma kimliyi</string>
4644
<string name="settings_support_installid_desc">Avtomatik xəta hesabatları anonimdir. Tərtibatçının xəta hesabatlarınızı tapmasına ehtiyacı varsa quraşdırma kimliyinizi paylaşın.</string>
4745
<string name="settings_support_label">Dəstək</string>

0 commit comments

Comments
 (0)