Merge pull request #9004 from JosJuice/android-menu-back

Android: Use Back to open the emulation menu on all devices
This commit is contained in:
JMC47 2020-09-12 08:17:23 -04:00 committed by GitHub
commit b1fecbb71c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 347 additions and 567 deletions

View File

@ -5,8 +5,8 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.SparseIntArray;
@ -23,8 +23,10 @@ import android.widget.Toast;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
@ -62,7 +64,6 @@ public final class EmulationActivity extends AppCompatActivity
private static final String BACKSTACK_NAME_SUBMENU = "submenu";
public static final int REQUEST_CHANGE_DISC = 1;
private View mDecorView;
private EmulationFragment mEmulationFragment;
private SharedPreferences mPreferences;
@ -70,9 +71,6 @@ public final class EmulationActivity extends AppCompatActivity
private Settings mSettings;
private MenuItem mPauseEmulationButton;
private MenuItem mUnpauseEmulationButton;
private boolean mDeviceHasTouchScreen;
private boolean mMenuVisible;
@ -85,7 +83,6 @@ public final class EmulationActivity extends AppCompatActivity
private int mPlatform;
private String[] mPaths;
private static boolean sUserPausedEmulation;
private boolean backPressedOnce = false;
public static final String EXTRA_SELECTED_GAMES = "SelectedGames";
public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
@ -104,7 +101,7 @@ public final class EmulationActivity extends AppCompatActivity
MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC,
MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP,
MENU_ACTION_SCREEN_ORIENTATION, MENU_ACTION_MOTION_CONTROLS, MENU_ACTION_PAUSE_EMULATION,
MENU_ACTION_UNPAUSE_EMULATION})
MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS})
public @interface MenuAction
{
}
@ -142,7 +139,7 @@ public final class EmulationActivity extends AppCompatActivity
public static final int MENU_ACTION_MOTION_CONTROLS = 30;
public static final int MENU_ACTION_PAUSE_EMULATION = 31;
public static final int MENU_ACTION_UNPAUSE_EMULATION = 32;
public static final int MENU_ACTION_OVERLAY_CONTROLS = 33;
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
@ -156,33 +153,6 @@ public final class EmulationActivity extends AppCompatActivity
.append(R.id.menu_emulation_adjust_scale, EmulationActivity.MENU_ACTION_ADJUST_SCALE);
buttonsActionsMap.append(R.id.menu_emulation_choose_controller,
EmulationActivity.MENU_ACTION_CHOOSE_CONTROLLER);
buttonsActionsMap
.append(R.id.menu_refresh_wiimotes, EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES);
buttonsActionsMap
.append(R.id.menu_emulation_pause, EmulationActivity.MENU_ACTION_PAUSE_EMULATION);
buttonsActionsMap
.append(R.id.menu_emulation_unpause, EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION);
buttonsActionsMap
.append(R.id.menu_emulation_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
buttonsActionsMap.append(R.id.menu_quicksave, EmulationActivity.MENU_ACTION_QUICK_SAVE);
buttonsActionsMap.append(R.id.menu_quickload, EmulationActivity.MENU_ACTION_QUICK_LOAD);
buttonsActionsMap
.append(R.id.menu_emulation_save_root, EmulationActivity.MENU_ACTION_SAVE_ROOT);
buttonsActionsMap
.append(R.id.menu_emulation_load_root, EmulationActivity.MENU_ACTION_LOAD_ROOT);
buttonsActionsMap.append(R.id.menu_emulation_save_1, EmulationActivity.MENU_ACTION_SAVE_SLOT1);
buttonsActionsMap.append(R.id.menu_emulation_save_2, EmulationActivity.MENU_ACTION_SAVE_SLOT2);
buttonsActionsMap.append(R.id.menu_emulation_save_3, EmulationActivity.MENU_ACTION_SAVE_SLOT3);
buttonsActionsMap.append(R.id.menu_emulation_save_4, EmulationActivity.MENU_ACTION_SAVE_SLOT4);
buttonsActionsMap.append(R.id.menu_emulation_save_5, EmulationActivity.MENU_ACTION_SAVE_SLOT5);
buttonsActionsMap.append(R.id.menu_emulation_load_1, EmulationActivity.MENU_ACTION_LOAD_SLOT1);
buttonsActionsMap.append(R.id.menu_emulation_load_2, EmulationActivity.MENU_ACTION_LOAD_SLOT2);
buttonsActionsMap.append(R.id.menu_emulation_load_3, EmulationActivity.MENU_ACTION_LOAD_SLOT3);
buttonsActionsMap.append(R.id.menu_emulation_load_4, EmulationActivity.MENU_ACTION_LOAD_SLOT4);
buttonsActionsMap.append(R.id.menu_emulation_load_5, EmulationActivity.MENU_ACTION_LOAD_SLOT5);
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
buttonsActionsMap.append(R.id.menu_emulation_joystick_rel_center,
EmulationActivity.MENU_ACTION_JOYSTICK_REL_CENTER);
buttonsActionsMap.append(R.id.menu_emulation_rumble, EmulationActivity.MENU_ACTION_RUMBLE);
@ -192,8 +162,6 @@ public final class EmulationActivity extends AppCompatActivity
EmulationActivity.MENU_SET_IR_SENSITIVITY);
buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap,
EmulationActivity.MENU_ACTION_CHOOSE_DOUBLETAP);
buttonsActionsMap.append(R.id.menu_screen_orientation,
EmulationActivity.MENU_ACTION_SCREEN_ORIENTATION);
buttonsActionsMap.append(R.id.menu_emulation_motion_controls,
EmulationActivity.MENU_ACTION_MOTION_CONTROLS);
}
@ -317,33 +285,10 @@ public final class EmulationActivity extends AppCompatActivity
mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen");
mMotionListener = new MotionListener(this);
int themeId;
if (mDeviceHasTouchScreen)
{
themeId = R.style.DolphinEmulationBase;
// Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive();
// Get a handle to the Window containing the UI.
mDecorView = getWindow().getDecorView();
mDecorView.setOnSystemUiVisibilityChangeListener(visibility ->
{
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
{
// Go back to immersive fullscreen mode in 3s
Handler handler = new Handler(getMainLooper());
handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */);
}
});
// Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive();
Toast.makeText(this, getString(R.string.emulation_touch_button_help), Toast.LENGTH_LONG)
.show();
}
else
{
themeId = R.style.DolphinEmulationTvBase;
}
setTheme(themeId);
Toast.makeText(this, getString(R.string.emulation_menu_help), Toast.LENGTH_LONG).show();
Rumble.initRumble(this);
@ -360,10 +305,7 @@ public final class EmulationActivity extends AppCompatActivity
.commit();
}
if (mDeviceHasTouchScreen)
{
setTitle(mSelectedTitle);
}
setTitle(mSelectedTitle);
}
@Override
@ -390,10 +332,20 @@ public final class EmulationActivity extends AppCompatActivity
sUserPausedEmulation = savedInstanceState.getBoolean(EXTRA_USER_PAUSED_EMULATION);
}
@Override
public void onWindowFocusChanged(boolean hasFocus)
{
if (hasFocus)
{
enableFullscreenImmersive();
}
}
@Override
protected void onResume()
{
super.onResume();
if (!sIsGameCubeGame && mPreferences.getInt("motionControlsEnabled", 0) != 2)
mMotionListener.enable();
}
@ -414,29 +366,22 @@ public final class EmulationActivity extends AppCompatActivity
@Override
public void onBackPressed()
{
if (!mDeviceHasTouchScreen)
if (!closeSubmenu())
{
boolean popResult = getSupportFragmentManager().popBackStackImmediate(
BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (!popResult)
{
toggleMenu();
}
toggleMenu();
}
else
}
@Override
public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
if (backPressedOnce)
{
mEmulationFragment.stopEmulation();
finish();
}
else
{
backPressedOnce = true;
Toast.makeText(this, "Press back again to exit", Toast.LENGTH_LONG).show();
new Handler().postDelayed(() -> backPressedOnce = false, 3000);
}
mEmulationFragment.stopEmulation();
finish();
return true;
}
return super.onKeyLongPress(keyCode, event);
}
@Override
@ -459,14 +404,13 @@ public final class EmulationActivity extends AppCompatActivity
private void enableFullscreenImmersive()
{
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
mDecorView.setSystemUiVisibility(
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE);
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
private void updateOrientation()
@ -475,13 +419,22 @@ public final class EmulationActivity extends AppCompatActivity
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE));
}
private boolean closeSubmenu()
{
return getSupportFragmentManager().popBackStackImmediate(BACKSTACK_NAME_SUBMENU,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
private boolean closeMenu()
{
mMenuVisible = false;
return getSupportFragmentManager().popBackStackImmediate(BACKSTACK_NAME_MENU,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
private void toggleMenu()
{
boolean result = getSupportFragmentManager().popBackStackImmediate(
BACKSTACK_NAME_MENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
mMenuVisible = false;
if (!result)
if (!closeMenu())
{
// Removing the menu failed, so that means it wasn't visible. Add it.
Fragment fragment = MenuFragment.newInstance(mSelectedTitle);
@ -498,35 +451,13 @@ public final class EmulationActivity extends AppCompatActivity
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
public void showOverlayControlsMenu(@NonNull View anchor)
{
// Inflate the menu; this adds items to the action bar if it is present.
if (sIsGameCubeGame)
{
getMenuInflater().inflate(R.menu.menu_emulation, menu);
}
else
{
getMenuInflater().inflate(R.menu.menu_emulation_wii, menu);
}
PopupMenu popup = new PopupMenu(this, anchor);
Menu menu = popup.getMenu();
mPauseEmulationButton = menu.findItem(R.id.menu_emulation_pause);
mUnpauseEmulationButton = menu.findItem(R.id.menu_emulation_unpause);
if (sUserPausedEmulation)
{
showUnpauseEmulationButton();
}
if (mSettings.getSection(SettingsFile.FILE_NAME_DOLPHIN, Settings.SECTION_INI_CORE)
.getBoolean(SettingsFile.KEY_ENABLE_SAVE_STATES, false))
{
menu.findItem(R.id.menu_quicksave).setVisible(true);
menu.findItem(R.id.menu_quickload).setVisible(true);
menu.findItem(R.id.menu_emulation_save_root).setVisible(true);
menu.findItem(R.id.menu_emulation_load_root).setVisible(true);
}
int id = sIsGameCubeGame ? R.menu.menu_overlay_controls_gc : R.menu.menu_overlay_controls_wii;
popup.getMenuInflater().inflate(id, menu);
// Populate the checkbox value for joystick center on touch
menu.findItem(R.id.menu_emulation_joystick_rel_center)
@ -534,7 +465,9 @@ public final class EmulationActivity extends AppCompatActivity
menu.findItem(R.id.menu_emulation_rumble)
.setChecked(mPreferences.getBoolean("phoneRumble", true));
return true;
popup.setOnMenuItemClickListener(this::onOptionsItemSelected);
popup.show();
}
@SuppressWarnings("WrongConstant")
@ -608,13 +541,11 @@ public final class EmulationActivity extends AppCompatActivity
case MENU_ACTION_PAUSE_EMULATION:
sUserPausedEmulation = true;
NativeLibrary.PauseEmulation();
showUnpauseEmulationButton();
return;
case MENU_ACTION_UNPAUSE_EMULATION:
sUserPausedEmulation = false;
NativeLibrary.UnPauseEmulation();
showPauseEmulationButton();
return;
// Screenshot capturing
@ -631,19 +562,12 @@ public final class EmulationActivity extends AppCompatActivity
NativeLibrary.LoadState(9);
return;
// TV Menu only
case MENU_ACTION_SAVE_ROOT:
if (!mDeviceHasTouchScreen)
{
showSubMenu(SaveLoadStateFragment.SaveOrLoad.SAVE);
}
showSubMenu(SaveLoadStateFragment.SaveOrLoad.SAVE);
return;
case MENU_ACTION_LOAD_ROOT:
if (!mDeviceHasTouchScreen)
{
showSubMenu(SaveLoadStateFragment.SaveOrLoad.LOAD);
}
showSubMenu(SaveLoadStateFragment.SaveOrLoad.LOAD);
return;
// Save state slots
@ -718,37 +642,17 @@ public final class EmulationActivity extends AppCompatActivity
return;
case MENU_ACTION_EXIT:
// ATV menu is built using a fragment, this will pop that fragment before emulation ends.
if (TvUtil.isLeanback(getApplicationContext()))
toggleMenu(); // Hide the menu (it will be showing since we just clicked it)
mEmulationFragment.stopEmulation();
finish();
return;
}
}
private void showPauseEmulationButton()
{
mUnpauseEmulationButton.setVisible(false);
mPauseEmulationButton.setVisible(true);
}
private void showUnpauseEmulationButton()
{
mPauseEmulationButton.setVisible(false);
mUnpauseEmulationButton.setVisible(true);
}
public static boolean getHasUserPausedEmulation()
{
return sUserPausedEmulation;
}
public static void setHasUserPausedEmulation(boolean value)
{
sUserPausedEmulation = value;
}
private void toggleJoystickRelCenter(boolean state)
{
final SharedPreferences.Editor editor = mPreferences.edit();
@ -764,7 +668,6 @@ public final class EmulationActivity extends AppCompatActivity
Rumble.setPhoneVibrator(state, this);
}
private void editControlsPlacement()
{
if (mEmulationFragment.isConfiguringControls())
@ -773,6 +676,8 @@ public final class EmulationActivity extends AppCompatActivity
}
else
{
closeSubmenu();
closeMenu();
mEmulationFragment.startConfiguringControls();
}
}
@ -781,7 +686,7 @@ public final class EmulationActivity extends AppCompatActivity
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
if (mMenuVisible)
if (mMenuVisible || event.getKeyCode() == KeyEvent.KEYCODE_BACK)
{
return super.dispatchKeyEvent(event);
}
@ -791,14 +696,6 @@ public final class EmulationActivity extends AppCompatActivity
switch (event.getAction())
{
case KeyEvent.ACTION_DOWN:
// Handling the case where the back button is pressed.
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
{
onBackPressed();
return true;
}
// Normal key events.
action = NativeLibrary.ButtonState.PRESSED;
break;
case KeyEvent.ACTION_UP:
@ -1176,6 +1073,52 @@ public final class EmulationActivity extends AppCompatActivity
.show();
}
private static boolean areCoordinatesOutside(@Nullable View view, float x, float y)
{
if (view == null)
{
return true;
}
Rect viewBounds = new Rect();
view.getGlobalVisibleRect(viewBounds);
return !viewBounds.contains(Math.round(x), Math.round(y));
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
if (event.getActionMasked() == MotionEvent.ACTION_DOWN)
{
boolean anyMenuClosed = false;
Fragment submenu = getSupportFragmentManager().findFragmentById(R.id.frame_submenu);
if (submenu != null && areCoordinatesOutside(submenu.getView(), event.getX(), event.getY()))
{
closeSubmenu();
submenu = null;
anyMenuClosed = true;
}
if (submenu == null)
{
Fragment menu = getSupportFragmentManager().findFragmentById(R.id.frame_menu);
if (menu != null && areCoordinatesOutside(menu.getView(), event.getX(), event.getY()))
{
closeMenu();
anyMenuClosed = true;
}
}
if (anyMenuClosed)
{
return true;
}
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event)
{

View File

@ -12,7 +12,6 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSettin
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.TvUtil;
import java.util.ArrayList;
import java.util.List;
@ -63,8 +62,8 @@ public final class MotionAlertDialog extends AlertDialog
@Override
public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event)
{
// Option to clear by long back is only needed on the TV interface
if (TvUtil.isLeanback(getContext()) && keyCode == KeyEvent.KEYCODE_BACK)
// Intended for devices with no touchscreen or mouse
if (keyCode == KeyEvent.KEYCODE_BACK)
{
setting.clearValue(mAdapter.getSettings());
dismiss();

View File

@ -1,5 +1,7 @@
package org.dolphinemu.dolphinemu.fragments;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
@ -19,8 +21,10 @@ import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
public final class MenuFragment extends Fragment implements View.OnClickListener
{
private TextView mTitleText;
private View mPauseEmulation;
private View mUnpauseEmulation;
private static final String KEY_TITLE = "title";
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
@ -38,8 +42,12 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
.append(R.id.menu_emulation_save_root, EmulationActivity.MENU_ACTION_SAVE_ROOT);
buttonsActionsMap
.append(R.id.menu_emulation_load_root, EmulationActivity.MENU_ACTION_LOAD_ROOT);
buttonsActionsMap
.append(R.id.menu_overlay_controls, EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS);
buttonsActionsMap
.append(R.id.menu_refresh_wiimotes, EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES);
buttonsActionsMap
.append(R.id.menu_screen_orientation, EmulationActivity.MENU_ACTION_SCREEN_ORIENTATION);
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
}
@ -55,6 +63,14 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
return fragment;
}
// This is primarily intended to account for any navigation bar at the bottom of the screen
private int getBottomPaddingRequired()
{
Rect visibleFrame = new Rect();
requireActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleFrame);
return visibleFrame.bottom - visibleFrame.top - getResources().getDisplayMetrics().heightPixels;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
@ -65,10 +81,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
mPauseEmulation = options.findViewById(R.id.menu_pause_emulation);
mUnpauseEmulation = options.findViewById(R.id.menu_unpause_emulation);
if (EmulationActivity.getHasUserPausedEmulation())
{
showUnpauseEmulationButton();
}
updatePauseUnpauseVisibility();
boolean enableSaveStates = ((EmulationActivity) getActivity()).getSettings()
.getSection(SettingsFile.FILE_NAME_DOLPHIN, Settings.SECTION_INI_CORE)
@ -82,6 +95,41 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
options.findViewById(R.id.menu_emulation_load_root).setVisibility(View.VISIBLE);
}
PackageManager packageManager = requireActivity().getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
{
options.findViewById(R.id.menu_overlay_controls).setVisibility(View.GONE);
}
if (EmulationActivity.isGameCubeGame())
{
options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE);
}
// Old devices which support both portrait and landscape may report support for neither,
// so we only hide the orientation button if the device only supports one orientation
if (packageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT) !=
packageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE))
{
options.findViewById(R.id.menu_screen_orientation).setVisibility(View.GONE);
}
int bottomPaddingRequired = getBottomPaddingRequired();
// Provide a safe zone between the navigation bar and Exit Emulation to avoid accidental touches
float density = getResources().getDisplayMetrics().density;
if (bottomPaddingRequired >= 32 * density)
{
bottomPaddingRequired += 32 * density;
}
if (bottomPaddingRequired > rootView.getPaddingBottom())
{
rootView.setPadding(rootView.getPaddingLeft(), rootView.getPaddingTop(),
rootView.getPaddingRight(), bottomPaddingRequired);
}
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
{
Button button = (Button) options.getChildAt(childIndex);
@ -89,26 +137,24 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
button.setOnClickListener(this);
}
TextView titleText = rootView.findViewById(R.id.text_game_title);
rootView.findViewById(R.id.menu_exit).setOnClickListener(this);
mTitleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE);
if (title != null)
{
titleText.setText(title);
mTitleText.setText(title);
}
return rootView;
}
private void showPauseEmulationButton()
private void updatePauseUnpauseVisibility()
{
mUnpauseEmulation.setVisibility(View.GONE);
mPauseEmulation.setVisibility(View.VISIBLE);
}
boolean paused = EmulationActivity.getHasUserPausedEmulation();
private void showUnpauseEmulationButton()
{
mPauseEmulation.setVisibility(View.GONE);
mUnpauseEmulation.setVisibility(View.VISIBLE);
mUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE);
mPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE);
}
@SuppressWarnings("WrongConstant")
@ -116,21 +162,23 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
public void onClick(View button)
{
int action = buttonsActionsMap.get(button.getId());
if (action == EmulationActivity.MENU_ACTION_PAUSE_EMULATION)
EmulationActivity activity = (EmulationActivity) requireActivity();
if (action == EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS)
{
EmulationActivity.setHasUserPausedEmulation(true);
NativeLibrary.PauseEmulation();
showUnpauseEmulationButton();
}
else if (action == EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION)
{
EmulationActivity.setHasUserPausedEmulation(false);
NativeLibrary.UnPauseEmulation();
showPauseEmulationButton();
// We could use the button parameter as the anchor here, but this often results in a tiny menu
// (because the button often is in the middle of the screen), so let's use mTitleText instead
activity.showOverlayControlsMenu(mTitleText);
}
else if (action >= 0)
{
((EmulationActivity) getActivity()).handleMenuAction(action);
activity.handleMenuAction(action);
}
if (action == EmulationActivity.MENU_ACTION_PAUSE_EMULATION ||
action == EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION)
{
updatePauseUnpauseVisibility();
}
}
}

