Merge pull request #10980 from JosJuice/android-no-dir-init-fail

Android: Force quit app if external storage isn't mounted
This commit is contained in:
JosJuice 2022-08-14 15:47:50 +02:00 committed by GitHub
commit b6a18b0da5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 53 additions and 130 deletions

View File

@ -63,7 +63,7 @@ public class AppLinkActivity extends FragmentActivity
private void initResources()
{
mAfterDirectoryInitializationRunner = new AfterDirectoryInitializationRunner();
mAfterDirectoryInitializationRunner.runWithLifecycle(this, true, () -> tryPlay(playAction));
mAfterDirectoryInitializationRunner.runWithLifecycle(this, () -> tryPlay(playAction));
GameFileCacheManager.isLoading().observe(this, (isLoading) ->
{

View File

@ -185,7 +185,7 @@ public final class EmulationActivity extends AppCompatActivity
private static void performLaunchChecks(FragmentActivity activity,
Runnable continueCallback)
{
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true, () ->
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, () ->
{
if (!FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_DEFAULT_ISO) ||
!FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_FS_PATH) ||

View File

@ -63,6 +63,8 @@ public final class SettingsActivityPresenter
private void loadSettingsUI()
{
mView.hideLoading();
if (mSettings.isEmpty())
{
if (!TextUtils.isEmpty(mGameId))
@ -86,18 +88,9 @@ public final class SettingsActivityPresenter
private void prepareDolphinDirectoriesIfNeeded()
{
if (DirectoryInitialization.areDolphinDirectoriesReady())
{
loadSettingsUI();
}
else
{
mView.showLoading();
mView.showLoading();
new AfterDirectoryInitializationRunner()
.setFinishedCallback(mView::hideLoading)
.runWithLifecycle(mActivity, true, this::loadSettingsUI);
}
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, this::loadSettingsUI);
}
public Settings getSettings()

View File

@ -100,7 +100,7 @@ public interface SettingsActivityView
void showLoading();
/**
* Hide the loading the dialog
* Hide the loading dialog
*/
void hideLoading();

View File

@ -128,7 +128,7 @@ public final class GameFileCacheManager
if (!loadInProgress.getValue())
{
loadInProgress.setValue(true);
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
() -> executor.execute(GameFileCacheManager::load));
}
}
@ -144,7 +144,7 @@ public final class GameFileCacheManager
if (!rescanInProgress.getValue())
{
rescanInProgress.setValue(true);
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
() -> executor.execute(GameFileCacheManager::rescan));
}
}

View File

@ -79,7 +79,7 @@ public final class MainActivity extends AppCompatActivity
if (!DirectoryInitialization.isWaitingForWriteAccess(this))
{
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}
}
@ -92,7 +92,7 @@ public final class MainActivity extends AppCompatActivity
{
DirectoryInitialization.start(this);
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}
mPresenter.onResume();
@ -268,7 +268,7 @@ public final class MainActivity extends AppCompatActivity
DirectoryInitialization.start(this);
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}
}

View File

