diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml index 6185173afd9d..91b2a7aa8590 100644 --- a/AnkiDroid/src/main/AndroidManifest.xml +++ b/AnkiDroid/src/main/AndroidManifest.xml @@ -119,7 +119,7 @@ diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt b/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt index 1e3dac0034b6..73aa43914871 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt @@ -19,7 +19,10 @@ package com.ichi2.anki import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.os.Message import androidx.annotation.CheckResult import androidx.annotation.VisibleForTesting @@ -54,6 +57,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import timber.log.Timber import java.io.File +import java.time.Duration +import java.time.Instant import kotlin.math.max import kotlin.math.min @@ -67,54 +72,81 @@ import kotlin.math.min class IntentHandler : AbstractIntentHandler() { override fun onCreate(savedInstanceState: Bundle?) { // Note: This is our entry point from the launcher with intent: android.intent.action.MAIN - super.onCreate(savedInstanceState) - val intent = intent - Timber.v(intent.toString()) - val reloadIntent = Intent(this, DeckPicker::class.java) - reloadIntent.setDataAndType(getIntent().data, getIntent().type) - val action = intent.action - // #6157 - We want to block actions that need permissions we don't have, but not the default case - // as this requires nothing - val runIfStoragePermissions = { runnable: () -> Unit -> performActionIfStorageAccessible(reloadIntent, action) { runnable() } } - val launchType = getLaunchType(intent) - // TODO block the UI with some kind of ProgressDialog instead of cancelling the sync work - if (requiresCollectionAccess(launchType)) { - // # 18899 - if (WorkManager.isInitialized()) { - SyncWorker.cancel(this) - } - } - when (launchType) { - LaunchType.FILE_IMPORT -> - runIfStoragePermissions { - handleFileImport(fileIntent, reloadIntent, action) - finish() - } - LaunchType.TEXT_IMPORT -> - runIfStoragePermissions { - onSelectedCsvForImport(fileIntent) - finish() + + val handleScreen = { delay: Long -> + Handler(Looper.getMainLooper()).postDelayed({ + val intent = intent + Timber.v(intent.toString()) + val reloadIntent = Intent(this, DeckPicker::class.java) + reloadIntent.setDataAndType(getIntent().data, getIntent().type) + val action = intent.action + // #6157 - We want to block actions that need permissions we don't have, but not the default case + // as this requires nothing + val runIfStoragePermissions = { runnable: () -> Unit -> + performActionIfStorageAccessible(reloadIntent, action) { runnable() } } - LaunchType.IMAGE_IMPORT -> - runIfStoragePermissions { - handleImageImport(intent) - finish() + val launchType = getLaunchType(intent) + // TODO block the UI with some kind of ProgressDialog instead of cancelling the sync work + if (requiresCollectionAccess(launchType)) { + // # 18899 + if (WorkManager.isInitialized()) { + SyncWorker.cancel(this) + } } - LaunchType.SHARED_TEXT -> - runIfStoragePermissions { - handleSharedText(intent) - finish() + when (launchType) { + LaunchType.FILE_IMPORT -> + runIfStoragePermissions { + handleFileImport(fileIntent, reloadIntent, action) + finish() + } + LaunchType.TEXT_IMPORT -> + runIfStoragePermissions { + onSelectedCsvForImport(fileIntent) + finish() + } + LaunchType.IMAGE_IMPORT -> + runIfStoragePermissions { + handleImageImport(intent) + finish() + } + LaunchType.SHARED_TEXT -> + runIfStoragePermissions { + handleSharedText(intent) + finish() + } + LaunchType.SYNC -> runIfStoragePermissions { handleSyncIntent(reloadIntent, action) } + LaunchType.REVIEW -> runIfStoragePermissions { handleReviewIntent(reloadIntent, intent) } + LaunchType.DEFAULT_START_APP_IF_NEW -> { + Timber.d("onCreate() performing default action") + launchDeckPickerIfNoOtherTasks(reloadIntent) + } + LaunchType.COPY_DEBUG_INFO -> { + copyDebugInfoToClipboard(intent) + finish() + } } - LaunchType.SYNC -> runIfStoragePermissions { handleSyncIntent(reloadIntent, action) } - LaunchType.REVIEW -> runIfStoragePermissions { handleReviewIntent(reloadIntent, intent) } - LaunchType.DEFAULT_START_APP_IF_NEW -> { - Timber.d("onCreate() performing default action") - launchDeckPickerIfNoOtherTasks(reloadIntent) - } - LaunchType.COPY_DEBUG_INFO -> { - copyDebugInfoToClipboard(intent) - finish() + }, delay) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + splashScreen.setOnExitAnimationListener { splashScreenView -> + val animationDuration = splashScreenView.iconAnimationDuration + val animationStart = splashScreenView.iconAnimationStart + + Timber.v("duration: ${animationDuration?.toMillis()} start: $animationStart") + val remainingDuration = + if (animationDuration != null && animationStart != null) { + (animationDuration - Duration.between(animationStart, Instant.now())).toMillis().coerceAtLeast(0L) + } else { + 0L + } + Timber.v("remainDuration: $remainingDuration") + handleScreen(remainingDuration) } + super.onCreate(savedInstanceState) + } else { + super.onCreate(savedInstanceState) + handleScreen(0L) // No delay for older Android versions } } diff --git a/AnkiDroid/src/main/res/drawable/launch_screen.xml b/AnkiDroid/src/main/res/drawable/launch_screen.xml index 1857646f9a4a..eb40660977a0 100644 --- a/AnkiDroid/src/main/res/drawable/launch_screen.xml +++ b/AnkiDroid/src/main/res/drawable/launch_screen.xml @@ -2,14 +2,15 @@ - - - - - - + + diff --git a/AnkiDroid/src/main/res/drawable/splash_branding.xml b/AnkiDroid/src/main/res/drawable/splash_branding.xml new file mode 100644 index 000000000000..1a6a8dcdfd3c --- /dev/null +++ b/AnkiDroid/src/main/res/drawable/splash_branding.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/AnkiDroid/src/main/res/drawable/splash_icon.xml b/AnkiDroid/src/main/res/drawable/splash_icon.xml new file mode 100644 index 000000000000..a5beeb3a4753 --- /dev/null +++ b/AnkiDroid/src/main/res/drawable/splash_icon.xml @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AnkiDroid/src/main/res/values-v35/theme_dark.xml b/AnkiDroid/src/main/res/values-v35/theme_dark.xml index 9f30b60d7f88..1f672e073e3b 100644 --- a/AnkiDroid/src/main/res/values-v35/theme_dark.xml +++ b/AnkiDroid/src/main/res/values-v35/theme_dark.xml @@ -17,6 +17,10 @@