Skip to content

Commit

Permalink
NF: Mark receivers are exported
Browse files Browse the repository at this point in the history
This ensure there is no change in behaviour.

I checked whether we could try to not export the download of decks,
but it does not works.
The app does not crash on api 24 on simulator.

There was a slight problem, with variables that could potentially be
null. To ensure the type checker agreed with the code, without using
`!!`, I had to rewrite some of the logic.

I also ensured that some of the code that was copy/pasted in various
activity now entirely belong to AnkiActivity.
  • Loading branch information
Arthur-Milchior committed Jul 10, 2024
1 parent 16de500 commit d90bdc8
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 154 deletions.
107 changes: 77 additions & 30 deletions AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,48 @@ package com.ichi2.anki

import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.*
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Color
import android.hardware.SensorManager
import android.net.Uri
import android.os.*
import android.view.*
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewGroup
import android.view.ViewParent
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.webkit.*
import android.webkit.CookieManager
import android.webkit.JsResult
import android.webkit.PermissionRequest
import android.webkit.RenderProcessGoneDetail
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebView.HitTestResult
import android.widget.*
import android.webkit.WebViewClient
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
Expand All @@ -54,9 +81,23 @@ import com.google.android.material.snackbar.Snackbar
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anki.CollectionManager.TR
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.cardviewer.*
import com.ichi2.anki.cardviewer.AndroidCardRenderContext
import com.ichi2.anki.cardviewer.AndroidCardRenderContext.Companion.createInstance
import com.ichi2.anki.cardviewer.CardMediaPlayer
import com.ichi2.anki.cardviewer.Gesture
import com.ichi2.anki.cardviewer.GestureProcessor
import com.ichi2.anki.cardviewer.JavascriptEvaluator
import com.ichi2.anki.cardviewer.MediaErrorHandler
import com.ichi2.anki.cardviewer.OnRenderProcessGoneDelegate
import com.ichi2.anki.cardviewer.RenderedCard
import com.ichi2.anki.cardviewer.SingleCardSide
import com.ichi2.anki.cardviewer.TTS
import com.ichi2.anki.cardviewer.TypeAnswer
import com.ichi2.anki.cardviewer.TypeAnswer.Companion.createInstance
import com.ichi2.anki.cardviewer.ViewerCommand
import com.ichi2.anki.cardviewer.ViewerRefresh
import com.ichi2.anki.cardviewer.handledGamepadKeyDown
import com.ichi2.anki.cardviewer.handledGamepadKeyUp
import com.ichi2.anki.dialogs.TtsVoicesDialogFragment
import com.ichi2.anki.dialogs.tags.TagsDialog
import com.ichi2.anki.dialogs.tags.TagsDialogFactory
Expand All @@ -68,11 +109,16 @@ import com.ichi2.anki.pages.AnkiServer
import com.ichi2.anki.pages.CongratsPage
import com.ichi2.anki.pages.PostRequestHandler
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.receiver.SdCardReceiver
import com.ichi2.anki.reviewer.*
import com.ichi2.anki.reviewer.AutomaticAnswer
import com.ichi2.anki.reviewer.AutomaticAnswer.AutomaticallyAnswered
import com.ichi2.anki.reviewer.AutomaticAnswerAction
import com.ichi2.anki.reviewer.CardSide
import com.ichi2.anki.reviewer.EaseButton
import com.ichi2.anki.reviewer.FullScreenMode
import com.ichi2.anki.reviewer.FullScreenMode.Companion.DEFAULT
import com.ichi2.anki.reviewer.FullScreenMode.Companion.fromPreference
import com.ichi2.anki.reviewer.MotionEventHandler
import com.ichi2.anki.reviewer.PreviousAnswerIndicator
import com.ichi2.anki.servicelayer.LanguageHintService.applyLanguageHint
import com.ichi2.anki.servicelayer.NoteService.isMarked
import com.ichi2.anki.services.migrationServiceWhileStartedOrNull
Expand All @@ -84,26 +130,45 @@ import com.ichi2.anki.utils.OnlyOnce.preventSimultaneousExecutions
import com.ichi2.annotations.NeedsTest
import com.ichi2.compat.CompatHelper.Companion.resolveActivityCompat
import com.ichi2.compat.ResolveInfoFlagsCompat
import com.ichi2.libanki.*
import com.ichi2.libanki.Card
import com.ichi2.libanki.CardId
import com.ichi2.libanki.ChangeManager
import com.ichi2.libanki.Collection
import com.ichi2.libanki.Consts
import com.ichi2.libanki.Consts.BUTTON_TYPE
import com.ichi2.libanki.DeckId
import com.ichi2.libanki.Decks
import com.ichi2.libanki.Sound.getAvTag
import com.ichi2.libanki.SoundOrVideoTag
import com.ichi2.libanki.TTSTag
import com.ichi2.libanki.Utils
import com.ichi2.libanki.note
import com.ichi2.libanki.renderOutput
import com.ichi2.libanki.setTagsFromStr
import com.ichi2.libanki.undoableOp
import com.ichi2.themes.Themes
import com.ichi2.themes.Themes.getResFromAttr
import com.ichi2.ui.FixedEditText
import com.ichi2.utils.*
import com.ichi2.utils.BlocksSchemaUpgrade
import com.ichi2.utils.ClipboardUtil.getText
import com.ichi2.utils.HandlerUtils.executeFunctionWithDelay
import com.ichi2.utils.HandlerUtils.newHandler
import com.ichi2.utils.HashUtil.hashSetInit
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.Stopwatch
import com.ichi2.utils.WebViewDebugging.initializeDebugging
import com.ichi2.utils.message
import com.ichi2.utils.negativeButton
import com.ichi2.utils.positiveButton
import com.ichi2.utils.show
import com.ichi2.utils.title
import com.squareup.seismic.ShakeDetector
import kotlinx.coroutines.Job
import kotlinx.coroutines.runBlocking
import timber.log.Timber
import java.io.*
import java.io.File
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.util.*
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReadWriteLock
import java.util.concurrent.locks.ReentrantReadWriteLock
Expand Down Expand Up @@ -743,24 +808,6 @@ abstract class AbstractFlashcardViewer :
return cardContent != null
}

