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:
commit
b6a18b0da5
|
@ -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) ->
|
||||
{
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -100,7 +100,7 @@ public interface SettingsActivityView
|
|||
void showLoading();
|
||||
|
||||
/**
|
||||
* Hide the loading the dialog
|
||||
* Hide the loading dialog
|
||||
*/
|
||||
void hideLoading();
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue