From 957691444d2c59939ecbf96b2ea0a52bccf720a9 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Thu, 2 Jul 2015 23:54:32 -0400 Subject: [PATCH 1/5] Android TV: Replace toolbar on EmulationActivity with a full-screen menu. --- .../activities/EmulationActivity.java | 225 ++++++++++++------ .../fragments/EmulationFragment.java | 7 +- .../dolphinemu/fragments/MenuFragment.java | 38 +++ .../layout-television/activity_emulation.xml | 45 ++++ .../layout-television/fragment_emulation.xml | 14 ++ .../main/res/layout/fragment_ingame_menu.xml | 64 +++++ .../app/src/main/res/values/styles.xml | 34 +++ 7 files changed, 357 insertions(+), 70 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java create mode 100644 Source/Android/app/src/main/res/layout-television/activity_emulation.xml create mode 100644 Source/Android/app/src/main/res/layout-television/fragment_emulation.xml create mode 100644 Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml 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 6b27c08c4a..00501e10d6 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 @@ -15,6 +15,7 @@ import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; @@ -29,10 +30,13 @@ public final class EmulationActivity extends AppCompatActivity { private View mDecorView; private ImageView mImageView; + private FrameLayout mFrameEmulation; + private LinearLayout mMenuLayout; private boolean mDeviceHasTouchScreen; private boolean mSystemUiVisible; + private boolean mMenuVisible; // So that MainActivity knows which view to invalidate before the return animation. private int mPosition; @@ -56,49 +60,61 @@ public final class EmulationActivity extends AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { + mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); + + int themeId; + if (mDeviceHasTouchScreen) + { + themeId = R.style.DolphinEmulationGamecube; + + // Get a handle to the Window containing the UI. + mDecorView = getWindow().getDecorView(); + + // Set these options now so that the SurfaceView the game renders into is the right size. + mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + // Set the ActionBar to follow the navigation/status bar's visibility changes. + mDecorView.setOnSystemUiVisibilityChangeListener( + new View.OnSystemUiVisibilityChangeListener() + { + @Override + public void onSystemUiVisibilityChange(int flags) + { + mSystemUiVisible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + + if (mSystemUiVisible) + { + getSupportActionBar().show(); + hideSystemUiAfterDelay(); + } + else + { + getSupportActionBar().hide(); + } + } + } + ); + } + else + { + themeId = R.style.DolphinEmulationTvGamecube; + } + + setTheme(themeId); super.onCreate(savedInstanceState); // Picasso will take a while to load these big-ass screenshots. So don't run // the animation until we say so. postponeEnterTransition(); - mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); - - // Get a handle to the Window containing the UI. - mDecorView = getWindow().getDecorView(); - - // Set these options now so that the SurfaceView the game renders into is the right size. - mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - - // Set the ActionBar to follow the navigation/status bar's visibility changes. - mDecorView.setOnSystemUiVisibilityChangeListener( - new View.OnSystemUiVisibilityChangeListener() - { - @Override - public void onSystemUiVisibilityChange(int flags) - { - mSystemUiVisible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; - - if (mSystemUiVisible) - { - getSupportActionBar().show(); - hideSystemUiAfterDelay(); - } - else - { - getSupportActionBar().hide(); - } - } - } - ); - setContentView(R.layout.activity_emulation); mImageView = (ImageView) findViewById(R.id.image_screenshot); mFrameContent = (FrameLayout) findViewById(R.id.frame_content); mFrameEmulation = (FrameLayout) findViewById(R.id.frame_emulation_fragment); + mMenuLayout = (LinearLayout) findViewById(R.id.layout_ingame_menu); Intent gameToEmulate = getIntent(); String path = gameToEmulate.getStringExtra("SelectedGame"); @@ -181,8 +197,11 @@ public final class EmulationActivity extends AppCompatActivity { super.onPostCreate(savedInstanceState); - // Give the user a few seconds to see what the controls look like, then hide them. - hideSystemUiAfterDelay(); + if (mDeviceHasTouchScreen) + { + // Give the user a few seconds to see what the controls look like, then hide them. + hideSystemUiAfterDelay(); + } } @Override @@ -190,36 +209,88 @@ public final class EmulationActivity extends AppCompatActivity { super.onWindowFocusChanged(hasFocus); - if (hasFocus) + if (mDeviceHasTouchScreen) { - hideSystemUiAfterDelay(); - } - else - { - // If the window loses focus (i.e. a dialog box, or a popup menu is on screen - // stop hiding the UI. - mSystemUiHider.removeMessages(0); + if (hasFocus) + { + hideSystemUiAfterDelay(); + } + else + { + // If the window loses focus (i.e. a dialog box, or a popup menu is on screen + // stop hiding the UI. + mSystemUiHider.removeMessages(0); + } } } @Override public void onBackPressed() { - if (!mDeviceHasTouchScreen && !mSystemUiVisible) + if (!mDeviceHasTouchScreen) { - showSystemUI(); + toggleMenu(); } else { - // Let the system handle it; i.e. quit the activity TODO or show "are you sure?" dialog. - EmulationFragment fragment = (EmulationFragment) getFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - fragment.notifyEmulationStopped(); - - NativeLibrary.StopEmulation(); + stopEmulation(); } } + private void toggleMenu() + { + if (mMenuVisible) + { + mMenuLayout.animate() + .withLayer() + .setDuration(200) + .alpha(0.0f) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(new Runnable() + { + @Override + public void run() + { + mMenuLayout.setVisibility(View.GONE); + mMenuVisible = false; + } + }); + } + else + { + mMenuLayout.setVisibility(View.VISIBLE); + + mMenuLayout.setScaleX(1.1f); + mMenuLayout.setScaleY(1.1f); + mMenuLayout.setAlpha(0.0f); + + mMenuLayout.animate() + .withLayer() + .setDuration(300) + .alpha(1.0f) + .scaleX(1.0f) + .scaleY(1.0f) + .withEndAction(new Runnable() + { + @Override + public void run() + { + mMenuVisible = true; + } + }); + } + } + + private void stopEmulation() + { + EmulationFragment fragment = (EmulationFragment) getFragmentManager() + .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); + fragment.notifyEmulationStopped(); + + NativeLibrary.StopEmulation(); + } + public void exitWithAnimation() { runOnUiThread(new Runnable() @@ -257,7 +328,7 @@ public final class EmulationActivity extends AppCompatActivity mImageView.setVisibility(View.VISIBLE); mImageView.animate() .withLayer() - .setDuration(500) + .setDuration(100) .alpha(1.0f) .withEndAction(afterShowingScreenshot); } @@ -284,7 +355,13 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) + onMenuItemClicked(item.getItemId()); + return true; + } + + public void onMenuItemClicked(int id) + { + switch (id) { // Enable/Disable input overlay. case R.id.menu_emulation_input_overlay: @@ -294,67 +371,69 @@ public final class EmulationActivity extends AppCompatActivity emulationFragment.toggleInputOverlayVisibility(); - return true; + return; } // Screenshot capturing case R.id.menu_emulation_screenshot: NativeLibrary.SaveScreenShot(); - return true; + return; // Quicksave / Load case R.id.menu_quicksave: NativeLibrary.SaveState(9); - return true; + return; case R.id.menu_quickload: NativeLibrary.LoadState(9); - return true; + return; // Save state slots case R.id.menu_emulation_save_1: NativeLibrary.SaveState(0); - return true; + return; case R.id.menu_emulation_save_2: NativeLibrary.SaveState(1); - return true; + return; case R.id.menu_emulation_save_3: NativeLibrary.SaveState(2); - return true; + return; case R.id.menu_emulation_save_4: NativeLibrary.SaveState(3); - return true; + return; case R.id.menu_emulation_save_5: NativeLibrary.SaveState(4); - return true; + return; // Load state slots case R.id.menu_emulation_load_1: NativeLibrary.LoadState(0); - return true; + return; case R.id.menu_emulation_load_2: NativeLibrary.LoadState(1); - return true; + return; case R.id.menu_emulation_load_3: NativeLibrary.LoadState(2); - return true; + return; case R.id.menu_emulation_load_4: NativeLibrary.LoadState(3); - return true; + return; case R.id.menu_emulation_load_5: NativeLibrary.LoadState(4); - return true; + return; - default: - return super.onOptionsItemSelected(item); + case R.id.menu_exit: + toggleMenu(); + stopEmulation(); + return; } } @@ -362,6 +441,11 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean dispatchKeyEvent(KeyEvent event) { + if (mMenuVisible) + { + return super.dispatchKeyEvent(event); + } + int action = 0; switch (event.getAction()) @@ -391,6 +475,11 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (mMenuVisible) + { + return false; + } + if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) { return super.dispatchGenericMotionEvent(event); 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 9d23736cb6..1eb1684531 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 @@ -81,9 +81,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mSurfaceView.getHolder().addCallback(this); // If the input overlay was previously disabled, then don't show it. - if (!mPreferences.getBoolean("showInputOverlay", true)) + if (mInputOverlay != null) { - mInputOverlay.setVisibility(View.GONE); + if (!mPreferences.getBoolean("showInputOverlay", true)) + { + mInputOverlay.setVisibility(View.GONE); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java new file mode 100644 index 0000000000..f57ca36ede --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java @@ -0,0 +1,38 @@ +package org.dolphinemu.dolphinemu.fragments; + +import android.app.Fragment; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.EmulationActivity; + +public final class MenuFragment extends Fragment implements View.OnClickListener +{ + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.fragment_ingame_menu, container, false); + + for (int childIndex = 0; childIndex < rootView.getChildCount(); childIndex++) + { + Button button = (Button) rootView.getChildAt(childIndex); + + button.setOnClickListener(this); + } + + return rootView; + } + + @Override + public void onClick(View button) + { + ((EmulationActivity) getActivity()).onMenuItemClicked(button.getId()); + } +} diff --git a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml new file mode 100644 index 0000000000..8770751fee --- /dev/null +++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml b/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml new file mode 100644 index 0000000000..787de65186 --- /dev/null +++ b/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml b/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml new file mode 100644 index 0000000000..76572112fb --- /dev/null +++ b/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml @@ -0,0 +1,64 @@ + + + +