diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index 1fded39aba..284a00684c 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -155,4 +155,3 @@ - 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 815b5b7396..3b7838a814 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 @@ -9,7 +9,6 @@ import android.content.SharedPreferences; import android.graphics.Rect; import android.os.Bundle; import android.preference.PreferenceManager; -import android.text.TextUtils; import android.util.SparseIntArray; import android.view.InputDevice; import android.view.KeyEvent; @@ -80,12 +79,14 @@ public final class EmulationActivity extends AppCompatActivity private boolean activityRecreated; private String[] mPaths; private boolean mRiivolution; + private boolean mLaunchSystemMenu; private boolean mIgnoreWarnings; private static boolean sUserPausedEmulation; private boolean mMenuToastShown; public static final String EXTRA_SELECTED_GAMES = "SelectedGames"; public static final String EXTRA_RIIVOLUTION = "Riivolution"; + public static final String EXTRA_SYSTEM_MENU = "SystemMenu"; public static final String EXTRA_IGNORE_WARNINGS = "IgnoreWarnings"; public static final String EXTRA_USER_PAUSED_EMULATION = "sUserPausedEmulation"; public static final String EXTRA_MENU_TOAST_SHOWN = "MenuToastShown"; @@ -171,11 +172,9 @@ public final class EmulationActivity extends AppCompatActivity launch(activity, new String[]{filePath}, riivolution); } - public static void launch(FragmentActivity activity, String[] filePaths, boolean riivolution) + private static void performLaunchChecks(FragmentActivity activity, + Runnable continueCallback) { - if (sIgnoreLaunchRequests) - return; - new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true, () -> { if (FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_DEFAULT_ISO) && @@ -185,7 +184,7 @@ public final class EmulationActivity extends AppCompatActivity FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_RESOURCEPACK_PATH) && FileBrowserHelper.isPathEmptyOrValid(StringSetting.MAIN_SD_PATH)) { - launchWithoutChecks(activity, filePaths, riivolution); + continueCallback.run(); } else { @@ -194,12 +193,44 @@ public final class EmulationActivity extends AppCompatActivity builder.setPositiveButton(R.string.yes, (dialogInterface, i) -> SettingsActivity.launch(activity, MenuTag.CONFIG_PATHS)); builder.setNeutralButton(R.string.continue_anyway, (dialogInterface, i) -> - launchWithoutChecks(activity, filePaths, riivolution)); + continueCallback.run()); builder.show(); } }); } + + public static void launchSystemMenu(FragmentActivity activity) + { + if (sIgnoreLaunchRequests) + return; + + performLaunchChecks(activity, () -> + { + launchSystemMenuWithoutChecks(activity); + }); + } + + public static void launch(FragmentActivity activity, String[] filePaths, boolean riivolution) + { + if (sIgnoreLaunchRequests) + return; + + performLaunchChecks(activity, () -> + { + launchWithoutChecks(activity, filePaths, riivolution); + }); + } + + private static void launchSystemMenuWithoutChecks(FragmentActivity activity) + { + sIgnoreLaunchRequests = true; + + Intent launcher = new Intent(activity, EmulationActivity.class); + launcher.putExtra(EmulationActivity.EXTRA_SYSTEM_MENU, true); + activity.startActivity(launcher); + } + private static void launchWithoutChecks(FragmentActivity activity, String[] filePaths, boolean riivolution) { @@ -256,6 +287,7 @@ public final class EmulationActivity extends AppCompatActivity Intent gameToEmulate = getIntent(); mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES); mRiivolution = gameToEmulate.getBooleanExtra(EXTRA_RIIVOLUTION, false); + mLaunchSystemMenu = gameToEmulate.getBooleanExtra(EXTRA_SYSTEM_MENU, false); mIgnoreWarnings = gameToEmulate.getBooleanExtra(EXTRA_IGNORE_WARNINGS, false); sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false); mMenuToastShown = false; @@ -288,7 +320,7 @@ public final class EmulationActivity extends AppCompatActivity .findFragmentById(R.id.frame_emulation_fragment); if (mEmulationFragment == null) { - mEmulationFragment = EmulationFragment.newInstance(mPaths, mRiivolution); + mEmulationFragment = EmulationFragment.newInstance(mPaths, mRiivolution, mLaunchSystemMenu); getSupportFragmentManager().beginTransaction() .add(R.id.frame_emulation_fragment, mEmulationFragment) .commit(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateProgressBarDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateProgressBarDialogFragment.java new file mode 100644 index 0000000000..7130b09f00 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateProgressBarDialogFragment.java @@ -0,0 +1,110 @@ +package org.dolphinemu.dolphinemu.features.sysupdate.ui; + +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.pm.ActivityInfo; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.lifecycle.ViewModelProvider; + +import org.dolphinemu.dolphinemu.R; + +public class OnlineUpdateProgressBarDialogFragment extends DialogFragment +{ + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) + { + // Store the current orientation to be restored later + final int orientation = getActivity().getRequestedOrientation(); + // Rotating the device while the update is running can result in a title failing to import. + getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + + SystemUpdateViewModel viewModel = + new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); + + ProgressDialog progressDialog = new ProgressDialog(requireContext()); + progressDialog.setTitle(getString(R.string.updating)); + // We need to set the message to something here, otherwise the text will not appear when we set it later. + progressDialog.setMessage(""); + progressDialog.setButton(Dialog.BUTTON_NEGATIVE, getString(R.string.cancel), (dialog, i) -> + { + }); + progressDialog.setOnShowListener((dialogInterface) -> + { + // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. + // Setting the OnClickListener again after the dialog is shown overrides this behavior. + progressDialog.getButton(Dialog.BUTTON_NEGATIVE).setOnClickListener((view) -> + { + viewModel.setCanceled(); + }); + }); + progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + + viewModel.getProgressData().observe(this, (@Nullable Integer progress) -> + { + progressDialog.setProgress(progress.intValue()); + }); + + viewModel.getTotalData().observe(this, (@Nullable Integer total) -> + { + if (total == 0) + { + return; + } + + progressDialog.setMax(total.intValue()); + }); + + viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> + { + progressDialog.setMessage(getString(R.string.updating_message, titleId)); + }); + + viewModel.getResultData().observe(this, (@Nullable Integer result) -> + { + if (result == -1) + { + // This is the default value, ignore + return; + } + + OnlineUpdateResultFragment progressBarFragment = new OnlineUpdateResultFragment(); + progressBarFragment.show(getParentFragmentManager(), "OnlineUpdateResultFragment"); + + getActivity().setRequestedOrientation(orientation); + + dismiss(); + }); + + if (savedInstanceState == null) + { + final String region; + int selectedItem = viewModel.getRegion(); + + switch (selectedItem) + { + case 0: + region = "EUR"; + break; + case 1: + region = "JPN"; + break; + case 2: + region = "KOR"; + break; + case 3: + region = "USA"; + break; + default: + region = ""; + break; + } + viewModel.startUpdate(region); + } + return progressDialog; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java new file mode 100644 index 0000000000..198008d288 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java @@ -0,0 +1,42 @@ +package org.dolphinemu.dolphinemu.features.sysupdate.ui; + +import android.app.Dialog; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.lifecycle.ViewModelProvider; + +import org.dolphinemu.dolphinemu.R; + +public class OnlineUpdateRegionSelectDialogFragment extends DialogFragment +{ + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) + { + String[] items = {getString(R.string.europe), getString( + R.string.japan), getString(R.string.korea), getString(R.string.united_states)}; + int checkedItem = -1; + + return new AlertDialog.Builder(requireContext(), R.style.DolphinDialogBase) + .setTitle(R.string.region_select_title) + .setSingleChoiceItems(items, checkedItem, (dialog, which) -> + { + SystemUpdateViewModel viewModel = + new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); + viewModel.setRegion(which); + + OnlineUpdateProgressBarDialogFragment progressBarFragment = + new OnlineUpdateProgressBarDialogFragment(); + progressBarFragment + .show(getParentFragmentManager(), "OnlineUpdateProgressBarDialogFragment"); + progressBarFragment.setCancelable(false); + + dismiss(); + }) + .create(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateResultFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateResultFragment.java new file mode 100644 index 0000000000..e1f7557944 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateResultFragment.java @@ -0,0 +1,105 @@ +package org.dolphinemu.dolphinemu.features.sysupdate.ui; + +import android.app.Dialog; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.lifecycle.ViewModelProvider; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.utils.WiiUtils; + +public class OnlineUpdateResultFragment extends DialogFragment +{ + private int mResult; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) + { + SystemUpdateViewModel viewModel = + new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); + if (savedInstanceState == null) + { + mResult = viewModel.getResultData().getValue().intValue(); + viewModel.clear(); + } + else + { + mResult = savedInstanceState.getInt("result"); + } + + String message; + switch (mResult) + { + case WiiUtils.UPDATE_RESULT_SUCCESS: + message = getString(R.string.update_success); + break; + case WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE: + message = getString(R.string.already_up_to_date); + break; + case WiiUtils.UPDATE_RESULT_REGION_MISMATCH: + message = getString(R.string.region_mismatch); + break; + case WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION: + message = getString(R.string.missing_update_partition); + break; + case WiiUtils.UPDATE_RESULT_DISC_READ_FAILED: + message = getString(R.string.disc_read_failed); + break; + case WiiUtils.UPDATE_RESULT_SERVER_FAILED: + message = getString(R.string.server_failed); + break; + case WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED: + message = getString(R.string.download_failed); + break; + case WiiUtils.UPDATE_RESULT_IMPORT_FAILED: + message = getString(R.string.import_failed); + break; + case WiiUtils.UPDATE_RESULT_CANCELLED: + message = getString(R.string.update_cancelled); + break; + default: + throw new IllegalStateException("Unexpected value: " + mResult); + } + + String title; + switch (mResult) + { + case WiiUtils.UPDATE_RESULT_SUCCESS: + case WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE: + title = getString(R.string.update_success_title); + break; + case WiiUtils.UPDATE_RESULT_REGION_MISMATCH: + case WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION: + case WiiUtils.UPDATE_RESULT_DISC_READ_FAILED: + case WiiUtils.UPDATE_RESULT_SERVER_FAILED: + case WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED: + case WiiUtils.UPDATE_RESULT_IMPORT_FAILED: + title = getString(R.string.update_failed_title); + break; + case WiiUtils.UPDATE_RESULT_CANCELLED: + title = getString(R.string.update_cancelled_title); + break; + default: + throw new IllegalStateException("Unexpected value: " + mResult); + } + + return new AlertDialog.Builder(requireContext(), R.style.DolphinDialogBase) + .setTitle(title) + .setMessage(message) + .setPositiveButton(R.string.ok, (dialog, which) -> + { + dismiss(); + }) + .create(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) + { + super.onSaveInstanceState(outState); + outState.putInt("result", mResult); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java new file mode 100644 index 0000000000..b70e7682b7 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java @@ -0,0 +1,34 @@ +package org.dolphinemu.dolphinemu.features.sysupdate.ui; + +import android.app.Dialog; +import android.os.Bundle; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import org.dolphinemu.dolphinemu.R; + +public class SystemMenuNotInstalledDialogFragment extends DialogFragment +{ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) + { + return new AlertDialog.Builder(requireContext(), R.style.DolphinDialogBase) + .setTitle(R.string.system_menu_not_installed_title) + .setMessage(R.string.system_menu_not_installed_message) + .setPositiveButton(R.string.yes, (dialog, which) -> + { + FragmentManager fragmentManager = getParentFragmentManager(); + OnlineUpdateRegionSelectDialogFragment dialogFragment = + new OnlineUpdateRegionSelectDialogFragment(); + dialogFragment.show(fragmentManager, "OnlineUpdateRegionSelectDialogFragment"); + dismiss(); + }) + .setNegativeButton(R.string.no, (dialog, which) -> + { + dismiss(); + }) + .create(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java new file mode 100644 index 0000000000..ced570f8c3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java @@ -0,0 +1,90 @@ +package org.dolphinemu.dolphinemu.features.sysupdate.ui; + +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import org.dolphinemu.dolphinemu.utils.WiiUtils; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class SystemUpdateViewModel extends ViewModel +{ + private static final ExecutorService executor = Executors.newFixedThreadPool(1); + + private final MutableLiveData mProgressData = new MutableLiveData<>(); + private final MutableLiveData mTotalData = new MutableLiveData<>(); + private final MutableLiveData mTitleIdData = new MutableLiveData<>(); + private final MutableLiveData mResultData = new MutableLiveData<>(); + + private boolean mCanceled = false; + private int mRegion; + + public SystemUpdateViewModel() + { + clear(); + } + + public void setRegion(int region) + { + mRegion = region; + } + + public int getRegion() + { + return mRegion; + } + + public MutableLiveData getProgressData() + { + return mProgressData; + } + + public MutableLiveData getTotalData() + { + return mTotalData; + } + + public MutableLiveData getTitleIdData() + { + return mTitleIdData; + } + + public MutableLiveData getResultData() + { + return mResultData; + } + + public void setCanceled() + { + mCanceled = true; + } + + public void startUpdate(String region) + { + mCanceled = false; + + executor.execute(() -> + { + int result = WiiUtils.doOnlineUpdate(region, ((processed, total, titleId) -> + { + mProgressData.postValue(processed); + mTotalData.postValue(total); + mTitleIdData.postValue(titleId); + + return !mCanceled; + })); + + mResultData.postValue(result); + }); + } + + public void clear() + { + mProgressData.setValue(0); + mTotalData.setValue(0); + mTitleIdData.setValue(0l); + mResultData.setValue(-1); + mCanceled = false; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 7f1e158830..01d6ab6719 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -6,7 +6,6 @@ import android.content.Context; import android.graphics.Rect; import android.os.Bundle; import android.view.LayoutInflater; -import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; @@ -30,6 +29,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C { private static final String KEY_GAMEPATHS = "gamepaths"; private static final String KEY_RIIVOLUTION = "riivolution"; + private static final String KEY_SYSTEM_MENU = "systemMenu"; private InputOverlay mInputOverlay; @@ -37,14 +37,17 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C private boolean mRiivolution; private boolean mRunWhenSurfaceIsValid; private boolean mLoadPreviousTemporaryState; + private boolean mLaunchSystemMenu; private EmulationActivity activity; - public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution) + public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution, + boolean systemMenu) { Bundle args = new Bundle(); args.putStringArray(KEY_GAMEPATHS, gamePaths); args.putBoolean(KEY_RIIVOLUTION, riivolution); + args.putBoolean(KEY_SYSTEM_MENU, systemMenu); EmulationFragment fragment = new EmulationFragment(); fragment.setArguments(args); @@ -77,6 +80,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mGamePaths = getArguments().getStringArray(KEY_GAMEPATHS); mRiivolution = getArguments().getBoolean(KEY_RIIVOLUTION); + mLaunchSystemMenu = getArguments().getBoolean(KEY_SYSTEM_MENU); } /** @@ -270,6 +274,11 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C Log.debug("[EmulationFragment] Starting emulation thread from previous state."); NativeLibrary.Run(mGamePaths, mRiivolution, getTemporaryStateFilePath(), true); } + if (mLaunchSystemMenu) + { + Log.debug("[EmulationFragment] Starting emulation thread for the Wii Menu."); + NativeLibrary.RunSystemMenu(); + } else { Log.debug("[EmulationFragment] Starting emulation thread."); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 2b9b8defda..711f7d36de 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -14,6 +14,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.lifecycle.ViewModelProvider; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.viewpager.widget.ViewPager; @@ -27,6 +28,9 @@ import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.OnlineUpdateProgressBarDialogFragment; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemMenuNotInstalledDialogFragment; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemUpdateViewModel; import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView; @@ -36,6 +40,7 @@ import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.PermissionsHandler; import org.dolphinemu.dolphinemu.utils.StartupHandler; +import org.dolphinemu.dolphinemu.utils.WiiUtils; /** * The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which @@ -142,6 +147,14 @@ public final class MainActivity extends AppCompatActivity { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_game_grid, menu); + + if (WiiUtils.isSystemMenuInstalled()) + { + menu.findItem(R.id.menu_load_wii_system_menu).setTitle( + getString(R.string.grid_menu_load_wii_system_menu_installed, + WiiUtils.getSystemMenuVersion())); + } + return true; } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 76f53ddd72..b95b35331f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -3,18 +3,23 @@ package org.dolphinemu.dolphinemu.ui.main; import android.content.ContentResolver; -import android.content.Context; import android.content.Intent; import android.net.Uri; import androidx.appcompat.app.AlertDialog; -import androidx.core.app.ComponentActivity; +import androidx.activity.ComponentActivity; +import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.OnlineUpdateProgressBarDialogFragment; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemMenuNotInstalledDialogFragment; +import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemUpdateViewModel; import org.dolphinemu.dolphinemu.model.GameFileCache; import org.dolphinemu.dolphinemu.services.GameFileCacheManager; import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner; @@ -40,10 +45,10 @@ public final class MainPresenter private static boolean sShouldRescanLibrary = true; private final MainView mView; - private final ComponentActivity mActivity; + private final FragmentActivity mActivity; private String mDirToAdd; - public MainPresenter(MainView view, ComponentActivity activity) + public MainPresenter(MainView view, FragmentActivity activity) { mView = view; mActivity = activity; @@ -94,6 +99,14 @@ public final class MainPresenter mView.launchOpenFileActivity(REQUEST_GAME_FILE); return true; + case R.id.menu_load_wii_system_menu: + launchWiiSystemMenu(); + return true; + + case R.id.menu_online_system_update: + launchOnlineUpdate(); + return true; + case R.id.menu_install_wad: new AfterDirectoryInitializationRunner().runWithLifecycle(activity, true, () -> mView.launchOpenFileActivity(REQUEST_WAD_FILE)); @@ -287,4 +300,43 @@ public final class MainPresenter { sShouldRescanLibrary = false; } + + private void launchOnlineUpdate() + { + if (WiiUtils.isSystemMenuInstalled()) + { + SystemUpdateViewModel viewModel = + new ViewModelProvider(mActivity).get(SystemUpdateViewModel.class); + viewModel.setRegion(-1); + OnlineUpdateProgressBarDialogFragment progressBarFragment = + new OnlineUpdateProgressBarDialogFragment(); + progressBarFragment + .show(mActivity.getSupportFragmentManager(), "OnlineUpdateProgressBarDialogFragment"); + progressBarFragment.setCancelable(false); + } + else + { + SystemMenuNotInstalledDialogFragment dialogFragment = + new SystemMenuNotInstalledDialogFragment(); + dialogFragment + .show(mActivity.getSupportFragmentManager(), "SystemMenuNotInstalledDialogFragment"); + } + } + + private void launchWiiSystemMenu() + { + WiiUtils.isSystemMenuInstalled(); + + if (WiiUtils.isSystemMenuInstalled()) + { + EmulationActivity.launchSystemMenu(mActivity); + } + else + { + SystemMenuNotInstalledDialogFragment dialogFragment = + new SystemMenuNotInstalledDialogFragment(); + dialogFragment + .show(mActivity.getSupportFragmentManager(), "SystemMenuNotInstalledDialogFragment"); + } + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 58f3bbafb7..77ad01ecf3 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -378,6 +378,10 @@ public final class TvMainActivity extends FragmentActivity R.drawable.ic_folder, R.string.grid_menu_install_wad)); + rowItems.add(new TvSettingsItem(R.id.menu_load_wii_system_menu, + R.drawable.ic_folder, + R.string.grid_menu_load_wii_system_menu)); + rowItems.add(new TvSettingsItem(R.id.menu_import_wii_save, R.drawable.ic_folder, R.string.grid_menu_import_wii_save)); @@ -386,6 +390,10 @@ public final class TvMainActivity extends FragmentActivity R.drawable.ic_folder, R.string.grid_menu_import_nand_backup)); + rowItems.add(new TvSettingsItem(R.id.menu_online_system_update, + R.drawable.ic_folder, + R.string.grid_menu_online_system_update)); + // Create a header for this row. HeaderItem header = new HeaderItem(R.string.settings, getString(R.string.settings)); diff --git a/Source/Android/app/src/main/res/menu/menu_game_grid.xml b/Source/Android/app/src/main/res/menu/menu_game_grid.xml index 4b7d09ad97..b0fb121779 100644 --- a/Source/Android/app/src/main/res/menu/menu_game_grid.xml +++ b/Source/Android/app/src/main/res/menu/menu_game_grid.xml @@ -25,6 +25,11 @@ android:title="@string/grid_menu_install_wad" app:showAsAction="never"/> + + + + + diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index b0931ac7ad..9c7001b2a5 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -182,6 +182,29 @@ Display messages over the emulation screen area. These messages include memory card writes, video backend and CPU information, and JIT cache clearing. Download Game Covers from GameTDB.com + + Please select a region + Europe + Japan + Korea + United States + + + Updating + Updating title %016x...\nThis can take a while. + The emulated Wii console has been updated. + The emulated Wii console is already up-to-date. + The game\'s region does not match your console\'s. To avoid issues with the system menu, it is not possible to update the emulated console using this disc. + The game disc does not contain any usable update information. + The game disc does not contain any usable update information. + "Could not download update information from Nintendo. Please check your Internet connection and try again. + Could not download update files from Nintendo. Please check your Internet connection and try again. + "Could not install an update to the Wii system memory. Please refer to logs for more information. + The update has been cancelled. It is strongly recommended to finish it in order to avoid inconsistent system software versions. + Update completed + Update failed + Update cancelled + Audio DSP Emulation Engine @@ -391,6 +414,9 @@ Install WAD Import Wii Save Import BootMii NAND Backup + Perform Online System Update + Load Wii System Menu + Load Wii System Menu (%s) Importing... Do not close the app! Successfully installed this title to the NAND. @@ -401,6 +427,8 @@ Failed to import save file. The given file appears to be corrupted or is not a valid Wii save. Failed to import save file. Please launch the game once, then try again. Merging a new NAND over your currently selected NAND will overwrite any channels and savegames that already exist. This process is not reversible, so it is recommended that you keep backups of both NANDs. Are you sure you want to continue? + Not installed + The Wii Menu is currently not installed. Would you like to install it now?\nAn internet connection is required to download the update. It is recommended to download the update on Wi-Fi, as the amount of data downloaded may be large. Details