diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6eb2e60c..79ada8ae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,9 +3,9 @@ xmlns:tools="http://schemas.android.com/tools"> - - - + - - - - - - \ No newline at end of file diff --git a/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderModule.kt b/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderModule.kt index 1291eef3..9ab7463f 100644 --- a/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderModule.kt +++ b/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderModule.kt @@ -12,7 +12,6 @@ import eu.darken.octi.common.debug.logging.log import eu.darken.octi.common.debug.logging.logTag import eu.darken.octi.common.debug.recording.ui.RecorderActivity import eu.darken.octi.common.flow.DynamicStateFlow -import eu.darken.octi.common.startServiceCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter @@ -57,11 +56,7 @@ class RecorderModule @Inject constructor( newRecorder.start(createRecordingFilePath()) triggerFile.createNewFile() - context.startServiceCompat(Intent(context, RecorderService::class.java)) - - copy( - recorder = newRecorder - ) + copy(recorder = newRecorder) } else if (!shouldRecord && isRecording) { val currentLog = recorder!!.path!! recorder.stop() diff --git a/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderService.kt b/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderService.kt deleted file mode 100644 index d4e697f7..00000000 --- a/app/src/main/java/eu/darken/octi/common/debug/recording/core/RecorderService.kt +++ /dev/null @@ -1,112 +0,0 @@ -package eu.darken.octi.common.debug.recording.core - -import android.app.NotificationManager -import android.app.PendingIntent -import android.content.Intent -import android.os.IBinder -import androidx.core.app.NotificationChannelCompat -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import dagger.hilt.android.AndroidEntryPoint -import eu.darken.octi.R -import eu.darken.octi.common.BuildConfigWrap -import eu.darken.octi.common.coroutine.DispatcherProvider -import eu.darken.octi.common.debug.logging.log -import eu.darken.octi.common.debug.logging.logTag -import eu.darken.octi.common.notifications.PendingIntentCompat -import eu.darken.octi.common.uix.Service2 -import eu.darken.octi.main.ui.MainActivity -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import javax.inject.Inject - - -@AndroidEntryPoint -class RecorderService : Service2() { - private lateinit var builder: NotificationCompat.Builder - - @Inject lateinit var recorderModule: RecorderModule - @Inject lateinit var notificationManager: NotificationManager - @Inject lateinit var dispatcherProvider: DispatcherProvider - private val recorderScope by lazy { - CoroutineScope(SupervisorJob() + dispatcherProvider.IO) - } - - override fun onBind(intent: Intent?): IBinder? = null - - override fun onCreate() { - super.onCreate() - val compatChannel = NotificationChannelCompat - .Builder(NOTIF_CHANID_DEBUG, NotificationManagerCompat.IMPORTANCE_MAX) - .setName(getString(R.string.debug_notification_channel_label)) - .build() - NotificationManagerCompat.from(this).createNotificationChannel(compatChannel) - - val openIntent = Intent(this, MainActivity::class.java) - val openPi = PendingIntent.getActivity( - this, - 0, - openIntent, - PendingIntentCompat.FLAG_IMMUTABLE - ) - - val stopIntent = Intent(this, RecorderService::class.java) - stopIntent.action = STOP_ACTION - val stopPi = PendingIntent.getService( - this, - 0, - stopIntent, - PendingIntentCompat.FLAG_IMMUTABLE - ) - - builder = NotificationCompat.Builder(this, NOTIF_CHANID_DEBUG) - .setChannelId(NOTIF_CHANID_DEBUG) - .setContentIntent(openPi) - .setPriority(NotificationCompat.PRIORITY_MAX) - .setSmallIcon(R.drawable.ic_baseline_bug_report_24) - .setContentText("Idle") - .setContentTitle(getString(R.string.app_name)) - .addAction(NotificationCompat.Action.Builder(0, getString(R.string.general_done_action), stopPi).build()) - - startForeground(NOTIFICATION_ID, builder.build()) - - recorderModule.state - .onEach { - if (it.isRecording) { - builder.setContentText("Recording debug log: ${it.currentLogPath?.path}") - notificationManager.notify(NOTIFICATION_ID, builder.build()) - } else { - stopForeground(true) - stopSelf() - } - } - .launchIn(recorderScope) - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - log(TAG) { "onStartCommand(intent=$intent, flags=$flags, startId=$startId" } - if (intent?.action == STOP_ACTION) { - recorderScope.launch { - recorderModule.stopRecorder() - } - } - return START_STICKY - } - - override fun onDestroy() { - recorderScope.coroutineContext.cancel() - super.onDestroy() - } - - companion object { - private val TAG = - logTag("Debug", "Log", "eu.darken.octi.common.debug.recording.core.Recorder", "Service") - private val NOTIF_CHANID_DEBUG = "${BuildConfigWrap.APPLICATION_ID}.notification.channel.debug" - private const val STOP_ACTION = "STOP_SERVICE" - private const val NOTIFICATION_ID = 53 - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportEvent.kt b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportEvent.kt new file mode 100644 index 00000000..95ae9615 --- /dev/null +++ b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportEvent.kt @@ -0,0 +1,5 @@ +package eu.darken.octi.main.ui.settings.support + +sealed interface SupportEvent { + data object DebugLogInfo : SupportEvent +} \ No newline at end of file diff --git a/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragment.kt b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragment.kt index 78460b2e..74c8757f 100644 --- a/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragment.kt +++ b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragment.kt @@ -6,7 +6,6 @@ import androidx.annotation.Keep import androidx.fragment.app.viewModels import androidx.preference.Preference import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import eu.darken.octi.R import eu.darken.octi.common.ClipboardHelper @@ -35,31 +34,37 @@ class SupportFragment : PreferenceFragment2() { override fun onPreferencesCreated() { debugLogPref.setOnPreferenceClickListener { - MaterialAlertDialogBuilder(requireContext()).apply { - setTitle(R.string.support_debuglog_label) - setMessage(R.string.settings_debuglog_explanation) - setPositiveButton(R.string.general_continue) { _, _ -> vm.startDebugLog() } - setNegativeButton(R.string.general_cancel_action) { _, _ -> } - setNeutralButton(R.string.settings_privacy_policy_label) { _, _ -> webpageTool.open(PrivacyPolicy.URL) } - }.show() + vm.toggleDebugLog() true } super.onPreferencesCreated() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - vm.clipboardEvent.observe2(this) { installId -> - Snackbar.make(requireView(), installId, Snackbar.LENGTH_INDEFINITE) - .setAction(R.string.general_copy_action) { - clipboardHelper.copyToClipboard(installId) + vm.isRecording.observe2(this) { + debugLogPref.apply { + if (it != null) { + setIcon(R.drawable.ic_bug_stop_24) + setTitle(R.string.support_debuglog_inprogress_label) + summary = it.path + } else { + setIcon(R.drawable.ic_baseline_bug_report_24) + setTitle(R.string.support_debuglog_label) + setSummary(R.string.support_debuglog_desc) } - .show() + } } - vm.emailEvent.observe2(this) { startActivity(it) } - - vm.isRecording.observe2(this) { - debugLogPref.isEnabled = !it + vm.events.observe2(this) { + when (it) { + SupportEvent.DebugLogInfo -> MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(R.string.support_debuglog_label) + setMessage(R.string.settings_debuglog_explanation) + setPositiveButton(R.string.general_continue) { _, _ -> vm.toggleDebugLog(consent = true) } + setNegativeButton(R.string.general_cancel_action) { _, _ -> } + setNeutralButton(R.string.settings_privacy_policy_label) { _, _ -> webpageTool.open(PrivacyPolicy.URL) } + }.show() + } } super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragmentVM.kt b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragmentVM.kt index 1e384052..97d3b431 100644 --- a/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragmentVM.kt +++ b/app/src/main/java/eu/darken/octi/main/ui/settings/support/SupportFragmentVM.kt @@ -1,12 +1,12 @@ package eu.darken.octi.main.ui.settings.support -import android.content.Intent import dagger.hilt.android.lifecycle.HiltViewModel import eu.darken.octi.common.coroutine.DispatcherProvider import eu.darken.octi.common.debug.logging.log import eu.darken.octi.common.debug.recording.core.RecorderModule import eu.darken.octi.common.livedata.SingleLiveEvent import eu.darken.octi.common.uix.ViewModel3 +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import javax.inject.Inject @@ -16,13 +16,22 @@ class SupportFragmentVM @Inject constructor( private val recorderModule: RecorderModule, ) : ViewModel3(dispatcherProvider) { - val emailEvent = SingleLiveEvent() - val clipboardEvent = SingleLiveEvent() + val isRecording = recorderModule.state.map { it.currentLogPath }.asLiveData2() - val isRecording = recorderModule.state.map { it.isRecording }.asLiveData2() + val events = SingleLiveEvent() - fun startDebugLog() = launch { - log { "startDebugLog()" } - recorderModule.startRecorder() + fun toggleDebugLog(consent: Boolean = false) = launch { + log { "toggleDebugLog()" } + recorderModule.apply { + if (state.first().isRecording) { + stopRecorder() + } else { + if (consent) { + startRecorder() + } else { + events.postValue(SupportEvent.DebugLogInfo) + } + } + } } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bug_stop_24.xml b/app/src/main/res/drawable/ic_bug_stop_24.xml new file mode 100644 index 00000000..83f9224c --- /dev/null +++ b/app/src/main/res/drawable/ic_bug_stop_24.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bcc7d9ac..adc593b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,7 +56,8 @@ Discord A place to hang out in and ask questions. - Debug log + Record debug log + Stop debug log Record everything the app is doing into a text file that you can share. Support This file contains sensitive information (e.g. your installed applications). Only share it with trusted parties.