Skip to content

Commit 3789cef

Browse files
committed
feat: add scoped storage for full builds
1 parent 45267bf commit 3789cef

6 files changed

Lines changed: 60 additions & 4 deletions

File tree

AnkiDroid/src/main/java/com/ichi2/anki/InitialActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import com.ichi2.anki.exception.StorageAccessException
3535
import com.ichi2.anki.servicelayer.PreferenceUpgradeService
3636
import com.ichi2.anki.servicelayer.PreferenceUpgradeService.setPreferencesUpToDate
3737
import com.ichi2.anki.servicelayer.ScopedStorageService.isLegacyStorage
38+
import com.ichi2.anki.settings.Prefs
3839
import com.ichi2.anki.ui.windows.permissions.InternetPermissionFragment
3940
import com.ichi2.anki.ui.windows.permissions.NotificationsPermissionFragment
4041
import com.ichi2.anki.ui.windows.permissions.PermissionsFragment
@@ -257,6 +258,9 @@ internal fun selectAnkiDroidFolder(
257258
}
258259

259260
fun selectAnkiDroidFolder(context: Context): AnkiDroidFolder {
261+
if (Prefs.usePrivateStorage) {
262+
return AnkiDroidFolder.AppPrivateFolder
263+
}
260264
val canAccessLegacyStorage = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || Environment.isExternalStorageLegacy()
261265
val currentFolderIsAccessibleAndLegacy = canAccessLegacyStorage && isLegacyStorage(context, setCollectionPath = false) == true
262266

AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,18 @@ class IntentHandler : AbstractIntentHandler() {
349349
*
350350
* @throws SystemStorageException if `getExternalFilesDir` returns null
351351
*/
352+
353+
fun hasRequiredPermissions(context: Context): Boolean {
354+
if (Prefs.usePrivateStorage) return true
355+
return !ScopedStorageService.isLegacyStorage(context) || hasLegacyStorageAccessPermission(context) ||
356+
Permissions.isExternalStorageManagerCompat()
357+
}
358+
352359
fun grantedStoragePermissions(
353360
context: Context,
354361
showToast: Boolean,
355362
): Boolean {
356-
val granted =
357-
!ScopedStorageService.isLegacyStorage(context) ||
358-
hasLegacyStorageAccessPermission(context) ||
359-
Permissions.isExternalStorageManagerCompat()
363+
val granted = hasRequiredPermissions(context)
360364

361365
if (!granted && showToast) {
362366
showThemedToast(context, context.getString(R.string.intent_handler_failed_no_storage_permission), false)

AnkiDroid/src/main/java/com/ichi2/anki/settings/Prefs.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ open class PrefsRepository(
339339

340340
var internetPermissionRequested by booleanPref(R.string.internet_permission_requested_key, false)
341341

342+
var usePrivateStorage by booleanPref(R.string.use_private_storage_key, false)
343+
342344
// **************************************** Reviewer **************************************** //
343345

344346
val ignoreDisplayCutout by booleanPref(R.string.ignore_display_cutout_key, false)

AnkiDroid/src/main/java/com/ichi2/anki/ui/windows/permissions/PermissionsStartingAt30Fragment.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@ package com.ichi2.anki.ui.windows.permissions
1818
import android.os.Build
1919
import android.os.Bundle
2020
import android.view.LayoutInflater
21+
import android.view.View
2122
import android.view.ViewGroup
2223
import androidx.activity.result.contract.ActivityResultContracts
2324
import androidx.annotation.RequiresApi
25+
import androidx.core.content.edit
26+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
27+
import com.ichi2.anki.AnkiDroidApp
28+
import com.ichi2.anki.CollectionHelper
2429
import com.ichi2.anki.R
2530
import com.ichi2.anki.databinding.FragmentPermissionsStartingAt30Binding
31+
import com.ichi2.anki.settings.Prefs
2632
import com.ichi2.utils.Permissions
2733
import com.ichi2.utils.Permissions.canManageExternalStorage
34+
import java.io.File
2835

2936
/**
3037
* Permissions screen for requesting permissions at and above API 30,
@@ -43,6 +50,8 @@ class PermissionsStartingAt30Fragment : PermissionsFragment(R.layout.fragment_pe
4350
) {
4451
if (hasAllPermissions()) {
4552
requireActivity().finish()
53+
} else {
54+
showPrivateStorageWarningDialog()
4655
}
4756
}
4857

@@ -57,5 +66,29 @@ class PermissionsStartingAt30Fragment : PermissionsFragment(R.layout.fragment_pe
5766
.requestExternalStorageOnClick(accessAllFilesLauncher)
5867
internetPermission
5968
.initializeInternetPermissionItem()
69+
btnUsePrivateStorage.visibility = View.VISIBLE
70+
btnUsePrivateStorage.setOnClickListener {
71+
showPrivateStorageWarningDialog()
72+
}
6073
}.root
74+
75+
private fun showPrivateStorageWarningDialog() {
76+
MaterialAlertDialogBuilder(requireContext())
77+
.setTitle(R.string.private_storage_warning_title)
78+
.setMessage(R.string.private_storage_warning)
79+
.setPositiveButton(R.string.dialog_continue) { _, _ ->
80+
Prefs.usePrivateStorage = true
81+
82+
val externalFilesDir =
83+
requireContext().getExternalFilesDir(null) ?: requireContext().filesDir
84+
val privateDir = File(externalFilesDir, "AnkiDroid").apply { mkdirs() }
85+
86+
AnkiDroidApp.sharedPrefs().edit {
87+
putString(CollectionHelper.PREF_COLLECTION_PATH, privateDir.absolutePath)
88+
}
89+
90+
requireActivity().finish()
91+
}.setNegativeButton(R.string.dialog_cancel, null)
92+
.show()
93+
}
6194
}

AnkiDroid/src/main/res/layout/fragment_permissions_starting_at_30.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,13 @@
2626
app:permissionSummary="@string/permission_access_summary"
2727
app:permission="@string/manage_internet_permission"
2828
/>
29+
30+
<com.google.android.material.button.MaterialButton
31+
android:id="@+id/btn_use_private_storage"
32+
android:layout_width="match_parent"
33+
android:layout_height="wrap_content"
34+
android:layout_margin="16dp"
35+
android:text="@string/btn_skip_permission"
36+
android:visibility="gone"/>
37+
2938
</LinearLayout>

AnkiDroid/src/main/res/values/preferences.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,8 @@
269269

270270
<!-- Onboarding -->
271271
<string name="internet_permission_requested_key">internetPermissionRequested</string>
272+
<string name="use_private_storage_key">usePrivatestorage</string>
273+
<string name="btn_skip_permission">Skip</string>
274+
<string name="private_storage_warning_title"> Limited Storage access</string>
275+
<string name="private_storage_warning">Without this permission, Your Ankidroid collection will be stored in app\'s private storage and will be permanently deleted if you uninstall Ankidroid.</string>
272276
</resources>

0 commit comments

Comments
 (0)