From 172a9cf06cbd03ee1d6ecf1f2cfbe6a0f8afb9df Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Fri, 13 Sep 2019 10:06:03 -0700 Subject: [PATCH] Extract and test crash reporter code --- .../fenix/crashes/CrashReporterController.kt | 70 +++++++++++++++ .../fenix/crashes/CrashReporterFragment.kt | 57 ++++-------- .../res/layout/fragment_crash_reporter.xml | 20 ++--- .../crashes/CrashReporterControllerTest.kt | 90 +++++++++++++++++++ 4 files changed, 187 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt create mode 100644 app/src/test/java/org/mozilla/fenix/crashes/CrashReporterControllerTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt new file mode 100644 index 000000000..3a18fa07a --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.crashes + +import androidx.navigation.NavController +import mozilla.components.browser.session.Session +import mozilla.components.lib.crash.Crash +import org.mozilla.fenix.R +import org.mozilla.fenix.components.Components +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ext.nav +import org.mozilla.fenix.utils.Settings + +class CrashReporterController( + private val crash: Crash, + private val session: Session?, + private val navController: NavController, + private val components: Components, + private val settings: Settings +) { + + init { + components.analytics.metrics.track(Event.CrashReporterOpened) + } + + /** + * Closes the crash reporter fragment and tries to recover the session. + * + * @param sendCrash If true, submit a crash report. + */ + fun handleCloseAndRestore(sendCrash: Boolean) { + submitReportIfNecessary(sendCrash) + + components.useCases.sessionUseCases.crashRecovery.invoke() + navController.popBackStack() + } + + /** + * Closes the crash reporter fragment and the tab. + * + * @param sendCrash If true, submit a crash report. + */ + fun handleCloseAndRemove(sendCrash: Boolean) { + session ?: return + submitReportIfNecessary(sendCrash) + + components.useCases.tabsUseCases.removeTab(session) + components.useCases.sessionUseCases.crashRecovery.invoke() + navController.nav( + R.id.crashReporterFragment, + CrashReporterFragmentDirections.actionCrashReporterFragmentToHomeFragment() + ) + } + + /** + * Submits the crash report if the "Send crash" checkbox was checked and the setting is enabled. + */ + private fun submitReportIfNecessary(sendCrash: Boolean) { + val didSubmitReport = if (sendCrash && settings.isCrashReportingEnabled) { + components.analytics.crashReporter.submitReport(crash) + true + } else { + false + } + + components.analytics.metrics.track(Event.CrashReporterClosed(didSubmitReport)) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterFragment.kt b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterFragment.kt index 63260e9f4..d1f9c7cf7 100644 --- a/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterFragment.kt @@ -10,19 +10,19 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import androidx.navigation.Navigation import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs import kotlinx.android.synthetic.main.fragment_crash_reporter.* -import mozilla.components.browser.session.Session import mozilla.components.lib.crash.Crash import org.mozilla.fenix.R -import org.mozilla.fenix.components.metrics.Event -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings +/** + * Fragment shown when a tab crashes. + */ class CrashReporterFragment : Fragment() { + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -31,21 +31,25 @@ class CrashReporterFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val crash = Crash.fromIntent(CrashReporterFragmentArgs.fromBundle(arguments!!).crashIntent) - title.text = - getString(R.string.tab_crash_title_2, context!!.getString(R.string.app_name)) + val args: CrashReporterFragmentArgs by navArgs() + val crash = Crash.fromIntent(args.crashIntent) - requireContext().components.analytics.metrics.track(Event.CrashReporterOpened) + title.text = getString(R.string.tab_crash_title_2, getString(R.string.app_name)) - val selectedSession = requireComponents.core.sessionManager.selectedSession + val controller = CrashReporterController( + crash, + session = requireComponents.core.sessionManager.selectedSession, + navController = findNavController(), + components = requireComponents, + settings = requireContext().settings + ) restoreTabButton.setOnClickListener { - selectedSession?.let { session -> closeFragment(true, session, crash) } + controller.handleCloseAndRestore(sendCrashCheckbox.isChecked) } - closeTabButton.setOnClickListener { - selectedSession?.let { session -> closeFragment(false, session, crash) } + controller.handleCloseAndRemove(sendCrashCheckbox.isChecked) } } @@ -53,31 +57,4 @@ class CrashReporterFragment : Fragment() { super.onResume() (activity as AppCompatActivity).supportActionBar?.hide() } - - private fun closeFragment(shouldRestore: Boolean, session: Session, crash: Crash) { - submitReportIfNecessary(crash) - - if (shouldRestore) { - requireComponents.useCases.sessionUseCases.crashRecovery.invoke() - Navigation.findNavController(view!!).popBackStack() - } else { - requireComponents.useCases.tabsUseCases.removeTab.invoke(session) - requireComponents.useCases.sessionUseCases.crashRecovery.invoke() - navigateHome() - } - } - - private fun submitReportIfNecessary(crash: Crash) { - var didSubmitCrashReport = false - if (requireContext().settings.isCrashReportingEnabled && sendCrashCheckbox.isChecked) { - requireComponents.analytics.crashReporter.submitReport(crash) - didSubmitCrashReport = true - } - requireContext().components.analytics.metrics.track(Event.CrashReporterClosed(didSubmitCrashReport)) - } - - private fun navigateHome() { - val directions = CrashReporterFragmentDirections.actionCrashReporterFragmentToHomeFragment() - findNavController().nav(R.id.crashReporterFragment, directions) - } } diff --git a/app/src/main/res/layout/fragment_crash_reporter.xml b/app/src/main/res/layout/fragment_crash_reporter.xml index dfff9f168..4069f554c 100644 --- a/app/src/main/res/layout/fragment_crash_reporter.xml +++ b/app/src/main/res/layout/fragment_crash_reporter.xml @@ -11,16 +11,16 @@ android:background="?above"> + android:id="@+id/crash_tab_image" + android:layout_width="0dp" + android:layout_height="120dp" + android:layout_marginTop="40dp" + android:src="@drawable/fenix_error_1" + android:importantForAccessibility="no" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintWidth_percent="0.8" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" />