diff --git a/app/detekt_baseline.xml b/app/detekt_baseline.xml index 40e2c3c8a..2c43a15d6 100644 --- a/app/detekt_baseline.xml +++ b/app/detekt_baseline.xml @@ -11,7 +11,7 @@ MagicNumber:ShareFiles.kt$ShareFiles$24 MagicNumber:ZimManageViewModel.kt$ZimManageViewModel$5 MagicNumber:ZimManageViewModel.kt$ZimManageViewModel$500 - MagicNumber:ZimHostFragment.kt$ZimHostFragment$4 + NestedBlockDepth:LocalLibraryFragment.kt$LocalLibraryFragment$checkPermissions NestedBlockDepth:PeerGroupHandshake.kt$PeerGroupHandshake$readHandshakeAndExchangeMetaData NestedBlockDepth:ReceiverHandShake.kt$ReceiverHandShake$exchangeFileTransferMetadata PackageNaming:AvailableSpaceCalculator.kt$package org.kiwix.kiwixmobile.zim_manager.library_view diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt index 592471fc5..59790c3ee 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/LocalLibraryFragment.kt @@ -20,7 +20,9 @@ package org.kiwix.kiwixmobile.nav.destination.library import android.Manifest import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle +import android.os.Environment import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater @@ -62,6 +64,12 @@ import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.Re import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestSelect import org.kiwix.kiwixmobile.zim_manager.fileselect_view.FileSelectListState import javax.inject.Inject +import android.content.Intent +import android.net.Uri +import android.provider.Settings +import androidx.annotation.RequiresApi +import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower +import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE" @@ -69,6 +77,7 @@ class LocalLibraryFragment : BaseFragment() { @Inject lateinit var viewModelFactory: ViewModelProvider.Factory @Inject lateinit var sharedPreferenceUtil: SharedPreferenceUtil + @Inject lateinit var dialogShower: DialogShower private var actionMode: ActionMode? = null private val disposable = CompositeDisposable() @@ -202,7 +211,25 @@ class LocalLibraryFragment : BaseFragment() { REQUEST_STORAGE_PERMISSION ) } else { - requestFileSystemCheck() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Environment.isExternalStorageManager()) { + // We already have permission!! + requestFileSystemCheck() + } else { + if (sharedPreferenceUtil.manageExternalFilesPermissionDialog) { + // We should only ask for first time, If the users wants to revoke settings + // then they can directly toggle this feature from settings screen + sharedPreferenceUtil.manageExternalFilesPermissionDialog = false + // Show Dialog and Go to settings to give permission + dialogShower.show( + KiwixDialog.ManageExternalFilesPermissionDialog, + ::navigateToSettings + ) + } + } + } else { + requestFileSystemCheck() + } } } @@ -217,4 +244,13 @@ class LocalLibraryFragment : BaseFragment() { private fun navigateToLocalFileTransferFragment() { requireActivity().navigate(R.id.localFileTransferFragment) } + + @RequiresApi(Build.VERSION_CODES.R) + private fun navigateToSettings() { + val intent = Intent().apply { + action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION + data = Uri.fromParts("package", requireActivity().packageName, null) + } + startActivity(intent) + } } diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index da773d305..f9b3b51b1 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -8,6 +8,8 @@ + diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.java b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.java index badbf0f49..11d52e618 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.java +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CorePrefsFragment.java @@ -20,16 +20,23 @@ package org.kiwix.kiwixmobile.core.settings; import android.Manifest; import android.annotation.SuppressLint; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; +import android.provider.Settings; import android.view.LayoutInflater; import android.webkit.WebView; +import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import androidx.navigation.NavController; import androidx.preference.EditTextPreference; import androidx.preference.ListPreference; import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceFragmentCompat; import com.google.android.material.snackbar.Snackbar; import eu.mhutti1.utils.storage.StorageDevice; @@ -62,6 +69,9 @@ public abstract class CorePrefsFragment extends PreferenceFragmentCompat impleme public static final String PREF_CLEAR_ALL_HISTORY = "pref_clear_all_history"; public static final String PREF_CLEAR_ALL_NOTES = "pref_clear_all_notes"; public static final String PREF_CREDITS = "pref_credits"; + public static final String PREF_MANAGE_EXTERNAL_STORAGE_PERMISSION = + "pref_manage_external_storage"; + public static final String PREF_PERMISSION = "pref_permissions"; private static final int ZOOM_OFFSET = 2; private static final int ZOOM_SCALE = 25; private static final String INTERNAL_TEXT_ZOOM = "text_zoom"; @@ -87,6 +97,7 @@ public abstract class CorePrefsFragment extends PreferenceFragmentCompat impleme setStorage(); setUpSettings(); setupZoom(); + setMangeExternalStoragePermission(); new LanguageUtils(getActivity()).changeFont(getActivity().getLayoutInflater(), sharedPreferenceUtil); } @@ -174,6 +185,28 @@ public abstract class CorePrefsFragment extends PreferenceFragmentCompat impleme versionPref.setSummary(getVersionName() + " Build: " + getVersionCode()); } + private void setMangeExternalStoragePermission() { + Preference permissionPref = findPreference(PREF_MANAGE_EXTERNAL_STORAGE_PERMISSION); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { + showPermissionPreference(); + boolean externalStorageManager = Environment.isExternalStorageManager(); + if (externalStorageManager) { + permissionPref.setSummary(R.string.allowed); + } else { + permissionPref.setSummary(R.string.not_allowed); + } + permissionPref.setOnPreferenceClickListener( + preference -> { + navigateToSettings(); + return true; + }); + } + } + private void showPermissionPreference() { + PreferenceCategory preferenceCategory = findPreference(PREF_PERMISSION); + preferenceCategory.setVisible(true); + } + private int getVersionCode() { try { return getActivity().getPackageManager() @@ -282,4 +315,14 @@ public abstract class CorePrefsFragment extends PreferenceFragmentCompat impleme } return Unit.INSTANCE; } + + // TODO: 28/10/21 Refactor the code. We are using it twice. + @RequiresApi(Build.VERSION_CODES.R) + private void navigateToSettings() { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null); + intent.setData(uri); + startActivity(intent); + } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/SharedPreferenceUtil.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/SharedPreferenceUtil.kt index 8c7cc8ea9..19c4d0ac7 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/SharedPreferenceUtil.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/SharedPreferenceUtil.kt @@ -140,6 +140,13 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) { fun updateNightMode() = nightModes.offer(nightMode) + var manageExternalFilesPermissionDialog: Boolean + get() = sharedPreferences.getBoolean(PREF_MANAGE_EXTERNAL_FILES, true) + set(prefManageExternalFilesPermissionDialog) = + sharedPreferences.edit { + putBoolean(PREF_MANAGE_EXTERNAL_FILES, prefManageExternalFilesPermissionDialog) + } + var hostedBooks: Set get() = sharedPreferences.getStringSet(PREF_HOSTED_BOOKS, null)?.toHashSet() ?: HashSet() set(hostedBooks) { @@ -172,5 +179,6 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) { const val PREF_NIGHT_MODE = "pref_night_mode" private const val TEXT_ZOOM = "true_text_zoom" private const val DEFAULT_ZOOM = 100 + private const val PREF_MANAGE_EXTERNAL_FILES = "pref_manage_external_files" } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/dialog/KiwixDialog.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/dialog/KiwixDialog.kt index 53ce42151..7bb1139ac 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/dialog/KiwixDialog.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/dialog/KiwixDialog.kt @@ -84,6 +84,14 @@ sealed class KiwixDialog( cancelable = false ) + object ManageExternalFilesPermissionDialog : KiwixDialog( + R.string.all_files_permission_needed, + R.string.all_files_permission_needed_message, + R.string.yes, + R.string.no, + cancelable = false + ) + data class ShowHotspotDetails(override val args: List) : KiwixDialog( R.string.hotspot_turned_on, R.string.hotspot_details_message, diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index af11074bc..4a7c1289b 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -68,6 +68,7 @@ Clear history Clear recent searches and tabs history Notes + Permissions All History Cleared Clear bookmarks Clear All History? @@ -255,6 +256,7 @@ Status Clears all notes on all articles Clear all notes + Allow to read/write ZIM file\'s on SD card Change text size with 25\% increments. Pic Vid @@ -289,6 +291,10 @@ Close Drawer How to update content? To update content (a zim file) you need to download the full latest version of this very same content. You can do that via the download section. + All Files Permission Needed + In order to access all the zim files across device we need to have All Files Permission + Allowed + Not allowed @string/on @string/off diff --git a/core/src/main/res/xml/preferences.xml b/core/src/main/res/xml/preferences.xml index e8e0c52cb..081a15b34 100644 --- a/core/src/main/res/xml/preferences.xml +++ b/core/src/main/res/xml/preferences.xml @@ -95,6 +95,18 @@ android:title="@string/pref_clear_all_notes_title" app:iconSpaceReserved="false" /> + + + + +