diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt index 0de9db757c..e6f93aa67f 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt @@ -14,7 +14,6 @@ import android.media.AudioManager import android.net.Uri import android.os.Build import android.os.Bundle -import android.os.Process import android.view.* import android.view.animation.Animation import android.widget.ProgressBar @@ -45,6 +44,7 @@ import com.ichi2.anki.dialogs.DialogHandler import com.ichi2.anki.dialogs.SimpleMessageDialog import com.ichi2.anki.dialogs.SimpleMessageDialog.SimpleMessageDialogListener import com.ichi2.anki.snackbar.showSnackbar +import com.ichi2.anki.workarounds.AppLoadedFromBackupWorkaround.showedActivityFailedScreen import com.ichi2.async.CollectionLoader import com.ichi2.compat.CompatHelper.Companion.compat import com.ichi2.compat.customtabs.CustomTabActivityHelper @@ -667,45 +667,12 @@ open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener, Collec return supportActionBar!! } - protected fun showedActivityFailedScreen(savedInstanceState: Bundle?): Boolean { - if (AnkiDroidApp.isInitialized()) { - return false - } - - // #7630: Can be triggered with `adb shell bmgr restore com.ichi2.anki` after AnkiDroid settings are changed. - // Application.onCreate() is not called if: - // * The App was open - // * A restore took place - // * The app is reopened (until it exits: finish() does not do this - and removes it from the app list) - Timber.w("Activity started with no application instance") - showThemedToast( - this, - getString(R.string.ankidroid_cannot_open_after_backup_try_again), - false + protected fun showedActivityFailedScreen(savedInstanceState: Bundle?) = + showedActivityFailedScreen( + savedInstanceState = savedInstanceState, + activitySuperOnCreate = { state -> super.onCreate(state) } ) - // fixes: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. - // on Importer - Themes.setTheme(this) - // Avoids a SuperNotCalledException - super.onCreate(savedInstanceState) - finishActivityWithFade(this) - - // If we don't kill the process, the backup is not "done" and reopening the app show the same message. - Thread { - - // 3.5 seconds sleep, as the toast is killed on process death. - // Same as the default value of LENGTH_LONG - try { - Thread.sleep(3500) - } catch (e: InterruptedException) { - Timber.w(e) - } - Process.killProcess(Process.myPid()) - }.start() - return true - } - companion object { const val REQUEST_REVIEW = 901 const val DIALOG_FRAGMENT_TAG = "dialog" diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/workarounds/AppLoadedFromBackupWorkaround.kt b/AnkiDroid/src/main/java/com/ichi2/anki/workarounds/AppLoadedFromBackupWorkaround.kt new file mode 100644 index 0000000000..9aff0879f9 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/workarounds/AppLoadedFromBackupWorkaround.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 David Allison + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package com.ichi2.anki.workarounds + +import android.app.Activity +import android.os.Bundle +import android.os.Process +import com.ichi2.anki.AnkiActivity +import com.ichi2.anki.AnkiDroidApp +import com.ichi2.anki.R +import com.ichi2.anki.UIUtils +import com.ichi2.themes.Themes +import timber.log.Timber + +/** + * Handles an issue where the app is loaded via `bmgr`, which means [AnkiDroidApp.onCreate] is not called + */ +object AppLoadedFromBackupWorkaround { + /** + * @param savedInstanceState bundle provided to [Activity.onCreate] + * @param activitySuperOnCreate The [Activity.onCreate] to be called + * + * We have [activitySuperOnCreate] as Activity.onCreate is protected, so we can't easily call this from here. + * A lambda is better than reflection, although it adds another parameter + * + * @return true if [AnkiDroidApp] was not initialised properly, an 'activity failed' toast was + * displayed and the app will be killed. `false` if the app started normally + */ + fun Activity.showedActivityFailedScreen(savedInstanceState: Bundle?, activitySuperOnCreate: (Bundle?) -> Unit): Boolean { + if (AnkiDroidApp.isInitialized()) { + return false + } + + // #7630: Can be triggered with `adb shell bmgr restore com.ichi2.anki` after AnkiDroid settings are changed. + // Application.onCreate() is not called if: + // * The App was open + // * A restore took place + // * The app is reopened (until it exits: finish() does not do this - and removes it from the app list) + Timber.w("Activity started with no application instance") + UIUtils.showThemedToast( + this, + getString(R.string.ankidroid_cannot_open_after_backup_try_again), + false + ) + + // fixes: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. + // on Importer + Themes.setTheme(this) + // Avoids a SuperNotCalledException + activitySuperOnCreate(savedInstanceState) + AnkiActivity.finishActivityWithFade(this) + + // If we don't kill the process, the backup is not "done" and reopening the app show the same message. + Thread { + + // 3.5 seconds sleep, as the toast is killed on process death. + // Same as the default value of LENGTH_LONG + try { + Thread.sleep(3500) + } catch (e: InterruptedException) { + Timber.w(e) + } + Process.killProcess(Process.myPid()) + }.start() + return true + } +}