Android: Implement new EmulationActivity.

This commit is contained in:
Eder Bastos 2015-05-20 07:07:17 -04:00
parent 3e5e352fee
commit 286af8be50
11 changed files with 542 additions and 13 deletions

View File

@ -47,6 +47,10 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".activities.EmulationActivity"
android:theme="@style/DolphinEmulationGamecube"/>
<activity <activity
android:name=".about.AboutActivity" android:name=".about.AboutActivity"
android:theme="@android:style/Theme.Holo.Light" /> android:theme="@android:style/Theme.Holo.Light" />

View File

@ -0,0 +1,292 @@
package org.dolphinemu.dolphinemu.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.fragments.EmulationFragment;
import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment;
import java.util.List;
public final class EmulationActivity extends Activity
{
private View mDecorView;
/**
* Handlers are a way to pass a message to an Activity telling it to do something
* on the UI thread. This Handler responds to any message, even blank ones, by
* hiding the system UI.
*/
private Handler mSystemUiHider = new Handler()
{
@Override
public void handleMessage(Message msg)
{
hideSystemUI();
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// 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)
{
boolean visible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
if (visible)
{
getActionBar().show();
hideSystemUiAfterDelay();
}
else
{
getActionBar().hide();
}
}
}
);
setContentView(R.layout.activity_emulation);
Intent gameToEmulate = getIntent();
String path = gameToEmulate.getStringExtra("SelectedGame");
String title = gameToEmulate.getStringExtra("SelectedTitle");
setTitle(title);
// Instantiate an EmulationFragment.
EmulationFragment emulationFragment = EmulationFragment.newInstance(path);
// Add fragment to the activity - this triggers all its lifecycle callbacks.
getFragmentManager().beginTransaction()
.add(R.id.frame_content, emulationFragment, EmulationFragment.FRAGMENT_TAG)
.commit();
}
@Override
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
// Give the user a few seconds to see what the controls look like, then hide them.
hideSystemUiAfterDelay();
}
@Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
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 boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_emulation, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
// Enable/Disable input overlay.
case R.id.enableInputOverlay:
{
EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager()
.findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
emulationFragment.toggleInputOverlayVisibility();
return true;
}
// Screenshot capturing
case R.id.takeScreenshot:
NativeLibrary.SaveScreenShot();
return true;
// Save state slots
case R.id.saveSlot1:
NativeLibrary.SaveState(0);
return true;
case R.id.saveSlot2:
NativeLibrary.SaveState(1);
return true;
case R.id.saveSlot3:
NativeLibrary.SaveState(2);
return true;
case R.id.saveSlot4:
NativeLibrary.SaveState(3);
return true;
case R.id.saveSlot5:
NativeLibrary.SaveState(4);
return true;
// Load state slots
case R.id.loadSlot1:
NativeLibrary.LoadState(0);
return true;
case R.id.loadSlot2:
NativeLibrary.LoadState(1);
return true;
case R.id.loadSlot3:
NativeLibrary.LoadState(2);
return true;
case R.id.loadSlot4:
NativeLibrary.LoadState(3);
return true;
case R.id.loadSlot5:
NativeLibrary.LoadState(4);
return true;
case R.id.exitEmulation:
{
// Create a confirmation method for quitting the current emulation instance.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.overlay_exit_emulation);
builder.setMessage(R.string.overlay_exit_emulation_confirm);
builder.setNegativeButton(R.string.no, null);
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
onDestroy();
}
});
builder.show();
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
// Gets button presses
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
int action = 0;
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:
action = NativeLibrary.ButtonState.RELEASED;
break;
default:
return false;
}
InputDevice input = event.getDevice();
boolean handled = NativeLibrary.onGamePadEvent(InputConfigFragment.getInputDesc(input), event.getKeyCode(), action);
return handled;
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event)
{
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0))
{
return super.dispatchGenericMotionEvent(event);
}
// Don't attempt to do anything if we are disconnecting a device.
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL)
return true;
InputDevice input = event.getDevice();
List<InputDevice.MotionRange> motions = input.getMotionRanges();
for (InputDevice.MotionRange range : motions)
{
NativeLibrary.onGamePadMoveEvent(InputConfigFragment.getInputDesc(input), range.getAxis(), event.getAxisValue(range.getAxis()));
}
return true;
}
private void hideSystemUiAfterDelay()
{
// Clear any pending hide events.
mSystemUiHider.removeMessages(0);
// Add a new hide event, to occur 3 seconds from now.
mSystemUiHider.sendEmptyMessageDelayed(0, 3000);
}
private void hideSystemUI()
{
mDecorView.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);
}
private void showSystemUI()
{
mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}

View File

@ -14,8 +14,8 @@ import android.view.ViewGroup;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog; import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog;
import org.dolphinemu.dolphinemu.emulation.EmulationActivity;
import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.model.GameDatabase;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
@ -215,6 +215,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
Intent intent = new Intent(view.getContext(), EmulationActivity.class); Intent intent = new Intent(view.getContext(), EmulationActivity.class);
intent.putExtra("SelectedGame", holder.path); intent.putExtra("SelectedGame", holder.path);
intent.putExtra("SelectedTitle", holder.title);
view.getContext().startActivity(intent); view.getContext().startActivity(intent);
} }