View File

@ -0,0 +1,7 @@
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
/>

View File

@ -1,38 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frame_content">
<FrameLayout
android:id="@+id/frame_emulation_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<org.dolphinemu.dolphinemu.ui.NVidiaShieldWorkaroundView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<FrameLayout
android:id="@+id/frame_menu"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".25"
tools:layout="@layout/fragment_ingame_menu"/>
<FrameLayout
android:id="@+id/frame_submenu"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".75"/>
</LinearLayout>
</FrameLayout>

View File

@ -1,6 +1,8 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frame_content">
<FrameLayout
@ -8,4 +10,27 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<org.dolphinemu.dolphinemu.ui.NVidiaShieldWorkaroundView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<FrameLayout
android:id="@+id/frame_menu"
android:layout_width="260dp"
android:layout_height="match_parent"
tools:layout="@layout/fragment_ingame_menu"/>
<FrameLayout
android:id="@+id/frame_submenu"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</FrameLayout>

View File

@ -4,6 +4,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:background="@color/dolphin_blue_dark"
tools:layout_width="250dp">
@ -14,7 +15,9 @@
tools:text="The Legend of Zelda: The Wind Waker"
android:textColor="@android:color/white"
android:textSize="20sp"
android:layout_margin="32dp"/>
android:layout_marginHorizontal="32dp"
android:layout_marginTop="32dp"
android:layout_marginBottom="16dp"/>
<ScrollView
android:layout_width="match_parent"
@ -67,23 +70,41 @@
style="@style/InGameMenuOption"
android:visibility="gone"/>
<Button
android:id="@+id/menu_overlay_controls"
android:text="@string/emulation_overlay_controls"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_refresh_wiimotes"
android:text="@string/emulation_refresh_wiimotes"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_screen_orientation"
android:text="@string/emulation_screen_orientation"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_change_disc"
android:text="@string/emulation_change_disc"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_exit"
android:text="@string/emulation_exit"
style="@style/InGameMenuOption"/>
</LinearLayout>
</ScrollView>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#FFFFFF"
android:layout_marginTop="24dp"
android:layout_marginBottom="16dp"/>
<Button
android:id="@+id/menu_exit"
android:text="@string/emulation_exit"
style="@style/InGameMenuOption"/>
</LinearLayout>

