From 161f8c3fad9df97ae4f97b7f45125e5e4c9608a7 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 9 Nov 2020 23:15:35 +0100 Subject: [PATCH] Android: Warn when path in config is unavailable Content URIs stop working if Dolphin loses permissions, which happens for instance when reinstalling Dolphin. --- .../activities/EmulationActivity.java | 30 +++++++++++++++++-- .../ui/viewholder/FilePickerViewHolder.java | 19 ++++++++++-- .../dolphinemu/utils/ContentHandler.java | 18 +++++++++++ .../dolphinemu/utils/FileBrowserHelper.java | 12 ++++++++ .../drawable/invalid_setting_background.xml | 9 ++++++ .../app/src/main/res/values/colors.xml | 2 ++ .../app/src/main/res/values/strings.xml | 2 ++ 7 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 Source/Android/app/src/main/res/drawable/invalid_setting_background.xml diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index d8d1329259..2c142f05cb 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -36,6 +36,7 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; +import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; @@ -170,13 +171,38 @@ public final class EmulationActivity extends AppCompatActivity if (sIgnoreLaunchRequests) return; + new AfterDirectoryInitializationRunner().run(activity, true, () -> + { + if (FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_DEFAULT_ISO) && + FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_FS_PATH) && + FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_DUMP_PATH) && + FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_LOAD_PATH) && + FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_RESOURCEPACK_PATH) && + FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_SD_PATH)) + { + launchWithoutChecks(activity, filePaths); + } + else + { + AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.DolphinDialogBase); + builder.setMessage(R.string.unavailable_paths); + builder.setPositiveButton(R.string.yes, (dialogInterface, i) -> + SettingsActivity.launch(activity, MenuTag.CONFIG_PATHS)); + builder.setNeutralButton(R.string.continue_anyway, (dialogInterface, i) -> + launchWithoutChecks(activity, filePaths)); + builder.show(); + } + }); + } + + private static void launchWithoutChecks(FragmentActivity activity, String[] filePaths) + { sIgnoreLaunchRequests = true; Intent launcher = new Intent(activity, EmulationActivity.class); launcher.putExtra(EXTRA_SELECTED_GAMES, filePaths); - new AfterDirectoryInitializationRunner().run(activity, true, - () -> activity.startActivity(launcher)); + activity.startActivity(launcher); } public static void stopIgnoringLaunchRequests() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java index 1bc8000635..0be8c93188 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java @@ -1,5 +1,6 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.view.View; import android.widget.TextView; @@ -10,6 +11,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; +import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; public final class FilePickerViewHolder extends SettingViewHolder { @@ -19,6 +21,8 @@ public final class FilePickerViewHolder extends SettingViewHolder private TextView mTextSettingName; private TextView mTextSettingDescription; + private Drawable mDefaultBackground; + public FilePickerViewHolder(View itemView, SettingsAdapter adapter) { super(itemView, adapter); @@ -29,6 +33,8 @@ public final class FilePickerViewHolder extends SettingViewHolder { mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingDescription = root.findViewById(R.id.text_setting_description); + + mDefaultBackground = root.getBackground(); } @Override @@ -37,6 +43,17 @@ public final class FilePickerViewHolder extends SettingViewHolder mFilePicker = (FilePicker) item; mItem = item; + String path = mFilePicker.getSelectedValue(getAdapter().getSettings()); + + if (FileBrowserHelper.isPathEmptyOrValid(path)) + { + itemView.setBackground(mDefaultBackground); + } + else + { + itemView.setBackgroundResource(R.drawable.invalid_setting_background); + } + mTextSettingName.setText(item.getNameId()); if (item.getDescriptionId() > 0) @@ -45,8 +62,6 @@ public final class FilePickerViewHolder extends SettingViewHolder } else { - String path = mFilePicker.getSelectedValue(getAdapter().getSettings()); - if (TextUtils.isEmpty(path)) { String defaultPathRelative = mFilePicker.getDefaultPathRelativeToUserDirectory(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java index c2fa96999f..6ec418a1f9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ContentHandler.java @@ -52,6 +52,24 @@ public class ContentHandler } } + public static boolean exists(@NonNull String uri) + { + try + { + final String[] projection = new String[]{Document.COLUMN_MIME_TYPE, Document.COLUMN_SIZE}; + try (Cursor cursor = getContentResolver().query(Uri.parse(uri), projection, null, null, null)) + { + return cursor != null && cursor.getCount() > 0; + } + } + catch (SecurityException e) + { + Log.error("Tried to check if " + uri + " exists without permission"); + } + + return false; + } + @Nullable public static String getDisplayName(@NonNull Uri uri) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java index 1d0c982b65..79ec49deae 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java @@ -14,6 +14,7 @@ import com.nononsenseapps.filepicker.Utils; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.CustomFilePickerActivity; +import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import java.io.File; @@ -94,6 +95,16 @@ public final class FileBrowserHelper return null; } + public static boolean isPathEmptyOrValid(StringSetting path) + { + return isPathEmptyOrValid(path.getStringGlobal()); + } + + public static boolean isPathEmptyOrValid(String path) + { + return !path.startsWith("content://") || ContentHandler.exists(path); + } + public static void runAfterExtensionCheck(Context context, Uri uri, Set validExtensions, Runnable runnable) { @@ -132,6 +143,7 @@ public final class FileBrowserHelper .setMessage(message) .setPositiveButton(R.string.yes, (dialogInterface, i) -> runnable.run()) .setNegativeButton(R.string.no, null) + .setCancelable(false) .show(); } diff --git a/Source/Android/app/src/main/res/drawable/invalid_setting_background.xml b/Source/Android/app/src/main/res/drawable/invalid_setting_background.xml new file mode 100644 index 0000000000..ad58c2e30a --- /dev/null +++ b/Source/Android/app/src/main/res/drawable/invalid_setting_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Source/Android/app/src/main/res/values/colors.xml b/Source/Android/app/src/main/res/values/colors.xml index b62030758e..111c03802b 100644 --- a/Source/Android/app/src/main/res/values/colors.xml +++ b/Source/Android/app/src/main/res/values/colors.xml @@ -11,4 +11,6 @@ #444444 + #36ff0000 + diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 15557ca9d8..df0a151220 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -311,6 +311,7 @@ Clear Disabled Other + Continue Anyway Add Folder to Library @@ -431,6 +432,7 @@ It can efficiently compress both junk data and encrypted Wii data. The selected file does not appear to have a file name extension.\n\nContinue anyway? The selected file has the file name extension \"%1$s\", but \"%2$s\" was expected.\n\nContinue anyway? The selected file has the file name extension \"%1$s\", but one of these extensions was expected: %2$s\n\nContinue anyway? + Dolphin does not have permission to access one or more configured paths. Would you like to fix this before starting? Total Pitch