View File

@ -16,7 +16,7 @@ import com.squareup.picasso.Picasso;
import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.BuildConfig;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.emulation.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import de.hdodenhof.circleimageview.CircleImageView; import de.hdodenhof.circleimageview.CircleImageView;
@ -79,6 +79,8 @@ public final class GameDetailsDialog extends DialogFragment
Intent intent = new Intent(view.getContext(), EmulationActivity.class); Intent intent = new Intent(view.getContext(), EmulationActivity.class);
intent.putExtra("SelectedGame", getArguments().getString(ARGUMENT_GAME_PATH)); intent.putExtra("SelectedGame", getArguments().getString(ARGUMENT_GAME_PATH));
intent.putExtra("SelectedTitle", getArguments().getString(ARGUMENT_GAME_TITLE));
startActivity(intent); startActivity(intent);
} }
}); });

View File

@ -0,0 +1,114 @@
package org.dolphinemu.dolphinemu.fragments;
import android.app.Fragment;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.dolphinemu.dolphinemu.BuildConfig;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.emulation.overlay.InputOverlay;
public final class EmulationFragment extends Fragment
{
public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".emulation_fragment";
private static final String ARGUMENT_GAME_PATH = BuildConfig.APPLICATION_ID + ".game_path";
private SharedPreferences mPreferences;
private InputOverlay mInputOverlay;
public static EmulationFragment newInstance(String path)
{
EmulationFragment fragment = new EmulationFragment();
Bundle arguments = new Bundle();
arguments.putString(ARGUMENT_GAME_PATH, path);
fragment.setArguments(arguments);
return fragment;
}
/**
* Initialize anything that doesn't depend on the layout / views in here.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
}
/**
* Initialize the UI and start emulation in here.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
String path = getArguments().getString(ARGUMENT_GAME_PATH);
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay);
NativeLibrary.SetFilename(path);
// If the input overlay was previously disabled, then don't show it.
if (!mPreferences.getBoolean("showInputOverlay", true))
{
mInputOverlay.setVisibility(View.GONE);
}
return contents;
}
@Override
public void onStart()
{
super.onStart();
NativeLibrary.UnPauseEmulation();
}
@Override
public void onStop()
{
super.onStop();
NativeLibrary.PauseEmulation();
}
@Override
public void onDestroyView()
{
super.onDestroyView();
NativeLibrary.StopEmulation();
}
public void toggleInputOverlayVisibility()
{
SharedPreferences.Editor editor = mPreferences.edit();
// If the overlay is currently set to INVISIBLE
if (!mPreferences.getBoolean("showInputOverlay", false))
{
// Set it to VISIBLE
mInputOverlay.setVisibility(View.VISIBLE);
editor.putBoolean("showInputOverlay", true);
}
else
{
// Set it to INVISIBLE
mInputOverlay.setVisibility(View.GONE);
editor.putBoolean("showInputOverlay", false);
}
editor.apply();
}
}

View File

@ -0,0 +1,5 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frame_content">
</FrameLayout>

View File

@ -9,7 +9,7 @@
android:id="@+id/toolbar_game_list" android:id="@+id/toolbar_game_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/dolphin_blue" android:background="?android:colorPrimary"
android:minHeight="?android:attr/actionBarSize" android:minHeight="?android:attr/actionBarSize"
android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar" android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar"
android:elevation="6dp"/> android:elevation="6dp"/>

View File

@ -0,0 +1,22 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment">
<!-- This is what everything is rendered to during emulation -->
<org.dolphinemu.dolphinemu.emulation.NativeGLSurfaceView
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"/>
<!-- This is the onscreen input overlay -->
<org.dolphinemu.dolphinemu.emulation.overlay.InputOverlay
android:id="@+id/surface_input_overlay"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"/>
</FrameLayout>

View File

@ -0,0 +1,77 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.dolphinemu.dolphinemu.activities.EmulationActivity">
<!-- Enable/Disabe Input Overlay -->
<item
android:id="@+id/enableInputOverlay"
android:showAsAction="ifRoom"
android:title="@string/emulation_toggle_input"/>
<!-- Save State Slots -->
<item
android:id="@+id/takeScreenshot"
android:showAsAction="ifRoom"
android:title="@string/overlay_screenshot"/>
<item
android:id="@+id/saveStateRoot"
android:showAsAction="never"
android:title="@string/overlay_savestate">
<menu>
<item
android:id="@+id/saveSlot1"
android:title="@string/overlay_slot1"/>
<item
android:id="@+id/saveSlot2"
android:title="@string/overlay_slot2"/>
<item
android:id="@+id/saveSlot3"
android:title="@string/overlay_slot3"/>
<item
android:id="@+id/saveSlot4"
android:title="@string/overlay_slot4"/>
<item
android:id="@+id/saveSlot5"
android:title="@string/overlay_slot5"/>
</menu>
</item>
<!-- Load State Slots -->
<item
android:id="@+id/loadStateRoot"
android:showAsAction="never"
android:title="@string/overlay_loadstate">
<menu>
<item
android:id="@+id/loadSlot1"
android:title="@string/overlay_slot1"/>
<item
android:id="@+id/loadSlot2"
android:title="@string/overlay_slot2"/>
<item
android:id="@+id/loadSlot3"
android:title="@string/overlay_slot3"/>
<item
android:id="@+id/loadSlot4"
android:title="@string/overlay_slot4"/>
<item
android:id="@+id/loadSlot5"
android:title="@string/overlay_slot5"/>
</menu>
</item>
<item
android:id="@+id/exitEmulation"
android:showAsAction="ifRoom"
android:title="@string/overlay_exit_emulation">
</item>
</menu>

View File

@ -236,4 +236,7 @@
<string name="preferences_cpu">CPU Settings</string> <string name="preferences_cpu">CPU Settings</string>
<string name="preferences_input">Input Settings</string> <string name="preferences_input">Input Settings</string>
<string name="preferences_video">Video Settings</string> <string name="preferences_video">Video Settings</string>
<string name="emulation_title">Emulation Activity</string>
<string name="emulation_toggle_input">Toggle Input Overlay</string>
</resources> </resources>

View File

@ -22,23 +22,19 @@
</style> </style>
<style name="DolphinGamecube" parent="DolphinBase"> <style name="DolphinGamecube" parent="DolphinBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_gamecube</item> <item name="android:colorAccent">@color/dolphin_accent_gamecube</item>
</style> </style>
<style name="DolphinWiiware" parent="DolphinBase"> <style name="DolphinWiiware" parent="DolphinBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_wiiware</item> <item name="android:colorAccent">@color/dolphin_accent_wiiware</item>
</style> </style>
<!-- Inherit from the Base Dolphin Settings Theme--> <!-- Inherit from the Base Dolphin Settings Theme-->
<style name="DolphinSettingsWii" parent="DolphinSettingsBase"> <style name="DolphinSettingsWii" parent="DolphinSettingsBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_wii</item> <item name="android:colorAccent">@color/dolphin_accent_wii</item>
</style> </style>
<style name="DolphinSettingsGamecube" parent="DolphinSettingsBase"> <style name="DolphinSettingsGamecube" parent="DolphinSettingsBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_gamecube</item> <item name="android:colorAccent">@color/dolphin_accent_gamecube</item>
</style> </style>
@ -49,26 +45,39 @@
<!-- Themes for Dialogs --> <!-- Themes for Dialogs -->
<style name="DolphinDialogBase" parent="android:Theme.Material.Light.Dialog"> <style name="DolphinDialogBase" parent="android:Theme.Material.Light.Dialog">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">@color/dolphin_blue</item> <item name="android:colorPrimary">@color/dolphin_blue</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">@color/dolphin_blue_dark</item> <item name="android:colorPrimaryDark">@color/dolphin_blue_dark</item>
</style> </style>
<!-- Inherit from the Base Dolphin Dialog Theme--> <!-- Inherit from the Base Dolphin Dialog Theme-->
<style name="DolphinDialogWii" parent="DolphinDialogBase"> <style name="DolphinDialogWii" parent="DolphinDialogBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_wii</item> <item name="android:colorAccent">@color/dolphin_accent_wii</item>
</style> </style>
<style name="DolphinDialogGamecube" parent="DolphinDialogBase"> <style name="DolphinDialogGamecube" parent="DolphinDialogBase">
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/dolphin_accent_gamecube</item> <item name="android:colorAccent">@color/dolphin_accent_gamecube</item>
</style> </style>
<style name="DolphinDialogWiiware" parent="DolphinDialogBase"> <style name="DolphinDialogWiiware" parent="DolphinDialogBase">
<!-- theme UI controls like checkboxes and text fields --> <item name="android:colorAccent">@color/dolphin_accent_wiiware</item>
</style>
<style name="DolphinEmulationBase" parent="android:Theme.Material.Light.DarkActionBar">
<item name="android:colorPrimary">@color/dolphin_blue</item>
<item name="android:colorPrimaryDark">@color/dolphin_blue_dark</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
<!-- Inherit from the Base Dolphin Emulation Theme-->
<style name="DolphinEmulationWii" parent="DolphinEmulationBase">
<item name="android:colorAccent">@color/dolphin_accent_wii</item>
</style>
<style name="DolphinEmulationGamecube" parent="DolphinEmulationBase">
<item name="android:colorAccent">@color/dolphin_accent_gamecube</item>
</style>
<style name="DolphinEmulationWiiware" parent="DolphinEmulationBase">
<item name="android:colorAccent">@color/dolphin_accent_wiiware</item> <item name="android:colorAccent">@color/dolphin_accent_wiiware</item>
</style> </style>
</resources> </resources>