View File

@ -2,51 +2,51 @@
android:id="@+id/grid_state_slots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="2"
android:columnCount="@integer/loadsave_state_columns"
android:rowCount="@integer/loadsave_state_rows"
android:layout_gravity="center"
android:background="#af000000">
<Button
android:id="@+id/loadsave_state_button_1"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot1"
style="@style/OverlayInGameMenuOption"/>
<Button
android:id="@+id/loadsave_state_button_2"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot2"
style="@style/OverlayInGameMenuOption"/>
<Button
android:id="@+id/loadsave_state_button_3"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot3"
style="@style/OverlayInGameMenuOption"/>
<Button
android:id="@+id/loadsave_state_button_4"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot4"
style="@style/OverlayInGameMenuOption"/>
<Button
android:id="@+id/loadsave_state_button_5"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot5"
style="@style/OverlayInGameMenuOption"/>
<Button
android:id="@+id/loadsave_state_button_6"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_height="96dp"
android:text="@string/emulation_slot6"
style="@style/OverlayInGameMenuOption"/>
</GridLayout>
</GridLayout>

View File

@ -1,143 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="org.dolphinemu.dolphinemu.activities.EmulationActivity">
<item
android:id="@+id/menu_emulation_pause"
app:showAsAction="ifRoom"
android:icon="@drawable/lb_ic_pause"
android:title="@string/pause_emulation"/>
<item
android:id="@+id/menu_emulation_unpause"
app:showAsAction="ifRoom"
android:icon="@drawable/lb_ic_play"
android:title="@string/unpause_emulation"
android:visible="false"/>
<item
android:id="@+id/menu_emulation_screenshot"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_screenshot"
android:title="@string/emulation_screenshot"/>
<item
android:id="@+id/menu_quicksave"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_quicksave"
android:title="@string/emulation_quicksave"
android:visible="false"/>
<item
android:id="@+id/menu_quickload"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_quickload"
android:title="@string/emulation_quickload"
android:visible="false"/>
<!-- Save State Slots -->
<item
android:id="@+id/menu_emulation_save_root"
app:showAsAction="never"
android:title="@string/emulation_savestate"
android:visible="false">
<menu>
<item
android:id="@+id/menu_emulation_save_1"
android:title="@string/emulation_slot1"/>
<item
android:id="@+id/menu_emulation_save_2"
android:title="@string/emulation_slot2"/>
<item
android:id="@+id/menu_emulation_save_3"
android:title="@string/emulation_slot3"/>
<item
android:id="@+id/menu_emulation_save_4"
android:title="@string/emulation_slot4"/>
<item
android:id="@+id/menu_emulation_save_5"
android:title="@string/emulation_slot5"/>
</menu>
</item>
<!-- Load State Slots -->
<item
android:id="@+id/menu_emulation_load_root"
app:showAsAction="never"
android:title="@string/emulation_loadstate"
android:visible="false">
<menu>
<item
android:id="@+id/menu_emulation_load_1"
android:title="@string/emulation_slot1"/>
<item
android:id="@+id/menu_emulation_load_2"
android:title="@string/emulation_slot2"/>
<item
android:id="@+id/menu_emulation_load_3"
android:title="@string/emulation_slot3"/>
<item
android:id="@+id/menu_emulation_load_4"
android:title="@string/emulation_slot4"/>
<item
android:id="@+id/menu_emulation_load_5"
android:title="@string/emulation_slot5"/>
</menu>
</item>
<item
android:id="@+id/menu_emulation_overlay_controls"
app:showAsAction="never"
android:title="@string/emulation_overlay_controls">
<menu>
<item
android:id="@+id/menu_emulation_edit_layout"
android:title="@string/emulation_edit_layout"/>
<item
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>
<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_scale"/>
<item
android:id="@+id/menu_emulation_joystick_rel_center"
android:checkable="true"
android:title="@string/emulation_control_joystick_rel_center"/>
<item
android:id="@+id/menu_emulation_rumble"
android:checkable="true"
android:title="@string/emulation_control_rumble"/>
<item
android:id="@+id/menu_emulation_reset_overlay"
android:title="@string/emulation_touch_overlay_reset"/>
</menu>
</item>
<item
android:id="@+id/menu_screen_orientation"
app:showAsAction="never"
android:title="@string/emulation_screen_orientation"/>
<item
android:id="@+id/menu_change_disc"
app:showAsAction="never"
android:title="@string/emulation_change_disc"/>
<item
android:id="@+id/menu_exit"
app:showAsAction="never"
android:title="@string/emulation_exit"/>
</menu>

