Android: Start to get controller working
This commit is contained in:
parent
de1288bdca
commit
10b550bb63
|
@ -44,6 +44,11 @@
|
||||||
android:label="@string/ScanRomsActivity_title"
|
android:label="@string/ScanRomsActivity_title"
|
||||||
android:theme="@style/Theme.Project64.Apearance" >
|
android:theme="@style/Theme.Project64.Apearance" >
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="emu.project64.profile.ControllerProfileActivity"
|
||||||
|
android:label="@string/ControllerProfileActivity_title"
|
||||||
|
android:theme="@style/Theme.Project64.Apearance" >
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="emu.project64.game.GameActivity"
|
android:name="emu.project64.game.GameActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
|
|
|
@ -16,6 +16,7 @@ import android.graphics.Point;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
|
@ -47,6 +48,8 @@ public class AndroidDevice
|
||||||
|
|
||||||
public static final boolean IS_ACTION_BAR_AVAILABLE = AndroidDevice.IS_HONEYCOMB;
|
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 nativeWidth;
|
||||||
public final static int nativeHeight;
|
public final static int nativeHeight;
|
||||||
static
|
static
|
||||||
|
@ -72,6 +75,24 @@ public class AndroidDevice
|
||||||
nativeHeight = _nativeHeight;
|
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()
|
public static ArrayList<String> getStorageDirectories()
|
||||||
{
|
{
|
||||||
BufferedReader bufReader = null;
|
BufferedReader bufReader = null;
|
||||||
|
|
|
@ -11,9 +11,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import emu.project64.AndroidDevice;
|
import emu.project64.AndroidDevice;
|
||||||
import emu.project64.Project64Application;
|
|
||||||
import emu.project64.R;
|
import emu.project64.R;
|
||||||
import emu.project64.hack.MogaHack;
|
|
||||||
import emu.project64.input.AbstractController;
|
import emu.project64.input.AbstractController;
|
||||||
import emu.project64.input.PeripheralController;
|
import emu.project64.input.PeripheralController;
|
||||||
import emu.project64.input.TouchController;
|
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.AxisProvider;
|
||||||
import emu.project64.input.provider.KeyProvider;
|
import emu.project64.input.provider.KeyProvider;
|
||||||
import emu.project64.input.provider.KeyProvider.ImeFormula;
|
import emu.project64.input.provider.KeyProvider.ImeFormula;
|
||||||
import emu.project64.input.provider.MogaProvider;
|
|
||||||
import emu.project64.jni.NativeExports;
|
import emu.project64.jni.NativeExports;
|
||||||
import emu.project64.jni.NativeVideo;
|
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.UISettingID;
|
||||||
import emu.project64.jni.VideoSettingID;
|
import emu.project64.jni.VideoSettingID;
|
||||||
import emu.project64.persistent.ConfigFile;
|
import emu.project64.persistent.ConfigFile;
|
||||||
|
@ -39,19 +33,16 @@ import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.view.WindowManager.LayoutParams;
|
import android.view.WindowManager.LayoutParams;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
@ -69,7 +60,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
private ArrayList<AbstractController> mControllers;
|
private ArrayList<AbstractController> mControllers;
|
||||||
private VisibleTouchMap mTouchscreenMap;
|
private VisibleTouchMap mTouchscreenMap;
|
||||||
private KeyProvider mKeyProvider;
|
private KeyProvider mKeyProvider;
|
||||||
private Controller mMogaController;
|
|
||||||
|
|
||||||
// Internal flags
|
// Internal flags
|
||||||
private boolean mStarted = false;
|
private boolean mStarted = false;
|
||||||
|
@ -87,20 +77,14 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
{
|
{
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
mControllers = new ArrayList<AbstractController>();
|
mControllers = new ArrayList<AbstractController>();
|
||||||
mMogaController = Controller.getInstance(mActivity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(11)
|
|
||||||
public void onCreateBegin(Bundle savedInstanceState)
|
public void onCreateBegin(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
if (LOG_GAMELIFECYCLEHANDLER)
|
if (LOG_GAMELIFECYCLEHANDLER)
|
||||||
{
|
{
|
||||||
Log.i("GameLifecycleHandler", "onCreateBegin - Start");
|
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
|
// For Honeycomb, let the action bar overlay the rendered view (rather
|
||||||
// than squeezing it)
|
// than squeezing it)
|
||||||
|
@ -122,7 +106,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(11)
|
|
||||||
public void onCreateEnd(Bundle savedInstanceState)
|
public void onCreateEnd(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
if (LOG_GAMELIFECYCLEHANDLER)
|
if (LOG_GAMELIFECYCLEHANDLER)
|
||||||
|
@ -157,13 +140,22 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
mSurface.getHolder().addCallback(this);
|
mSurface.getHolder().addCallback(this);
|
||||||
mSurface.createGLContext((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE));
|
mSurface.createGLContext((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE));
|
||||||
|
|
||||||
//CreateTouchScreenControls();
|
// Configure the action bar introduced in higher Android versions
|
||||||
//View inputSource = mOverlay;
|
/*if (AndroidDevice.IS_ACTION_BAR_AVAILABLE)
|
||||||
//initControllers(inputSource);
|
{
|
||||||
|
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
|
CreateTouchScreenControls();*/
|
||||||
// functionality
|
|
||||||
//inputSource.setOnKeyListener(this);
|
// Initialize user interface devices
|
||||||
|
initControllers(mOverlay);
|
||||||
|
|
||||||
|
// Override the peripheral controllers' key provider, to add some extra functionality
|
||||||
|
mOverlay.setOnKeyListener(this);
|
||||||
if (LOG_GAMELIFECYCLEHANDLER)
|
if (LOG_GAMELIFECYCLEHANDLER)
|
||||||
{
|
{
|
||||||
Log.i("GameLifecycleHandler", "onCreateEnd done");
|
Log.i("GameLifecycleHandler", "onCreateEnd done");
|
||||||
|
@ -186,8 +178,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
}
|
}
|
||||||
mIsResumed = true;
|
mIsResumed = true;
|
||||||
tryRunning();
|
tryRunning();
|
||||||
|
|
||||||
mMogaController.onResume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -325,7 +315,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
{
|
{
|
||||||
Log.i("GameLifecycleHandler", "onDestroy");
|
Log.i("GameLifecycleHandler", "onDestroy");
|
||||||
}
|
}
|
||||||
mMogaController.exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSettingDone()
|
public void onSettingDone()
|
||||||
|
@ -343,10 +332,8 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
|
|
||||||
private void CreateTouchScreenControls()
|
private void CreateTouchScreenControls()
|
||||||
{
|
{
|
||||||
/*boolean isTouchscreenAnimated = false; // mGlobalPrefs.isTouchscreenAnimated
|
boolean isTouchscreenAnimated = false; //mGlobalPrefs.isTouchscreenAnimated
|
||||||
boolean isTouchscreenHidden = false; // !isTouchscreenEnabled ||
|
boolean isTouchscreenHidden = false; //!isTouchscreenEnabled || globalPrefs.touchscreenTransparency == 0;
|
||||||
// globalPrefs.touchscreenTransparency
|
|
||||||
// == 0;
|
|
||||||
String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
|
String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
|
||||||
String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
|
String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
|
||||||
ConfigFile touchscreenConfigFile = new ConfigFile( touchscreenProfiles_cfg );
|
ConfigFile touchscreenConfigFile = new ConfigFile( touchscreenProfiles_cfg );
|
||||||
|
@ -361,11 +348,10 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
String touchscreenSkinsDir = AndroidDevice.PACKAGE_DIRECTORY + "/skins/touchscreen";
|
String touchscreenSkinsDir = AndroidDevice.PACKAGE_DIRECTORY + "/skins/touchscreen";
|
||||||
String touchscreenSkin = touchscreenSkinsDir + "/Outline";
|
String touchscreenSkin = touchscreenSkinsDir + "/Outline";
|
||||||
|
|
||||||
// The touch map and overlay are needed to display frame rate and/or
|
// The touch map and overlay are needed to display frame rate and/or controls
|
||||||
// controls
|
|
||||||
mTouchscreenMap = new VisibleTouchMap( mActivity.getResources() );
|
mTouchscreenMap = new VisibleTouchMap( mActivity.getResources() );
|
||||||
mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency );
|
mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency );
|
||||||
mOverlay.initialize(mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated);*/
|
mOverlay.initialize( mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -385,20 +371,20 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
private void initControllers(View inputSource)
|
private void initControllers(View inputSource)
|
||||||
{
|
{
|
||||||
// By default, send Player 1 rumbles through phone vibrator
|
// 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;
|
int touchscreenAutoHold = 0;
|
||||||
boolean isTouchscreenFeedbackEnabled = false;
|
boolean isTouchscreenFeedbackEnabled = false;
|
||||||
Set<Integer> autoHoldableButtons = null;
|
Set<Integer> autoHoldableButtons = null;
|
||||||
|
|
||||||
// Create the touchscreen controller
|
// Create the touchscreen controller
|
||||||
TouchController touchscreenController = new TouchController(mTouchscreenMap, inputSource, mOverlay, vibrator,
|
TouchController touchscreenController = new TouchController( mTouchscreenMap,
|
||||||
touchscreenAutoHold, isTouchscreenFeedbackEnabled, autoHoldableButtons);
|
inputSource, mOverlay, vibrator, touchscreenAutoHold,
|
||||||
|
isTouchscreenFeedbackEnabled, autoHoldableButtons );
|
||||||
mControllers.add( touchscreenController );
|
mControllers.add( touchscreenController );
|
||||||
|
|
||||||
// Create the input providers shared among all peripheral controllers
|
// Create the input providers shared among all peripheral controllers
|
||||||
String profile_name = NativeExports.UISettingsLoadString(UISettingID.Controller_CurrentProfile.getValue());
|
String profile_name = NativeExports.SettingsLoadString(UISettingID.ControllerCurrentProfile.toString());
|
||||||
ConfigFile ControllerConfigFile = new ConfigFile(
|
ConfigFile ControllerConfigFile = new ConfigFile(NativeExports.SettingsLoadString(UISettingID.ControllerConfigFile.toString()));
|
||||||
NativeExports.UISettingsLoadString(UISettingID.Controller_ConfigFile.getValue()));
|
|
||||||
ConfigSection section = ControllerConfigFile.get( profile_name );
|
ConfigSection section = ControllerConfigFile.get( profile_name );
|
||||||
if (section != null)
|
if (section != null)
|
||||||
{
|
{
|
||||||
|
@ -406,12 +392,11 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
||||||
InputMap map = new InputMap( ControllerProfile.get( "map" ) );
|
InputMap map = new InputMap( ControllerProfile.get( "map" ) );
|
||||||
|
|
||||||
mKeyProvider = new KeyProvider( inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
|
mKeyProvider = new KeyProvider( inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
|
||||||
MogaProvider mogaProvider = new MogaProvider(mMogaController);
|
|
||||||
AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider( inputSource ) : null;
|
AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider( inputSource ) : null;
|
||||||
int Deadzone = NativeExports.UISettingsLoadDword(UISettingID.Controller_Deadzone.getValue());
|
int Deadzone = NativeExports.SettingsLoadDword(UISettingID.ControllerDeadzone.toString());
|
||||||
int Sensitivity = NativeExports.UISettingsLoadDword(UISettingID.Controller_Sensitivity.getValue());
|
int Sensitivity = NativeExports.SettingsLoadDword(UISettingID.ControllerSensitivity.toString());
|
||||||
mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider, mogaProvider));
|
mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider));
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryRunning()
|
private void tryRunning()
|
||||||
|
|
|
@ -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 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package emu.project64.settings;
|
||||||
|
|
||||||
import emu.project64.R;
|
import emu.project64.R;
|
||||||
import emu.project64.SplashActivity;
|
import emu.project64.SplashActivity;
|
||||||
|
import emu.project64.profile.ControllerProfileActivity;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -61,6 +62,9 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat
|
||||||
}
|
}
|
||||||
else if (preference.getKey().equals("settings_gamepad_screen"))
|
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"))
|
else if (preference.getKey().equals("settings_video"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false">
|
||||||
>
|
<androidx.appcompat.widget.Toolbar
|
||||||
<android.support.v7.widget.Toolbar
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
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"
|
||||||
|
/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
***********************************************************************************
|
***********************************************************************************
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
>
|
>
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
|
|
Loading…
Reference in New Issue