Android: Start to get controller working

This commit is contained in:
zilmar 2023-12-07 16:14:04 +10:30
parent de1288bdca
commit 10b550bb63
7 changed files with 549 additions and 64 deletions

View File

@ -44,6 +44,11 @@
android:label="@string/ScanRomsActivity_title"
android:theme="@style/Theme.Project64.Apearance" >
</activity>
<activity
android:name="emu.project64.profile.ControllerProfileActivity"
android:label="@string/ControllerProfileActivity_title"
android:theme="@style/Theme.Project64.Apearance" >
</activity>
<activity
android:name="emu.project64.game.GameActivity"
android:configChanges="keyboardHidden|orientation|screenSize"

View File

@ -16,6 +16,7 @@ import android.graphics.Point;
import android.os.Build;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.WindowManager;
@SuppressLint("NewApi")
@ -47,6 +48,8 @@ public class AndroidDevice
public static final boolean IS_ACTION_BAR_AVAILABLE = AndroidDevice.IS_HONEYCOMB;
public static boolean MapVolumeKeys = false;
public final static int nativeWidth;
public final static int nativeHeight;
static
@ -72,6 +75,24 @@ public class AndroidDevice
nativeHeight = _nativeHeight;
}
public static List<Integer> getUnmappableKeyCodes ()
{
List<Integer> unmappables = new ArrayList<Integer>();
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<String> getStorageDirectories()
{
BufferedReader bufReader = null;

View File

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

View File

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

View File

@ -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"))
{

View File

@ -1,21 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:focusable="false"
android:focusableInTouchMode="false"
>
<android.support.v7.widget.Toolbar
android:focusableInTouchMode="false">
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/background_actionbar"
android:theme="@style/Theme.Project64.ToolBar" />
android:theme="@style/Theme.Project64.ToolBar"
app:titleTextAppearance="@style/Theme.Project64.ToolBar.TitleText"
/>
<!--
***********************************************************************************

View File

@ -8,7 +8,7 @@
android:focusable="false"
android:focusableInTouchMode="false"
>
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"