View File

@ -1,163 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="org.dolphinemu.dolphinemu.activities.EmulationActivity">
<item
android:id="@+id/menu_emulation_pause"
app:showAsAction="ifRoom"
android:icon="@drawable/lb_ic_pause"
android:title="@string/pause_emulation"/>
<item
android:id="@+id/menu_emulation_unpause"
app:showAsAction="ifRoom"
android:icon="@drawable/lb_ic_play"
android:title="@string/unpause_emulation"
android:visible="false"/>
<item
android:id="@+id/menu_emulation_screenshot"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_screenshot"
android:title="@string/emulation_screenshot"/>
<item
android:id="@+id/menu_quicksave"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_quicksave"
android:title="@string/emulation_quicksave"
android:visible="false"/>
<item
android:id="@+id/menu_quickload"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_quickload"
android:title="@string/emulation_quickload"
android:visible="false"/>
<!-- Save State Slots -->
<item
android:id="@+id/menu_emulation_save_root"
app:showAsAction="never"
android:title="@string/emulation_savestate"
android:visible="false">
<menu>
<item
android:id="@+id/menu_emulation_save_1"
android:title="@string/emulation_slot1"/>
<item
android:id="@+id/menu_emulation_save_2"
android:title="@string/emulation_slot2"/>
<item
android:id="@+id/menu_emulation_save_3"
android:title="@string/emulation_slot3"/>
<item
android:id="@+id/menu_emulation_save_4"
android:title="@string/emulation_slot4"/>
<item
android:id="@+id/menu_emulation_save_5"
android:title="@string/emulation_slot5"/>
</menu>
</item>
<!-- Load State Slots -->
<item
android:id="@+id/menu_emulation_load_root"
app:showAsAction="never"
android:title="@string/emulation_loadstate"
android:visible="false">
<menu>
<item
android:id="@+id/menu_emulation_load_1"
android:title="@string/emulation_slot1"/>
<item
android:id="@+id/menu_emulation_load_2"
android:title="@string/emulation_slot2"/>
<item
android:id="@+id/menu_emulation_load_3"
android:title="@string/emulation_slot3"/>
<item
android:id="@+id/menu_emulation_load_4"
android:title="@string/emulation_slot4"/>
<item
android:id="@+id/menu_emulation_load_5"
android:title="@string/emulation_slot5"/>
</menu>
</item>
<item
android:id="@+id/menu_emulation_overlay_controls"
app:showAsAction="never"
android:title="@string/emulation_overlay_controls">
<menu>
<item
android:id="@+id/menu_emulation_edit_layout"
android:title="@string/emulation_edit_layout"/>
<item
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>
<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_scale"/>
<group android:checkableBehavior="all">
<item
android:id="@+id/menu_emulation_joystick_rel_center"
android:checkable="true"
android:title="@string/emulation_control_joystick_rel_center"/>
<item
android:id="@+id/menu_emulation_rumble"
android:checkable="true"
android:title="@string/emulation_control_rumble"/>
</group>
<item
android:id="@+id/menu_emulation_choose_controller"
android:title="@string/emulation_choose_controller"/>
<item
android:id="@+id/menu_emulation_motion_controls"
android:title="@string/emulation_motion_controls"/>
<item
android:id="@+id/menu_emulation_ir_group"
android:title="@string/emulation_ir_group"
app:showAsAction="never">
<menu>
<item
android:id="@+id/menu_emulation_set_ir_sensitivity"
android:title="@string/emulation_ir_sensitivity"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_emulation_choose_doubletap"
android:title="@string/emulation_choose_doubletap"
app:showAsAction="ifRoom"/>
</menu>
</item>
<item
android:id="@+id/menu_emulation_reset_overlay"
android:title="@string/emulation_touch_overlay_reset"/>
</menu>
</item>
<item
android:id="@+id/menu_screen_orientation"
app:showAsAction="never"
android:title="@string/emulation_screen_orientation"/>
<item
android:id="@+id/menu_change_disc"
app:showAsAction="never"
android:title="@string/emulation_change_disc"/>
</menu>

