diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml
index 96e24cb5a..b47792f2c 100644
--- a/Android/app/src/main/AndroidManifest.xml
+++ b/Android/app/src/main/AndroidManifest.xml
@@ -44,6 +44,11 @@
android:label="@string/ScanRomsActivity_title"
android:theme="@style/Theme.Project64.Apearance" >
+
+
getUnmappableKeyCodes ()
+ {
+ List unmappables = new ArrayList();
+ unmappables.add( KeyEvent.KEYCODE_MENU );
+ if( IS_HONEYCOMB )
+ {
+ // Back key is needed to show/hide the action bar in HC+
+ unmappables.add( KeyEvent.KEYCODE_BACK );
+ }
+ if( !MapVolumeKeys )
+ {
+ unmappables.add( KeyEvent.KEYCODE_VOLUME_UP );
+ unmappables.add( KeyEvent.KEYCODE_VOLUME_DOWN );
+ unmappables.add( KeyEvent.KEYCODE_VOLUME_MUTE );
+ }
+ return unmappables;
+ }
+
public static ArrayList getStorageDirectories()
{
BufferedReader bufReader = null;
diff --git a/Android/app/src/main/java/emu/project64/game/GameLifecycleHandler.java b/Android/app/src/main/java/emu/project64/game/GameLifecycleHandler.java
index 8583b0f60..04486414a 100644
--- a/Android/app/src/main/java/emu/project64/game/GameLifecycleHandler.java
+++ b/Android/app/src/main/java/emu/project64/game/GameLifecycleHandler.java
@@ -11,9 +11,7 @@ import java.util.ArrayList;
import java.util.Set;
import emu.project64.AndroidDevice;
-import emu.project64.Project64Application;
import emu.project64.R;
-import emu.project64.hack.MogaHack;
import emu.project64.input.AbstractController;
import emu.project64.input.PeripheralController;
import emu.project64.input.TouchController;
@@ -23,12 +21,8 @@ import emu.project64.input.provider.AbstractProvider;
import emu.project64.input.provider.AxisProvider;
import emu.project64.input.provider.KeyProvider;
import emu.project64.input.provider.KeyProvider.ImeFormula;
-import emu.project64.input.provider.MogaProvider;
import emu.project64.jni.NativeExports;
import emu.project64.jni.NativeVideo;
-import emu.project64.jni.NativeXperiaTouchpad;
-import emu.project64.jni.SettingsID;
-import emu.project64.jni.SystemEvent;
import emu.project64.jni.UISettingID;
import emu.project64.jni.VideoSettingID;
import emu.project64.persistent.ConfigFile;
@@ -39,19 +33,16 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
-import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
-import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
@@ -69,7 +60,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
private ArrayList mControllers;
private VisibleTouchMap mTouchscreenMap;
private KeyProvider mKeyProvider;
- private Controller mMogaController;
// Internal flags
private boolean mStarted = false;
@@ -87,20 +77,14 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
{
mActivity = activity;
mControllers = new ArrayList();
- mMogaController = Controller.getInstance(mActivity);
}
- @TargetApi(11)
public void onCreateBegin(Bundle savedInstanceState)
{
if (LOG_GAMELIFECYCLEHANDLER)
{
Log.i("GameLifecycleHandler", "onCreateBegin - Start");
}
- // Initialize MOGA controller API
- // TODO: Remove hack after MOGA SDK is fixed
- // mMogaController.init();
- MogaHack.init(mMogaController, mActivity);
// For Honeycomb, let the action bar overlay the rendered view (rather
// than squeezing it)
@@ -122,7 +106,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
}
}
- @TargetApi(11)
public void onCreateEnd(Bundle savedInstanceState)
{
if (LOG_GAMELIFECYCLEHANDLER)
@@ -157,13 +140,22 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
mSurface.getHolder().addCallback(this);
mSurface.createGLContext((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE));
- //CreateTouchScreenControls();
- //View inputSource = mOverlay;
- //initControllers(inputSource);
+ // Configure the action bar introduced in higher Android versions
+ /*if (AndroidDevice.IS_ACTION_BAR_AVAILABLE)
+ {
+ mActivity.getActionBar().hide();
+ ColorDrawable color = new ColorDrawable(Color.parseColor("#303030"));
+ color.setAlpha(50 /*mGlobalPrefs.displayActionBarTransparency*/ /*);
+ mActivity.getActionBar().setBackgroundDrawable(color);
+ }
- // Override the peripheral controllers' key provider, to add some extra
- // functionality
- //inputSource.setOnKeyListener(this);
+ CreateTouchScreenControls();*/
+
+ // Initialize user interface devices
+ initControllers(mOverlay);
+
+ // Override the peripheral controllers' key provider, to add some extra functionality
+ mOverlay.setOnKeyListener(this);
if (LOG_GAMELIFECYCLEHANDLER)
{
Log.i("GameLifecycleHandler", "onCreateEnd done");
@@ -186,8 +178,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
}
mIsResumed = true;
tryRunning();
-
- mMogaController.onResume();
}
@Override
@@ -325,7 +315,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
{
Log.i("GameLifecycleHandler", "onDestroy");
}
- mMogaController.exit();
}
public void onSettingDone()
@@ -343,30 +332,27 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
private void CreateTouchScreenControls()
{
- /*boolean isTouchscreenAnimated = false; // mGlobalPrefs.isTouchscreenAnimated
- boolean isTouchscreenHidden = false; // !isTouchscreenEnabled ||
- // globalPrefs.touchscreenTransparency
- // == 0;
+ boolean isTouchscreenAnimated = false; //mGlobalPrefs.isTouchscreenAnimated
+ boolean isTouchscreenHidden = false; //!isTouchscreenEnabled || globalPrefs.touchscreenTransparency == 0;
String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
- ConfigFile touchscreenConfigFile = new ConfigFile(touchscreenProfiles_cfg);
+ ConfigFile touchscreenConfigFile = new ConfigFile( touchscreenProfiles_cfg );
ConfigSection section = touchscreenConfigFile.get(mlayout);
if (section == null)
{
mlayout = "Analog";
section = touchscreenConfigFile.get(mlayout);
}
- Profile touchscreenProfile = new Profile(true, section);
+ Profile touchscreenProfile = new Profile( true, section);
int touchscreenTransparency = 100;
String touchscreenSkinsDir = AndroidDevice.PACKAGE_DIRECTORY + "/skins/touchscreen";
String touchscreenSkin = touchscreenSkinsDir + "/Outline";
- // The touch map and overlay are needed to display frame rate and/or
- // controls
- mTouchscreenMap = new VisibleTouchMap(mActivity.getResources());
- mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency);
- mOverlay.initialize(mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated);*/
- }
+ // The touch map and overlay are needed to display frame rate and/or controls
+ mTouchscreenMap = new VisibleTouchMap( mActivity.getResources() );
+ mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency );
+ mOverlay.initialize( mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated );
+ }
@Override
public boolean onKey(View view, int keyCode, KeyEvent event)
@@ -385,33 +371,32 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
private void initControllers(View inputSource)
{
// By default, send Player 1 rumbles through phone vibrator
- /*Vibrator vibrator = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE);
+ Vibrator vibrator = (Vibrator) mActivity.getSystemService( Context.VIBRATOR_SERVICE );
int touchscreenAutoHold = 0;
boolean isTouchscreenFeedbackEnabled = false;
Set autoHoldableButtons = null;
// Create the touchscreen controller
- TouchController touchscreenController = new TouchController(mTouchscreenMap, inputSource, mOverlay, vibrator,
- touchscreenAutoHold, isTouchscreenFeedbackEnabled, autoHoldableButtons);
- mControllers.add(touchscreenController);
+ TouchController touchscreenController = new TouchController( mTouchscreenMap,
+ inputSource, mOverlay, vibrator, touchscreenAutoHold,
+ isTouchscreenFeedbackEnabled, autoHoldableButtons );
+ mControllers.add( touchscreenController );
// Create the input providers shared among all peripheral controllers
- String profile_name = NativeExports.UISettingsLoadString(UISettingID.Controller_CurrentProfile.getValue());
- ConfigFile ControllerConfigFile = new ConfigFile(
- NativeExports.UISettingsLoadString(UISettingID.Controller_ConfigFile.getValue()));
- ConfigSection section = ControllerConfigFile.get(profile_name);
+ String profile_name = NativeExports.SettingsLoadString(UISettingID.ControllerCurrentProfile.toString());
+ ConfigFile ControllerConfigFile = new ConfigFile(NativeExports.SettingsLoadString(UISettingID.ControllerConfigFile.toString()));
+ ConfigSection section = ControllerConfigFile.get( profile_name );
if (section != null)
{
- Profile ControllerProfile = new Profile(false, section);
- InputMap map = new InputMap(ControllerProfile.get("map"));
+ Profile ControllerProfile = new Profile( false, section );
+ InputMap map = new InputMap( ControllerProfile.get( "map" ) );
- mKeyProvider = new KeyProvider(inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes());
- MogaProvider mogaProvider = new MogaProvider(mMogaController);
- AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider(inputSource) : null;
- int Deadzone = NativeExports.UISettingsLoadDword(UISettingID.Controller_Deadzone.getValue());
- int Sensitivity = NativeExports.UISettingsLoadDword(UISettingID.Controller_Sensitivity.getValue());
- mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider, mogaProvider));
- }*/
+ mKeyProvider = new KeyProvider( inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
+ AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider( inputSource ) : null;
+ int Deadzone = NativeExports.SettingsLoadDword(UISettingID.ControllerDeadzone.toString());
+ int Sensitivity = NativeExports.SettingsLoadDword(UISettingID.ControllerSensitivity.toString());
+ mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider));
+ }
}
private void tryRunning()
diff --git a/Android/app/src/main/java/emu/project64/profile/ControllerProfileActivity.java b/Android/app/src/main/java/emu/project64/profile/ControllerProfileActivity.java
new file mode 100644
index 000000000..eb308f74a
--- /dev/null
+++ b/Android/app/src/main/java/emu/project64/profile/ControllerProfileActivity.java
@@ -0,0 +1,471 @@
+package emu.project64.profile;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import java.util.ArrayList;
+
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.input.AbstractController;
+import emu.project64.input.map.InputMap;
+import emu.project64.input.provider.AbstractProvider;
+import emu.project64.input.provider.AxisProvider;
+import emu.project64.input.provider.KeyProvider;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.UISettingID;
+import emu.project64.persistent.ConfigFile;
+
+public class ControllerProfileActivity extends AppCompatActivity implements AbstractProvider.OnInputListener, View.OnClickListener
+{
+ // Visual settings
+ private static final float UNMAPPED_BUTTON_ALPHA = 0.2f;
+ private static final int UNMAPPED_BUTTON_FILTER = 0x66FFFFFF;
+ private static final int MIN_LAYOUT_WIDTH_DP = 480;
+
+ // Controller profile objects
+ private ConfigFile mConfigFile;
+ private Profile mProfile;
+
+ // Input listening
+ private KeyProvider mKeyProvider;
+ private AxisProvider mAxisProvider;
+
+ // Widgets
+ private final Button[] mN64Buttons = new Button[InputMap.NUM_MAPPABLES];
+ private TextView mFeedbackText;
+
+ @Override
+ public void onCreate( Bundle savedInstanceState )
+ {
+ super.onCreate(savedInstanceState);
+
+ // Load the profile; fail fast if there are any programmer usage errors
+ String name = NativeExports.SettingsLoadString(UISettingID.ControllerCurrentProfile.toString());
+ if(TextUtils.isEmpty(name))
+ {
+ throw new Error("Invalid usage: profile name cannot be null or empty");
+ }
+ mConfigFile = new ConfigFile(NativeExports.SettingsLoadString(UISettingID.ControllerConfigFile.toString()));
+ ConfigFile.ConfigSection Section = mConfigFile.get( name );
+ if (Section == null)
+ {
+ //profile not found create it
+ mConfigFile.put(name, "map", "-");
+ Section = mConfigFile.get( name );
+ if(Section == null)
+ {
+ throw new Error( "Invalid usage: profile name not found in config file" );
+ }
+ }
+ mProfile = new Profile(false, Section);
+
+ // Set up input listeners
+ mKeyProvider = new KeyProvider( KeyProvider.ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
+ mKeyProvider.registerListener( this );
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ mAxisProvider = new AxisProvider();
+ mAxisProvider.registerListener( this );
+ }
+
+ // Initialize the layout
+ initLayoutDefault();
+
+ // Refresh everything
+ refreshAllButtons();
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+
+ // Lazily persist the profile data; only need to do it on pause
+ mProfile.writeTo( mConfigFile );
+ mConfigFile.save();
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ if (item.getItemId() == android.R.id.home)
+ {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onBackPressed()
+ {
+ finish();
+ }
+
+ private void initLayoutDefault()
+ {
+ WindowManager manager = (WindowManager) getSystemService( Context.WINDOW_SERVICE );
+ DisplayMetrics metrics = new DisplayMetrics();
+ manager.getDefaultDisplay().getMetrics( metrics );
+ float ScaleFactor = (float) DisplayMetrics.DENSITY_DEFAULT / (float) metrics.densityDpi;
+ int widthDp = Math.round( metrics.widthPixels * ScaleFactor );
+
+ // For narrow screens, use an alternate layout
+ if( widthDp < MIN_LAYOUT_WIDTH_DP )
+ {
+ setContentView( R.layout.controller_profile_activity_port );
+ }
+ else
+ {
+ setContentView( R.layout.controller_profile_activity );
+ }
+
+ // Add the tool bar to the activity (which supports the fancy menu/arrow animation)
+ Toolbar toolbar = findViewById( R.id.toolbar );
+ toolbar.setTitle( getString(R.string.gamepad_title) );
+ setSupportActionBar( toolbar );
+ ActionBar actionbar = getSupportActionBar();
+
+ if (AndroidDevice.IS_ICE_CREAM_SANDWICH)
+ {
+ actionbar.setHomeButtonEnabled(true);
+ actionbar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ // Initialize and refresh the widgets
+ initWidgets();
+ }
+
+ private void initWidgets()
+ {
+ // Get the text view object
+ mFeedbackText = findViewById( R.id.textFeedback );
+ mFeedbackText.setText( "" );
+
+ // Create a button list to simplify highlighting and mapping
+ setupButton( R.id.buttonDR, AbstractController.DPD_R );
+ setupButton( R.id.buttonDL, AbstractController.DPD_L );
+ setupButton( R.id.buttonDD, AbstractController.DPD_D );
+ setupButton( R.id.buttonDU, AbstractController.DPD_U );
+ setupButton( R.id.buttonS, AbstractController.START );
+ setupButton( R.id.buttonZ, AbstractController.BTN_Z );
+ setupButton( R.id.buttonB, AbstractController.BTN_B );
+ setupButton( R.id.buttonA, AbstractController.BTN_A );
+ setupButton( R.id.buttonCR, AbstractController.CPD_R );
+ setupButton( R.id.buttonCL, AbstractController.CPD_L );
+ setupButton( R.id.buttonCD, AbstractController.CPD_D );
+ setupButton( R.id.buttonCU, AbstractController.CPD_U );
+ setupButton( R.id.buttonR, AbstractController.BTN_R );
+ setupButton( R.id.buttonL, AbstractController.BTN_L );
+ setupButton( R.id.buttonAR, InputMap.AXIS_R );
+ setupButton( R.id.buttonAL, InputMap.AXIS_L );
+ setupButton( R.id.buttonAD, InputMap.AXIS_D );
+ setupButton( R.id.buttonAU, InputMap.AXIS_U );
+ }
+
+ private void setupButton( int resId, int index )
+ {
+ mN64Buttons[index] = findViewById( resId );
+ if( mN64Buttons[index] != null )
+ {
+ mN64Buttons[index].setOnClickListener( this );
+ }
+ }
+
+ @Override
+ public void onClick(View view)
+ {
+ // Handle button clicks in the mapping screen
+ for( int i = 0; i < mN64Buttons.length; i++ )
+ {
+ // Find the button that was pressed
+ if( view.equals( mN64Buttons[i] ) )
+ {
+ // Popup a dialog to listen to input codes from user
+ Button button = (Button) view;
+ popupListener( button.getText(), i );
+ }
+ }
+ }
+
+ private interface PromptInputCodeListener
+ {
+ void onDialogClosed( int inputCode, int hardwareId, int which );
+ }
+
+ /**
+ * Open a dialog to prompt the user for an input code.
+ *
+ * @param context The activity context.
+ * @param title The title of the dialog.
+ * @param message The message to be shown inside the dialog.
+ * @param neutralButtonText The text to be shown on the neutral button, or null.
+ * @param listener The listener to process the input code, when provided.
+ */
+ public static void promptInputCode( Context context, CharSequence title, CharSequence message,
+ CharSequence neutralButtonText, final PromptInputCodeListener listener )
+ {
+ final ArrayList providers = new ArrayList<>();
+
+ // Create a widget to dispatch key/motion event data
+ FrameLayout view = new FrameLayout( context );
+ EditText dummyImeListener = new EditText( context );
+ dummyImeListener.setVisibility( View.INVISIBLE );
+ dummyImeListener.setHeight( 0 );
+ view.addView( dummyImeListener );
+
+ // Set the focus parameters of the view so that it will dispatch events
+ view.setFocusable( true );
+ view.setFocusableInTouchMode( true );
+ view.requestFocus();
+
+ // Create the input event providers
+ providers.add( new KeyProvider(view,KeyProvider.ImeFormula.DEFAULT,AndroidDevice.getUnmappableKeyCodes()));
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ providers.add( new AxisProvider(view));
+ }
+
+ // Notify the client when the user clicks the dialog's positive button
+ DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick( DialogInterface dialog, int which )
+ {
+ for( AbstractProvider provider : providers )
+ {
+ provider.unregisterAllListeners();
+ }
+ listener.onDialogClosed( 0, 0, which );
+ }
+ };
+
+ final AlertDialog dialog = new AlertDialog.Builder( context ).setTitle( title ).setMessage( message ).setCancelable( false )
+ .setNegativeButton( context.getString( android.R.string.cancel ), clickListener )
+ .setPositiveButton( context.getString( android.R.string.ok ), clickListener )
+ .setNeutralButton( neutralButtonText, clickListener ).setPositiveButton( null, null )
+ .setView( view ).create();
+
+ AbstractProvider.OnInputListener inputListener = new AbstractProvider.OnInputListener()
+ {
+ @Override
+ public void onInput( int[] inputCodes, float[] strengths, int hardwareId )
+ {
+ if( inputCodes == null || strengths == null )
+ return;
+
+ // Find the strongest input
+ float maxStrength = 0;
+ int strongestInputCode = 0;
+ for( int i = 0; i < inputCodes.length; i++ )
+ {
+ // Identify the strongest input
+ float strength = strengths[i];
+ if( strength > maxStrength )
+ {
+ maxStrength = strength;
+ strongestInputCode = inputCodes[i];
+ }
+ }
+
+ // Call the overloaded method with the strongest found
+ onInput( strongestInputCode, maxStrength, hardwareId );
+ }
+
+ @Override
+ public void onInput( int inputCode, float strength, int hardwareId )
+ {
+ if( inputCode != 0 && strength > AbstractProvider.STRENGTH_THRESHOLD )
+ {
+ for( AbstractProvider provider : providers )
+ provider.unregisterAllListeners();
+ listener.onDialogClosed( inputCode, hardwareId, DialogInterface.BUTTON_POSITIVE );
+ dialog.dismiss();
+ }
+ }
+ };
+
+ // Connect the upstream event listeners
+ for( AbstractProvider provider : providers )
+ {
+ provider.registerListener( inputListener );
+ }
+
+ // Launch the dialog
+ dialog.show();
+ }
+
+ private void popupListener( CharSequence title, final int index )
+ {
+ final InputMap map = new InputMap( mProfile.get( "map" ) );
+ String message = getString( R.string.inputMapActivity_popupMessage,map.getMappedCodeInfo( index ) );
+ String btnText = getString( R.string.inputMapActivity_popupUnmap );
+
+ PromptInputCodeListener listener = new PromptInputCodeListener()
+ {
+ @Override
+ public void onDialogClosed( int inputCode, int hardwareId, int which )
+ {
+ if( which != DialogInterface.BUTTON_NEGATIVE )
+ {
+ if( which == DialogInterface.BUTTON_POSITIVE )
+ {
+ map.map( inputCode, index );
+ }
+ else
+ {
+ map.unmapCommand( index );
+ }
+ mProfile.put( "map", map.serialize() );
+ refreshAllButtons();
+ }
+ }
+ };
+ promptInputCode( this, title, message, btnText, listener);
+ }
+
+ @Override
+ public boolean onKeyDown( int keyCode, KeyEvent event )
+ {
+ return mKeyProvider.onKey( keyCode, event ) || super.onKeyDown( keyCode, event );
+ }
+
+ @Override
+ public boolean onKeyUp( int keyCode, KeyEvent event )
+ {
+ return mKeyProvider.onKey( keyCode, event ) || super.onKeyUp( keyCode, event );
+ }
+
+ @Override
+ public boolean onGenericMotionEvent( MotionEvent event )
+ {
+ if( !AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ return false;
+ }
+ return mAxisProvider.onGenericMotion( event ) || super.onGenericMotionEvent( event );
+ }
+
+ @Override
+ public void onInput(int inputCode, float strength, int hardwareId)
+ {
+ refreshButton( inputCode, strength );
+ refreshFeedbackText( inputCode, strength );
+ }
+
+ @Override
+ public void onInput(int[] inputCodes, float[] strengths, int hardwareId)
+ {
+ float maxStrength = AbstractProvider.STRENGTH_THRESHOLD;
+ int strongestInputCode = 0;
+ for( int i = 0; i < inputCodes.length; i++ )
+ {
+ int inputCode = inputCodes[i];
+ float strength = strengths[i];
+
+ // Cache the strongest input
+ if( strength > maxStrength )
+ {
+ maxStrength = strength;
+ strongestInputCode = inputCode;
+ }
+
+ refreshButton( inputCode, strength );
+ }
+ refreshFeedbackText( strongestInputCode, maxStrength );
+ }
+
+ private void refreshFeedbackText( int inputCode, float strength )
+ {
+ // Update the feedback text (not all layouts include this, so check null)
+ if( mFeedbackText != null )
+ {
+ mFeedbackText.setText( strength > AbstractProvider.STRENGTH_THRESHOLD ? AbstractProvider.getInputName( inputCode ) : "" );
+ }
+ }
+
+ private void refreshButton( int inputCode, float strength )
+ {
+ InputMap map = new InputMap( mProfile.get( "map" ) );
+ int command = map.get( inputCode );
+ if( command != InputMap.UNMAPPED )
+ {
+ Button button = mN64Buttons[command];
+ refreshButton( button, strength, true );
+ }
+ }
+
+ private void refreshButton( Button button, float strength, boolean isMapped )
+ {
+ if( button != null )
+ {
+ button.setPressed( strength > AbstractProvider.STRENGTH_THRESHOLD );
+
+ // Fade any buttons that aren't mapped
+ if( AndroidDevice.IS_HONEYCOMB )
+ {
+ if( isMapped )
+ {
+ button.setAlpha( 1 );
+ }
+ else
+ {
+ button.setAlpha( UNMAPPED_BUTTON_ALPHA );
+ }
+ }
+ else
+ {
+ // For older APIs try something similar (not quite the same)
+ if( isMapped )
+ {
+ button.getBackground().clearColorFilter();
+ }
+ else
+ {
+ button.getBackground().setColorFilter( UNMAPPED_BUTTON_FILTER, PorterDuff.Mode.MULTIPLY );
+ }
+ button.invalidate();
+ }
+ }
+ }
+
+ private void refreshAllButtons()
+ {
+ final InputMap map = new InputMap( mProfile.get( "map" ) );
+ for( int i = 0; i < mN64Buttons.length; i++ )
+ {
+ refreshButton( mN64Buttons[i], 0, map.isMapped( i ) );
+ }
+ }
+}
diff --git a/Android/app/src/main/java/emu/project64/settings/BaseSettingsFragment.java b/Android/app/src/main/java/emu/project64/settings/BaseSettingsFragment.java
index cf55120f2..3e0f6cb59 100644
--- a/Android/app/src/main/java/emu/project64/settings/BaseSettingsFragment.java
+++ b/Android/app/src/main/java/emu/project64/settings/BaseSettingsFragment.java
@@ -2,6 +2,7 @@ package emu.project64.settings;
import emu.project64.R;
import emu.project64.SplashActivity;
+import emu.project64.profile.ControllerProfileActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
@@ -61,6 +62,9 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat
}
else if (preference.getKey().equals("settings_gamepad_screen"))
{
+ final AppCompatActivity activity = (AppCompatActivity)getActivity();
+ Intent intent = new Intent( activity, ControllerProfileActivity.class );
+ activity.startActivity( intent );
}
else if (preference.getKey().equals("settings_video"))
{
diff --git a/Android/app/src/main/res/layout/controller_profile_activity.xml b/Android/app/src/main/res/layout/controller_profile_activity.xml
index fb8ab95a7..db1927cee 100644
--- a/Android/app/src/main/res/layout/controller_profile_activity.xml
+++ b/Android/app/src/main/res/layout/controller_profile_activity.xml
@@ -1,21 +1,20 @@
-
-
+
+ android:theme="@style/Theme.Project64.ToolBar"
+ app:titleTextAppearance="@style/Theme.Project64.ToolBar.TitleText"
+ />