Android: Add online system update functionality

This commit is contained in:
Simonx22 2022-01-09 14:29:46 -05:00 committed by OatmealDome
parent 8ad1292df7
commit 55378cab39
13 changed files with 548 additions and 15 deletions

View File

@ -155,4 +155,3 @@
</application>
</manifest>

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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<Integer> mProgressData = new MutableLiveData<>();
private final MutableLiveData<Integer> mTotalData = new MutableLiveData<>();
private final MutableLiveData<Long> mTitleIdData = new MutableLiveData<>();
private final MutableLiveData<Integer> 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<Integer> getProgressData()
{
return mProgressData;
}
public MutableLiveData<Integer> getTotalData()
{
return mTotalData;
}
public MutableLiveData<Long> getTitleIdData()
{
return mTitleIdData;
}
public MutableLiveData<Integer> 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;
}
}

View File

@ -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.");

View File

@ -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;
}

View File

@ -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");
}
}
}

View File

@ -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));

View File

@ -25,6 +25,11 @@
android:title="@string/grid_menu_install_wad"
app:showAsAction="never"/>
<item
android:id="@+id/menu_load_wii_system_menu"
android:title="@string/grid_menu_load_wii_system_menu"
app:showAsAction="never"/>
<item
android:id="@+id/menu_import_wii_save"
android:title="@string/grid_menu_import_wii_save"
@ -35,4 +40,10 @@
android:title="@string/grid_menu_import_nand_backup"
app:showAsAction="never"/>
<item
android:id="@+id/menu_online_system_update"
android:title="@string/grid_menu_online_system_update"
app:showAsAction="never"/>
<group />
</menu>

View File

@ -182,6 +182,29 @@
<string name="osd_messages_description">Display messages over the emulation screen area. These messages include memory card writes, video backend and CPU information, and JIT cache clearing.</string>
<string name="download_game_covers">Download Game Covers from GameTDB.com</string>
<!-- Online Update Region Select Fragment -->
<string name="region_select_title">Please select a region</string>
<string name="europe">Europe</string>
<string name="japan">Japan</string>
<string name="korea">Korea</string>
<string name="united_states">United States</string>
<!-- Online Update Progress Bar Fragment -->
<string name="updating">Updating</string>
<string name="updating_message">Updating title %016x...\nThis can take a while.</string>
<string name="update_success">The emulated Wii console has been updated.</string>
<string name="already_up_to_date">The emulated Wii console is already up-to-date.</string>
<string name="region_mismatch">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.</string>
<string name="missing_update_partition">The game disc does not contain any usable update information.</string>
<string name="disc_read_failed">The game disc does not contain any usable update information.</string>
<string name="server_failed">"Could not download update information from Nintendo. Please check your Internet connection and try again.</string>
<string name="download_failed">Could not download update files from Nintendo. Please check your Internet connection and try again.</string>
<string name="import_failed">"Could not install an update to the Wii system memory. Please refer to logs for more information.</string>
<string name="update_cancelled">The update has been cancelled. It is strongly recommended to finish it in order to avoid inconsistent system software versions.</string>
<string name="update_success_title">Update completed</string>
<string name="update_failed_title">Update failed</string>
<string name="update_cancelled_title">Update cancelled</string>
<!-- Audio Settings -->
<string name="audio_submenu">Audio</string>
<string name="dsp_emulation_engine">DSP Emulation Engine</string>
@ -391,6 +414,9 @@
<string name="grid_menu_install_wad">Install WAD</string>
<string name="grid_menu_import_wii_save">Import Wii Save</string>
<string name="grid_menu_import_nand_backup">Import BootMii NAND Backup</string>
<string name="grid_menu_online_system_update">Perform Online System Update</string>
<string name="grid_menu_load_wii_system_menu">Load Wii System Menu</string>
<string name="grid_menu_load_wii_system_menu_installed">Load Wii System Menu (%s)</string>
<string name="import_in_progress">Importing...</string>
<string name="do_not_close_app">Do not close the app!</string>
<string name="wad_install_success">Successfully installed this title to the NAND.</string>
@ -401,6 +427,8 @@
<string name="wii_save_import_corruped_source">Failed to import save file. The given file appears to be corrupted or is not a valid Wii save.</string>
<string name="wii_save_import_title_missing">Failed to import save file. Please launch the game once, then try again.</string>
<string name="nand_import_warning">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?</string>
<string name="system_menu_not_installed_title">Not installed</string>
<string name="system_menu_not_installed_message">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.</string>
<!-- Game Properties Screen -->
<string name="properties_details">Details</string>