View File

@ -0,0 +1,30 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.dolphinemu.dolphinemu.activities.EmulationActivity">
<item
android:id="@+id/menu_emulation_edit_layout"
android:title="@string/emulation_edit_layout"/>
<item
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>
<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_scale"/>
<item
android:id="@+id/menu_emulation_joystick_rel_center"
android:checkable="true"
android:title="@string/emulation_control_joystick_rel_center"/>
<item
android:id="@+id/menu_emulation_rumble"
android:checkable="true"
android:title="@string/emulation_control_rumble"/>
<item
android:id="@+id/menu_emulation_reset_overlay"
android:title="@string/emulation_touch_overlay_reset"/>
</menu>

View File

@ -0,0 +1,53 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.dolphinemu.dolphinemu.activities.EmulationActivity">
<item
android:id="@+id/menu_emulation_edit_layout"
android:title="@string/emulation_edit_layout"/>
<item
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>
<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_scale"/>
<group android:checkableBehavior="all">
<item
android:id="@+id/menu_emulation_joystick_rel_center"
android:checkable="true"
android:title="@string/emulation_control_joystick_rel_center"/>
<item
android:id="@+id/menu_emulation_rumble"
android:checkable="true"
android:title="@string/emulation_control_rumble"/>
</group>
<item
android:id="@+id/menu_emulation_choose_controller"
android:title="@string/emulation_choose_controller"/>
<item
android:id="@+id/menu_emulation_motion_controls"
android:title="@string/emulation_motion_controls"/>
<item
android:id="@+id/menu_emulation_ir_group"
android:title="@string/emulation_ir_group">
<menu>
<item
android:id="@+id/menu_emulation_set_ir_sensitivity"
android:title="@string/emulation_ir_sensitivity"/>
<item
android:id="@+id/menu_emulation_choose_doubletap"
android:title="@string/emulation_choose_doubletap"/>
</menu>
</item>
<item
android:id="@+id/menu_emulation_reset_overlay"
android:title="@string/emulation_touch_overlay_reset"/>
</menu>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="loadsave_state_columns">2</integer>
<integer name="loadsave_state_rows">3</integer>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="loadsave_state_columns">3</integer>
<integer name="loadsave_state_rows">2</integer>
</resources>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="game_grid_columns">3</integer>
<integer name="loadsave_state_columns">1</integer>
<integer name="loadsave_state_rows">6</integer>
<!-- Default GameCube landscape layout -->
<integer name="BUTTON_A_X">865</integer>

