diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt index 47f43dae0edf5cf59621975f0923cd8b83f15cee..07bfd4404b3f7c606c6a15b1c64b415fd6f15063 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt @@ -2,20 +2,19 @@ package de.rki.coronawarnapp.test.debugoptions.ui import android.annotation.SuppressLint import android.os.Bundle -import android.text.format.Formatter import android.view.View import android.widget.RadioButton import android.widget.RadioGroup import androidx.core.view.ViewCompat import androidx.core.view.children import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentTestDebugoptionsBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.setGone import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels @@ -32,19 +31,9 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.testLogfileToggle.apply { - setOnClickListener { vm.setLoggerEnabled(isChecked) } + binding.showDebugLogScreen.setOnClickListener { + findNavController().navigate(R.id.debuglogFragment) } - vm.loggerState.observe2(this) { state -> - binding.apply { - testLogfileToggle.isChecked = state.isLogging - val logSize = Formatter.formatShortFileSize(requireContext(), state.logsize) - testLogfileToggle.text = "Logfile enabled ($logSize)" - testLogfileShare.setGone(!state.isLogging) - } - } - binding.testLogfileShare.setOnClickListener { vm.shareLogFile() } - vm.logShareEvent.observe2(this) { showSnackBar("Logfile copied to $it") } // Server environment card binding.environmentToggleGroup.apply { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModel.kt index 9f6bfb7ad391b69671ecd2448dfbe9a8102946d0..e9b4bda7f7e71be71c837acb467adb246991fadb 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModel.kt @@ -1,22 +1,16 @@ package de.rki.coronawarnapp.test.debugoptions.ui -import android.content.Context import com.squareup.inject.assisted.AssistedInject import de.rki.coronawarnapp.environment.EnvironmentSetup import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnvironmentType import de.rki.coronawarnapp.test.debugoptions.ui.EnvironmentState.Companion.toEnvironmentState -import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.coroutine.DispatcherProvider -import de.rki.coronawarnapp.util.debug.LoggerState.Companion.toLoggerState -import de.rki.coronawarnapp.util.di.AppContext import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.ui.smartLiveData import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory -import java.io.File class DebugOptionsFragmentViewModel @AssistedInject constructor( - @AppContext private val context: Context, private val envSetup: EnvironmentSetup, dispatcherProvider: DispatcherProvider ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { @@ -34,36 +28,6 @@ class DebugOptionsFragmentViewModel @AssistedInject constructor( } } - val loggerState by smartLiveData { - CWADebug.toLoggerState() - } - - fun setLoggerEnabled(enable: Boolean) { - CWADebug.fileLogger?.let { - if (enable) it.start() else it.stop() - } - loggerState.update { CWADebug.toLoggerState() } - } - - val logShareEvent = SingleLiveEvent<File?>() - - fun shareLogFile() { - CWADebug.fileLogger?.let { - launch { - if (!it.logFile.exists()) return@launch - - val externalPath = File( - context.getExternalFilesDir(null), - "LogFile-${System.currentTimeMillis()}.log" - ) - - it.logFile.copyTo(externalPath) - - logShareEvent.postValue(externalPath) - } - } - } - @AssistedInject.Factory interface Factory : SimpleCWAViewModelFactory<DebugOptionsFragmentViewModel> } diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml index 92afdbf89c73d87c4cff4ea27b794c145db9a5c9..cca12450d9fee3eafa2d51795b793186606cf4b7 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml @@ -32,27 +32,26 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <Switch - android:id="@+id/test_logfile_toggle" - style="@style/body1" + <TextView + android:id="@+id/new_debuglog_screen_explanation" + style="@style/body2" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_tiny" + android:layout_marginTop="@dimen/spacing_small" android:layout_weight="1" - android:text="Logfile enabled" - android:theme="@style/switchBase" + android:text="The debuglog option has moved. It's now available for all builds. For test builds it's started automatically on each app start." app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/debug_container_title" /> <Button - android:id="@+id/test_logfile_share" + android:id="@+id/show_debug_log_screen" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_tiny" - android:text="Share log" + android:text="Open new debug log screen" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@+id/test_logfile_toggle" /> + app:layout_constraintTop_toBottomOf="@+id/new_debuglog_screen_explanation" /> </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt index 2cdd042ea0c4f9e160ff32fb0896dd0ecc8e0653..da7e345ccacd4f4f88a8c5fd4a938f8dd7827fbb 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.app.Application import android.content.Context import android.util.Log +import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.di.ApplicationComponent import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job @@ -44,8 +45,19 @@ object DebugLogger : DebugLoggerBase() { context = application try { - if (triggerFile.exists()) { - Timber.tag(TAG).i("Trigger file exists, starting debug log.") + val startLogger = when { + triggerFile.exists() -> { + Timber.tag(TAG).i("Trigger file exists, starting debug log.") + true + } + CWADebug.isDeviceForTestersBuild -> { + Timber.tag(TAG).i("Trigger file does not exist, but it's a tester build, starting debug log.") + true + } + else -> false + } + + if (startLogger) { runBlocking { start() } } } catch (e: Exception) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt index 15f4ffa545e810b2f56e68134bf624d9e9a60c47..c794c54b9521708e3cf4e11237e7f81d65ef935f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt @@ -5,13 +5,11 @@ import android.os.Build import androidx.annotation.VisibleForTesting import de.rki.coronawarnapp.BuildConfig import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger -import de.rki.coronawarnapp.util.debug.FileLogger import de.rki.coronawarnapp.util.debug.UncaughtExceptionLogger import de.rki.coronawarnapp.util.di.ApplicationComponent import timber.log.Timber object CWADebug { - var fileLogger: FileLogger? = null fun init(application: Application) { if (isDebugBuildOrMode) System.setProperty("kotlinx.coroutines.debug", "on") @@ -19,9 +17,6 @@ object CWADebug { if (isDeviceForTestersBuild) { Timber.plant(Timber.DebugTree()) } - if (isDeviceForTestersBuild) { - fileLogger = FileLogger(application) - } setupExceptionHandler() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt deleted file mode 100644 index e8d283d9c7695095ffa9995d76aa3cb2c232873a..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt +++ /dev/null @@ -1,46 +0,0 @@ -package de.rki.coronawarnapp.util.debug - -import android.content.Context -import de.rki.coronawarnapp.util.CWADebug -import timber.log.Timber -import java.io.File - -class FileLogger constructor(context: Context) { - - val logFile = File(context.cacheDir, "FileLoggerTree.log") - - private val blockerFile = File(context.filesDir, "FileLoggerTree.blocker") - private var loggerTree: FileLoggerTree? = null - - val isLogging: Boolean - get() = loggerTree != null - - init { - if (!blockerFile.exists()) { - start() - } - } - - fun start() { - if (!CWADebug.isDeviceForTestersBuild) return - - if (loggerTree != null) return - - loggerTree = FileLoggerTree(logFile).also { - Timber.plant(it) - it.start() - blockerFile.delete() - } - } - - fun stop() { - if (!CWADebug.isDeviceForTestersBuild) return - - loggerTree?.let { - it.stop() - logFile.delete() - blockerFile.createNewFile() - loggerTree = null - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt deleted file mode 100644 index c3f50042c4c57701603af3c29fe10bf2782b6604..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt +++ /dev/null @@ -1,87 +0,0 @@ -package de.rki.coronawarnapp.util.debug - -import android.annotation.SuppressLint -import android.util.Log -import org.joda.time.Instant -import timber.log.Timber -import java.io.File -import java.io.FileOutputStream -import java.io.IOException -import java.io.OutputStreamWriter - -@SuppressLint("LogNotTimber") -class FileLoggerTree(private val logFile: File) : Timber.DebugTree() { - private var logWriter: OutputStreamWriter? = null - - @SuppressLint("SetWorldReadable") - @Synchronized - fun start() { - if (logWriter != null) return - - logFile.parentFile.mkdirs() - if (logFile.createNewFile()) { - Log.i(TAG, "File logger writing to " + logFile.path) - } - if (logFile.setReadable(true, false)) { - Log.i(TAG, "Debug run log read permission set") - } - - try { - logWriter = OutputStreamWriter(FileOutputStream(logFile, true)) - logWriter!!.write("=== BEGIN ===\n") - logWriter!!.write("Logfile: $logFile\n") - logWriter!!.flush() - Log.i(TAG, "File logger started.") - } catch (e: IOException) { - e.printStackTrace() - - logFile.delete() - if (logWriter != null) logWriter!!.close() - } - } - - @Synchronized - fun stop() { - logWriter?.let { - logWriter = null - try { - it.write("=== END ===\n") - it.close() - } catch (ignore: IOException) { - } - Log.i(TAG, "File logger stopped.") - } - } - - override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { - logWriter?.let { - try { - it.write("${Instant.now()} ${priorityToString(priority)}/$tag: $message\n") - it.flush() - } catch (e: IOException) { - Timber.tag(TAG).e(e) - try { - it.close() - } catch (ignore: Exception) { - } - logWriter = null - } - } - } - - override fun toString(): String { - return "FileLoggerTree(file=$logFile)" - } - - companion object { - private const val TAG = "FileLoggerTree" - private fun priorityToString(priority: Int): String = when (priority) { - Log.ERROR -> "E" - Log.WARN -> "W" - Log.INFO -> "I" - Log.DEBUG -> "D" - Log.VERBOSE -> "V" - else -> priority.toString() - } - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/LoggerState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/LoggerState.kt deleted file mode 100644 index 7f47800109c15da775967f2f25739361a3950406..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/LoggerState.kt +++ /dev/null @@ -1,15 +0,0 @@ -package de.rki.coronawarnapp.util.debug - -import de.rki.coronawarnapp.util.CWADebug - -data class LoggerState( - val isLogging: Boolean, - val logsize: Long -) { - companion object { - internal fun CWADebug.toLoggerState() = LoggerState( - isLogging = fileLogger?.isLogging ?: false, - logsize = fileLogger?.logFile?.length() ?: 0L - ) - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt index 99678b82732651514deb19468f0a5eb673214a3f..addaad19d1a7f7fad078a00a646082be36867d40 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.app.Application import dagger.Lazy import de.rki.coronawarnapp.bugreporting.censors.RegistrationTokenCensor +import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.di.ApplicationComponent import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe @@ -10,6 +11,7 @@ import io.mockk.MockKAnnotations import io.mockk.clearAllMocks import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockkObject import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -36,6 +38,9 @@ class DebugLoggerTest : BaseIOTest() { @BeforeEach fun setup() { MockKAnnotations.init(this) + mockkObject(CWADebug) + every { CWADebug.isDeviceForTestersBuild } returns false + testDir.mkdirs() testDir.exists() shouldBe true @@ -80,6 +85,16 @@ class DebugLoggerTest : BaseIOTest() { runningLog.exists() shouldBe true } + @Test + fun `init calls start if it is a tester build`() { + every { CWADebug.isDeviceForTestersBuild } returns true + createInstance().apply { + init(application) + isLogging shouldBe true + } + runningLog.exists() shouldBe true + } + @Test fun `start plants a tree and starts a logging coroutine`() { val instance = createInstance().apply { diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt index 7272bbc481705a1418c822223ce30cb48345000e..4883ed9049aadf384f6dbd79469f450eb464397b 100644 --- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt @@ -55,7 +55,6 @@ class DebugOptionsFragmentViewModelTest : BaseTest() { } private fun createViewModel(): DebugOptionsFragmentViewModel = DebugOptionsFragmentViewModel( - context = context, envSetup = environmentSetup, dispatcherProvider = TestDispatcherProvider )