@ -81,7 +81,7 @@ public final class MainPresenter
public void onFabClick()
{
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity,
mView::launchFileListActivity);
}
@ -99,7 +99,7 @@ public final class MainPresenter
return true;
case R.id.button_add_directory:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
mView::launchFileListActivity);
return true;
@ -112,22 +112,22 @@ public final class MainPresenter
return true;
case R.id.menu_online_system_update:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
this::launchOnlineUpdate);
return true;
case R.id.menu_install_wad:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
() -> mView.launchOpenFileActivity(REQUEST_WAD_FILE));
return true;
case R.id.menu_import_wii_save:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
() -> mView.launchOpenFileActivity(REQUEST_WII_SAVE_FILE));
return true;
case R.id.menu_import_nand_backup:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
() -> mView.launchOpenFileActivity(REQUEST_NAND_BIN_FILE));
return true;
}
@ -325,7 +325,7 @@ public final class MainPresenter
}
else
{
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, true, () ->
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, () ->
{
SystemMenuNotInstalledDialogFragment dialogFragment =
new SystemMenuNotInstalledDialogFragment();

View File

@ -2,43 +2,14 @@
package org.dolphinemu.dolphinemu.utils;
import android.content.Context;
import android.widget.Toast;
import androidx.core.app.ComponentActivity;
import androidx.lifecycle.Observer;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization.DirectoryInitializationState;
public class AfterDirectoryInitializationRunner
{
private Observer<DirectoryInitializationState> mObserver;
private Runnable mUnregisterCallback;
/**
* Sets a Runnable which will be called when:
*
* 1. The Runnable supplied to {@link #runWithLifecycle}/{@link #runWithoutLifecycle}
* is just about to run, or
* 2. {@link #runWithLifecycle}/{@link #runWithoutLifecycle} was called with
* abortOnFailure == true and there is a failure
*
* @return this
*/
public AfterDirectoryInitializationRunner setFinishedCallback(Runnable runnable)
{
mUnregisterCallback = runnable;
return this;
}
private void runFinishedCallback()
{
if (mUnregisterCallback != null)
{
mUnregisterCallback.run();
}
}
/**
* Executes a Runnable after directory initialization has finished.
@ -59,23 +30,15 @@ public class AfterDirectoryInitializationRunner
* If the passed-in activity gets destroyed before this operation finishes,
* it will be automatically canceled.
*/
public void runWithLifecycle(ComponentActivity activity, boolean abortOnFailure,
Runnable runnable)
public void runWithLifecycle(ComponentActivity activity, Runnable runnable)
{
if (DirectoryInitialization.areDolphinDirectoriesReady())
{
runFinishedCallback();
runnable.run();
}
else if (abortOnFailure &&
showErrorMessage(activity,
DirectoryInitialization.getDolphinDirectoriesState().getValue()))
{
runFinishedCallback();
}
else
{
mObserver = createObserver(activity, abortOnFailure, runnable);
mObserver = createObserver(runnable);
DirectoryInitialization.getDolphinDirectoriesState().observe(activity, mObserver);
}
}
@ -96,46 +59,26 @@ public class AfterDirectoryInitializationRunner
* the attempt to run the Runnable will never be aborted, and the Runnable
* is guaranteed to run if directory initialization ever finishes.
*/
public void runWithoutLifecycle(Context context, boolean abortOnFailure, Runnable runnable)
public void runWithoutLifecycle(Runnable runnable)
{
if (DirectoryInitialization.areDolphinDirectoriesReady())
{
runFinishedCallback();
runnable.run();
}
else if (abortOnFailure &&
showErrorMessage(context,
DirectoryInitialization.getDolphinDirectoriesState().getValue()))
{
runFinishedCallback();
}
else
{
mObserver = createObserver(context, abortOnFailure, runnable);
mObserver = createObserver(runnable);
DirectoryInitialization.getDolphinDirectoriesState().observeForever(mObserver);
}
}
private Observer<DirectoryInitializationState> createObserver(Context context,
boolean abortOnFailure, Runnable runnable)
private Observer<DirectoryInitializationState> createObserver(Runnable runnable)
{
return (state) ->
{
boolean done = state == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
if (!done && abortOnFailure)
{
done = showErrorMessage(context, state);
}
if (done)
{
cancel();
runFinishedCallback();
}
if (state == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
cancel();
runnable.run();
}
};
@ -145,17 +88,4 @@ public class AfterDirectoryInitializationRunner
{
DirectoryInitialization.getDolphinDirectoriesState().removeObserver(mObserver);
}
private static boolean showErrorMessage(Context context, DirectoryInitializationState state)
{
switch (state)
{
case CANT_FIND_EXTERNAL_STORAGE:
Toast.makeText(context, R.string.external_storage_not_mounted, Toast.LENGTH_LONG).show();
return true;
default:
return false;
}
}
}

View File

@ -25,7 +25,7 @@ public class Analytics
public static void checkAnalyticsInit(Context context)
{
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false, () ->
new AfterDirectoryInitializationRunner().runWithoutLifecycle(() ->
{
if (!BooleanSetting.MAIN_ANALYTICS_PERMISSION_ASKED.getBooleanGlobal())
{

View File

@ -10,6 +10,7 @@ import android.content.SharedPreferences;
import android.os.Build;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -17,6 +18,7 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import java.io.File;
@ -43,13 +45,12 @@ public final class DirectoryInitialization
{
NOT_YET_INITIALIZED,
INITIALIZING,
DOLPHIN_DIRECTORIES_INITIALIZED,
CANT_FIND_EXTERNAL_STORAGE
DOLPHIN_DIRECTORIES_INITIALIZED
}
public static void start(Context context)
{
if (directoryState.getValue() == DirectoryInitializationState.INITIALIZING)
if (directoryState.getValue() != DirectoryInitializationState.NOT_YET_INITIALIZED)
return;
directoryState.setValue(DirectoryInitializationState.INITIALIZING);
@ -60,31 +61,30 @@ public final class DirectoryInitialization
private static void init(Context context)
{
if (directoryState.getValue() != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
if (directoryState.getValue() == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
return;
if (!setDolphinUserDirectory(context))
{
if (setDolphinUserDirectory(context))
{
initializeInternalStorage(context);
boolean wiimoteIniWritten = initializeExternalStorage(context);
NativeLibrary.Initialize();
NativeLibrary.ReportStartToAnalytics();
areDirectoriesAvailable = true;
if (wiimoteIniWritten)
{
// This has to be done after calling NativeLibrary.Initialize(),
// as it relies on the config system
EmulationActivity.updateWiimoteNewIniPreferences(context);
}
directoryState.postValue(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED);
}
else
{
directoryState.postValue(DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE);
}
Toast.makeText(context, R.string.external_storage_not_mounted, Toast.LENGTH_LONG).show();
System.exit(1);
}
initializeInternalStorage(context);
boolean wiimoteIniWritten = initializeExternalStorage(context);
NativeLibrary.Initialize();
NativeLibrary.ReportStartToAnalytics();
areDirectoriesAvailable = true;
if (wiimoteIniWritten)
{
// This has to be done after calling NativeLibrary.Initialize(),
// as it relies on the config system
EmulationActivity.updateWiimoteNewIniPreferences(context);
}
directoryState.postValue(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED);
}
@Nullable

View File

@ -112,7 +112,7 @@ public final class StartupHandler
final Instant lastOpened = Instant.ofEpochMilli(lastOpen);
if (current.isAfter(lastOpened.plus(6, ChronoUnit.HOURS)))
{
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
NativeLibrary::ReportStartToAnalytics);
}
}