View File

@ -336,7 +336,7 @@
<string name="emulation_screenshot">Take Screenshot</string>
<string name="emulation_savestate">Save State</string>
<string name="emulation_loadstate">Load State</string>
<string name="emulation_exit">Exit</string>
<string name="emulation_exit">Exit Emulation</string>
<string name="emulation_slot1">Slot 1</string>
<string name="emulation_slot2">Slot 2</string>
<string name="emulation_slot3">Slot 3</string>
@ -355,7 +355,7 @@
<string name="emulation_control_joystick_rel_center">Relative Stick Center</string>
<string name="emulation_control_rumble">Rumble</string>
<string name="emulation_choose_controller">Choose Controller</string>
<string name="emulation_touch_button_help">Swipe down from the top of the screen to access the menu.</string>
<string name="emulation_menu_help">Press Back to access the menu.\nLong press Back to exit emulation.</string>
<string name="emulation_touch_overlay_reset">Reset Overlay</string>
<string name="emulation_ir_group">Touch IR Pointer</string>
<string name="emulation_ir_sensitivity">IR Sensitivity</string>

View File

@ -29,21 +29,7 @@
<style name="DolphinDialogBase" parent="Theme.AppCompat.DayNight.Dialog.Alert" />
<style name="DolphinEmulationBase" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="colorPrimary">@color/dolphin_blue</item>
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
<item name="colorAccent">@color/dolphin_purple</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowBackground">@android:color/black</item>
<!-- Enable window content transitions -->
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
</style>
<style name="DolphinEmulationTvBase" parent="Theme.AppCompat.DayNight.NoActionBar">
<style name="DolphinEmulationBase" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="colorPrimary">@color/dolphin_blue</item>
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
<item name="colorAccent">@color/dolphin_purple</item>