Skip to content

Commit

Permalink
Improvements to scoped storage
Browse files Browse the repository at this point in the history
This patch updates scoped storage, making the following changes:
1. only force copying on Android 11 (sdk 30) and above. Before, this was
   also enabled for Android 10 (sdk 29).
2. disable the advanced settings move option to copy to /sdcard on
   Android 30 and above (since it doesn't make sense anymore).
3. warn people on Android 29 when they try to explicitly use /sdcard
   that data might not remain accessible on future Android versions.
4. show warning before asking for external sdcard permissions if
   required.

Fixes #1478.
  • Loading branch information
ahmedre committed Nov 6, 2020
1 parent 7740503 commit 43f1b46
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ class QuranDataActivity : Activity(), SimpleDownloadListener, OnRequestPermissio
runListView()
}
}
} else if (needsPermission && Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
// we need permission (i.e. are writing to the sdcard) on Android 10 (Q) and above
} else if (needsPermission && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
// we need permission (i.e. are writing to the sdcard) on Android 11 and above
// we should migrate because when we are required to target Android 11 next year
// in sha' Allah, we may lose legacy permissions.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
Expand All @@ -14,6 +15,7 @@
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import com.quran.labs.androidquran.BuildConfig;
import com.quran.labs.androidquran.QuranAdvancedPreferenceActivity;
import com.quran.labs.androidquran.QuranApplication;
Expand Down Expand Up @@ -270,15 +272,7 @@ private void loadStorageOptions(Context context) {
String current = settings.getAppCustomLocation();
if (appSize < destStorage.getFreeSpace()) {
if (current == null || !current.equals(newLocation)) {
if (destStorage.doesRequirePermission()) {
if (!PermissionUtil.haveWriteExternalStoragePermission(context1)) {
requestExternalStoragePermission(newLocation);
return false;
}

// we have the permission, so fall through and handle the move
}
handleMove(newLocation);
handleMove(newLocation, destStorage);
}
} else {
ToastCompat.makeText(context1,
Expand All @@ -305,36 +299,76 @@ private void requestExternalStoragePermission(String newLocation) {
}


private void handleMove(String newLocation) {
private void handleMove(String newLocation, StorageUtils.Storage storageLocation) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ||
newLocation.equals(internalSdcardLocation)) {
moveFiles(newLocation);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// on Android Q (not really "above" since we don't show the option above),
// warn if the person tries to use the /sdcard path.
showScopedStorageConfirmation(newLocation, storageLocation);
} else {
// otherwise just copy
moveFiles(newLocation, storageLocation);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// don't warn for using Android app directories on Q and above
moveFiles(newLocation, storageLocation);
} else {
showKitKatConfirmation(newLocation);
// but on older versions, warn
showKitKatConfirmation(newLocation, storageLocation);
}
}

private void showKitKatConfirmation(final String newLocation) {
private void showScopedStorageConfirmation(final String newLocation,
final StorageUtils.Storage storageLocation) {
showConfirmation(newLocation, storageLocation, R.string.scoped_storage_message);
}

private void showKitKatConfirmation(final String newLocation,
final StorageUtils.Storage storageLocation) {
showConfirmation(newLocation, storageLocation, R.string.kitkat_external_message);
}

private void showConfirmation(final String newLocation,
final StorageUtils.Storage storageLocation,
@StringRes int message) {
final Context context = getActivity();
final AlertDialog.Builder b = new AlertDialog.Builder(context)
.setTitle(R.string.warning)
.setMessage(R.string.kitkat_external_message)
.setPositiveButton(R.string.dialog_ok, (currentDialog, which) -> {
moveFiles(newLocation);
currentDialog.dismiss();
QuranAdvancedSettingsFragment.this.dialog = null;
})
.setNegativeButton(R.string.cancel, (currentDialog, which) -> {
currentDialog.dismiss();
QuranAdvancedSettingsFragment.this.dialog = null;
});
dialog = b.create();
dialog.show();
if (context != null) {
final AlertDialog.Builder b = new AlertDialog.Builder(context)
.setTitle(R.string.warning)
.setMessage(message)
.setPositiveButton(R.string.dialog_ok, (currentDialog, which) -> {
moveFiles(newLocation, storageLocation);
currentDialog.dismiss();
QuranAdvancedSettingsFragment.this.dialog = null;
})
.setNegativeButton(R.string.cancel, (currentDialog, which) -> {
currentDialog.dismiss();
QuranAdvancedSettingsFragment.this.dialog = null;
});
dialog = b.create();
dialog.show();
}
}

private void moveFiles(String newLocation, StorageUtils.Storage storageLocation) {
final Context context = getContext();
if (context != null) {
if (storageLocation.doesRequirePermission() &&
!PermissionUtil.haveWriteExternalStoragePermission(context)) {
requestExternalStoragePermission(newLocation);
} else {
moveFiles(newLocation);
}
}
}

public void moveFiles(String newLocation) {
moveFilesAsyncTask = new MoveFilesAsyncTask(getActivity(), newLocation, quranFileUtils);
moveFilesAsyncTask.execute();
final Context context = getContext();
if (context != null) {
moveFilesAsyncTask = new MoveFilesAsyncTask(context, newLocation, quranFileUtils);
moveFilesAsyncTask.execute();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,12 @@ a. not see any item (if there's only one entry returned by getExternalFilesDirs,
}

int number = 1;
result.add(new Storage(context.getString(typeId, number),
Environment.getExternalStorageDirectory().getAbsolutePath(),
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M));
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
// don't show the /sdcard option for people on Android 11
result.add(new Storage(context.getString(typeId, number),
Environment.getExternalStorageDirectory().getAbsolutePath(),
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M));
}
for (File mountPoint : mountPoints) {
result.add(new Storage(context.getString(typeId, number++),
mountPoint.getAbsolutePath()));
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@
<string name="about_quran_enc_summary">الترجمات لعدد من اللغات</string>
<string name="about_tanzil" translatable="false">تنزيل</string>
<string name="about_tanzil_summary">ترجمات لبعض اللغات</string>
<string name="please_wait">الرجاء الانتظار...</string>
<string name="please_wait">الرجاء الانتظار</string>
<string name="exported_data">صدرت البيانات إلى %1$s</string>
<string name="audio_manager_remove_audio_title">حذف الملف الصوتي؟</string>
<string name="audio_manager_remove_audio_msg">سيتم حذف الملف الصوتي ل%1$s. متأكد؟</string>
Expand All @@ -345,5 +345,9 @@
<string name="please_grant_permissions">رجاء امنح الإذن في الإعدادات</string>
<string name="about_noorhidayat" translatable="false">نور وهداية (Noorhidayat)</string>
<string name="kitkat_external_message">بسبب قيود الأندرويد، إذا اخترت تخزين ملفات قرآن على الذاكرة الخارجية ثم مسحت التطبيق أو بيانات قرآن أندرويد، ستحذف جميع صفحات المصحف والصوت ولابد من تحميلها مجددا. هل ترغب في استعمال الذاكرة الخارجية؟</string>
<string name="scoped_storage_message">بسبب القيود الجديدة في أندرويد 11، تخزين بيانات التطبيق في
مكان غير مجلد التطبيق الافتراضي قد يؤدي إلى عدم تمكن التطبيق من الوصول لملفاته في إصدارات أندرويد
القادمة، هل ترغب في نقل البيانات على أية حال؟
</string>

</resources>
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@
data on your external SD card and later uninstall or clear data for Quran Android, all Quran
Android pages and audio will be deleted and you will have to download them again. Are you
sure you want to use the external SD card?</string>
<string name="scoped_storage_message">Due to Android changes to increase user privacy, copying
files outside of the app directories might stop Quran from accessing its data in future versions
of Android. Are you sure you\'d like to use this path?</string>
<string name="please_grant_permissions">Please grant permission in application settings</string>
<!-- Preferences End -->

Expand Down

0 comments on commit 43f1b46

Please sign in to comment.