/**
* Show/dismiss dialog when sd card is ejected/remounted (collection is saved by SdCardReceiver)
*/
private fun registerExternalStorageListener() {
if (unmountReceiver == null) {
unmountReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == SdCardReceiver.MEDIA_EJECT) {
finish()
}
}
}
val iFilter = IntentFilter()
iFilter.addAction(SdCardReceiver.MEDIA_EJECT)
registerReceiver(unmountReceiver, iFilter)
}
}

open fun undo(): Job {
return launchCatchingTask {
undoAndShowSnackbar(duration = Reviewer.ACTION_SNACKBAR_TIME)
Expand Down
58 changes: 55 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ package com.ichi2.anki
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.BitmapFactory
import android.graphics.Color
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.view.animation.Animation
import android.widget.ProgressBar
import androidx.activity.result.ActivityResultLauncher
Expand All @@ -27,7 +34,9 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.ThemeUtils
import androidx.appcompat.widget.Toolbar
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent.*
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_DARK
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_LIGHT
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_SYSTEM
import androidx.core.app.NotificationCompat
import androidx.core.app.PendingIntentCompat
import androidx.fragment.app.DialogFragment
Expand All @@ -36,7 +45,8 @@ import androidx.fragment.app.FragmentManager
import com.google.android.material.color.MaterialColors
import com.ichi2.anim.ActivityTransitionAnimation
import com.ichi2.anim.ActivityTransitionAnimation.Direction
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
import com.ichi2.anim.ActivityTransitionAnimation.Direction.DEFAULT
import com.ichi2.anim.ActivityTransitionAnimation.Direction.NONE
import com.ichi2.anki.analytics.UsageAnalytics
import com.ichi2.anki.dialogs.AsyncDialogFragment
import com.ichi2.anki.dialogs.DialogHandler
Expand All @@ -45,9 +55,11 @@ import com.ichi2.anki.dialogs.SimpleMessageDialog.SimpleMessageDialogListener
import com.ichi2.anki.preferences.Preferences
import com.ichi2.anki.preferences.Preferences.Companion.MINIMUM_CARDS_DUE_FOR_NOTIFICATION
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.receiver.SdCardReceiver
import com.ichi2.anki.snackbar.showSnackbar
import com.ichi2.anki.workarounds.AppLoadedFromBackupWorkaround.showedActivityFailedScreen
import com.ichi2.async.CollectionLoader
import com.ichi2.compat.CompatHelper
import com.ichi2.compat.customtabs.CustomTabActivityHelper
import com.ichi2.compat.customtabs.CustomTabsFallback
import com.ichi2.compat.customtabs.CustomTabsHelper
Expand All @@ -62,6 +74,11 @@ import androidx.browser.customtabs.CustomTabsIntent.Builder as CustomTabsIntentB
@KotlinCleanup("set activityName")
open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener {

/**
* Broadcast that informs us when the sd card is about to be unmounted
*/
private var unmountReceiver: BroadcastReceiver? = null

/** The name of the parent class (example: 'Reviewer') */
private val activityName: String
val dialogHandler = DialogHandler(this)
Expand Down Expand Up @@ -106,6 +123,15 @@ open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener {
customTabActivityHelper.unbindCustomTabsService(this)
}

override fun onDestroy() {
super.onDestroy()
val unmountReceiver = this.unmountReceiver
this.unmountReceiver = null
if (unmountReceiver != null) {
unregisterReceiver(unmountReceiver)
}
}

override fun onResume() {
super.onResume()
UsageAnalytics.sendAnalyticsScreenView(this)
Expand Down Expand Up @@ -135,6 +161,32 @@ open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener {
hideProgressBar()
}

/**
* Show/dismiss dialog when sd card is ejected/remounted (collection is saved by SdCardReceiver)
*/
protected open fun registerExternalStorageListener() {
if (unmountReceiver != null) {
// Receiver already registered
return
}
val unmountReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == SdCardReceiver.MEDIA_EJECT) {
onSdCardNotMounted()
}
}
}
val iFilter = IntentFilter()
iFilter.addAction(SdCardReceiver.MEDIA_EJECT)
CompatHelper.compat.registerExportedReceiver(this, unmountReceiver, iFilter)
this.unmountReceiver = unmountReceiver
}

protected fun onSdCardNotMounted() {
showThemedToast(this, resources.getString(R.string.sd_card_not_mounted), false)
finish()
}

/** Legacy code should migrate away from this, and use withCol {} instead.
* */
val getColUnsafe: Collection
Expand Down
Loading

0 comments on commit d90bdc8

Please sign in to comment.