Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #10980 from JosJuice/android-no-dir-init-fail
Android: Force quit app if external storage isn't mounted
  • Loading branch information
JosJuice committed Aug 14, 2022
2 parents 92c6407 + 1646197 commit b6a18b0
Show file tree
Hide file tree
Showing 11 changed files with 50 additions and 127 deletions.
Expand Up @@ -63,7 +63,7 @@ protected void onCreate(Bundle savedInstanceState)
private void initResources()
{
mAfterDirectoryInitializationRunner = new AfterDirectoryInitializationRunner();
mAfterDirectoryInitializationRunner.runWithLifecycle(this, true, () -> tryPlay(playAction));
mAfterDirectoryInitializationRunner.runWithLifecycle(this, () -> tryPlay(playAction));

GameFileCacheManager.isLoading().observe(this, (isLoading) ->
{
Expand Down
Expand Up @@ -185,7 +185,7 @@ public static void launch(FragmentActivity activity, String filePath, boolean ri
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) ||
Expand Down
Expand Up @@ -63,6 +63,8 @@ public void onStart()

private void loadSettingsUI()
{
mView.hideLoading();

if (mSettings.isEmpty())
{
if (!TextUtils.isEmpty(mGameId))
Expand All @@ -86,18 +88,9 @@ private void loadSettingsUI()

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()
Expand Down
Expand Up @@ -100,7 +100,7 @@
void showLoading();

/**
* Hide the loading the dialog
* Hide the loading dialog
*/
void hideLoading();

Expand Down
Expand Up @@ -128,7 +128,7 @@ public static void startLoad(Context context)
if (!loadInProgress.getValue())
{
loadInProgress.setValue(true);
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
() -> executor.execute(GameFileCacheManager::load));
}
}
Expand All @@ -144,7 +144,7 @@ public static void startRescan(Context context)
if (!rescanInProgress.getValue())
{
rescanInProgress.setValue(true);
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
() -> executor.execute(GameFileCacheManager::rescan));
}
}
Expand Down
Expand Up @@ -79,7 +79,7 @@ protected void onCreate(Bundle savedInstanceState)
if (!DirectoryInitialization.isWaitingForWriteAccess(this))
{
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}
}

Expand All @@ -92,7 +92,7 @@ protected void onResume()
{
DirectoryInitialization.start(this);
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}

mPresenter.onResume();
Expand Down Expand Up @@ -268,7 +268,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis

DirectoryInitialization.start(this);
new AfterDirectoryInitializationRunner()
.runWithLifecycle(this, false, this::setPlatformTabsAndStartGameFileCacheService);
.runWithLifecycle(this, this::setPlatformTabsAndStartGameFileCacheService);
}
}

Expand Down
Expand Up @@ -81,7 +81,7 @@ public void onDestroy()

public void onFabClick()
{
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity,
mView::launchFileListActivity);
}

Expand All @@ -99,7 +99,7 @@ public boolean handleOptionSelection(int itemId, ComponentActivity activity)
return true;

case R.id.button_add_directory:
new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true,
new AfterDirectoryInitializationRunner().runWithLifecycle(activity,
mView::launchFileListActivity);
return true;

Expand All @@ -112,22 +112,22 @@ public boolean handleOptionSelection(int itemId, ComponentActivity activity)
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;
}
Expand Down Expand Up @@ -325,7 +325,7 @@ private void launchWiiSystemMenu()
}
else
{
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, true, () ->
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, () ->
{
SystemMenuNotInstalledDialogFragment dialogFragment =
new SystemMenuNotInstalledDialogFragment();
Expand Down
Expand Up @@ -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.
Expand All @@ -59,23 +30,15 @@ private void runFinishedCallback()
* 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);
}
}
Expand All @@ -96,46 +59,26 @@ else if (abortOnFailure &&
* 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();
}
};
Expand All @@ -145,17 +88,4 @@ public void cancel()
{
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;
}
}
}
Expand Up @@ -25,7 +25,7 @@

public static void checkAnalyticsInit(Context context)
{
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false, () ->
new AfterDirectoryInitializationRunner().runWithoutLifecycle(() ->
{
if (!BooleanSetting.MAIN_ANALYTICS_PERMISSION_ASKED.getBooleanGlobal())
{
Expand Down
Expand Up @@ -10,13 +10,15 @@
import android.os.Build;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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;
Expand All @@ -43,13 +45,12 @@
{
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);
Expand All @@ -60,31 +61,30 @@ public static void start(Context context)

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();
Toast.makeText(context, R.string.external_storage_not_mounted, Toast.LENGTH_LONG).show();
System.exit(1);
}

areDirectoriesAvailable = true;
initializeInternalStorage(context);
boolean wiimoteIniWritten = initializeExternalStorage(context);
NativeLibrary.Initialize();
NativeLibrary.ReportStartToAnalytics();

if (wiimoteIniWritten)
{
// This has to be done after calling NativeLibrary.Initialize(),
// as it relies on the config system
EmulationActivity.updateWiimoteNewIniPreferences(context);
}
areDirectoriesAvailable = true;

directoryState.postValue(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED);
}
else
{
directoryState.postValue(DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE);
}
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
Expand Down
Expand Up @@ -112,7 +112,7 @@ public static void checkSessionReset(Context context)
final Instant lastOpened = Instant.ofEpochMilli(lastOpen);
if (current.isAfter(lastOpened.plus(6, ChronoUnit.HOURS)))
{
new AfterDirectoryInitializationRunner().runWithoutLifecycle(context, false,
new AfterDirectoryInitializationRunner().runWithoutLifecycle(
NativeLibrary::ReportStartToAnalytics);
}
}
Expand Down

0 comments on commit b6a18b0

Please sign in to comment.