Przeglądaj źródła

Android: Refactor joystick support to prepare for upcoming gamepad support.

iwgeric 10 lat temu
rodzic
commit
22d3f7f9f4

+ 257 - 0
jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java

@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.input.android;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.os.Vibrator;
+import android.view.View;
+import com.jme3.input.InputManager;
+import com.jme3.input.JoyInput;
+import com.jme3.input.Joystick;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.event.InputEvent;
+import com.jme3.input.event.JoyAxisEvent;
+import com.jme3.input.event.JoyButtonEvent;
+import com.jme3.system.AppSettings;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Main class that manages various joystick devices.  Joysticks can be many forms
+ * including a simulated joystick to communicate the device orientation as well
+ * as physical gamepads. </br>
+ * This class manages all the joysticks and feeds the inputs from each back
+ * to jME's InputManager.
+ *
+ * This handler also supports the joystick.rumble(rumbleAmount) method.  In this
+ * case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate
+ * if the device has a built in vibrate motor.
+ *
+ * Because Andorid does not allow for the user to define the intensity of the
+ * vibration, the rumble amount (ie strength) is converted into vibration pulses
+ * The stronger the strength amount, the shorter the delay between pulses.  If
+ * amount is 1, then the vibration stays on the whole time.  If amount is 0.5,
+ * the vibration will a pulse of equal parts vibration and delay.
+ * To turn off vibration, set rumble amount to 0.
+ *
+ * MainActivity needs the following line to enable Joysticks on Android platforms
+ *    joystickEventsEnabled = true;
+ * This is done to allow for battery conservation when sensor data or gamepads
+ * are not required by the application.
+ *
+ * To use the joystick rumble feature, the following line needs to be
+ * added to the Android Manifest File
+ *     <uses-permission android:name="android.permission.VIBRATE"/>
+ *
+ * @author iwgeric
+ */
+public class AndroidJoyInputHandler implements JoyInput {
+    private static final Logger logger = Logger.getLogger(AndroidJoyInputHandler.class.getName());
+
+    private List<Joystick> joystickList = new ArrayList<Joystick>();
+//    private boolean dontSendHistory = false;
+
+
+    // Internal
+    private GLSurfaceView view;
+    private boolean initialized = false;
+    private RawInputListener listener = null;
+    private ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>();
+    private AndroidSensorJoyInput sensorJoyInput;
+    private Vibrator vibrator = null;
+    private boolean vibratorActive = false;
+    private long maxRumbleTime = 250;  // 250ms
+
+    public AndroidJoyInputHandler() {
+        int buildVersion = Build.VERSION.SDK_INT;
+        logger.log(Level.INFO, "Android Build Version: {0}", buildVersion);
+//        if (buildVersion >= 14) {
+//            touchHandler = new AndroidTouchHandler14(this);
+//        } else if (buildVersion >= 8){
+//            touchHandler = new AndroidTouchHandler(this);
+//        }
+        sensorJoyInput = new AndroidSensorJoyInput(this);
+    }
+
+    public void setView(GLSurfaceView view) {
+//        if (touchHandler != null) {
+//            touchHandler.setView(view);
+//        }
+        if (sensorJoyInput != null) {
+            sensorJoyInput.setView(view);
+        }
+        this.view = (GLSurfaceView)view;
+
+    }
+
+    public View getView() {
+        return view;
+    }
+
+    public void loadSettings(AppSettings settings) {
+//        sensorEventsEnabled = settings.useSensors();
+    }
+
+    public void addEvent(InputEvent event) {
+        eventQueue.add(event);
+    }
+
+    /**
+     * Pauses the joystick device listeners to save battery life if they are not needed.
+     * Used to pause when the activity pauses
+     */
+    public void pauseJoysticks() {
+        if (sensorJoyInput != null) {
+            sensorJoyInput.pauseSensors();
+        }
+        if (vibrator != null && vibratorActive) {
+            vibrator.cancel();
+        }
+
+    }
+
+    /**
+     * Resumes the joystick device listeners.
+     * Used to resume when the activity comes to the top of the stack
+     */
+    public void resumeJoysticks() {
+        if (sensorJoyInput != null) {
+            sensorJoyInput.resumeSensors();
+        }
+
+    }
+
+
+
+
+
+    @Override
+    public void initialize() {
+//        if (sensorJoyInput != null) {
+//            sensorJoyInput.initialize();
+//        }
+        // Get instance of Vibrator from current Context
+        vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        if (vibrator == null) {
+            logger.log(Level.FINE, "Vibrator Service not found.");
+        }
+        initialized = true;
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return initialized;
+    }
+
+    @Override
+    public void destroy() {
+        initialized = false;
+
+        if (sensorJoyInput != null) {
+            sensorJoyInput.destroy();
+        }
+
+        setView(null);
+    }
+
+    @Override
+    public void setInputListener(RawInputListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public long getInputTimeNanos() {
+        return System.nanoTime();
+    }
+
+    @Override
+    public void setJoyRumble(int joyId, float amount) {
+        // convert amount to pulses since Android doesn't allow intensity
+        if (vibrator != null) {
+            final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
+            final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
+            final long[] rumblePattern = {
+                0, // start immediately
+                rumbleOnDur, // time to leave vibration on
+                rumbleOffDur // time to delay between vibrations
+            };
+            final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
+
+            logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
+                    new Object[]{amount, rumbleOnDur, rumbleOffDur});
+
+            if (rumbleOnDur > 0) {
+                vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
+                vibratorActive = true;
+            } else {
+                vibrator.cancel();
+                vibratorActive = false;
+            }
+        }
+    }
+
+    @Override
+    public Joystick[] loadJoysticks(InputManager inputManager) {
+        joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager));
+
+
+        return joystickList.toArray( new Joystick[joystickList.size()] );
+    }
+
+    @Override
+    public void update() {
+        if (sensorJoyInput != null) {
+            sensorJoyInput.update();
+        }
+
+        if (listener != null) {
+            InputEvent inputEvent;
+
+            while ((inputEvent = eventQueue.poll()) != null) {
+                if (inputEvent instanceof JoyAxisEvent) {
+                    listener.onJoyAxisEvent((JoyAxisEvent)inputEvent);
+                } else if (inputEvent instanceof JoyButtonEvent) {
+                    listener.onJoyButtonEvent((JoyButtonEvent)inputEvent);
+                }
+            }
+        }
+
+    }
+
+
+
+}

+ 46 - 130
jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java

@@ -37,7 +37,7 @@ import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-import android.os.Vibrator;
+import android.opengl.GLSurfaceView;
 import android.view.Surface;
 import android.view.WindowManager;
 import com.jme3.input.AbstractJoystick;
@@ -47,10 +47,8 @@ import com.jme3.input.JoyInput;
 import com.jme3.input.Joystick;
 import com.jme3.input.JoystickAxis;
 import com.jme3.input.SensorJoystickAxis;
-import com.jme3.input.RawInputListener;
 import com.jme3.input.event.JoyAxisEvent;
 import com.jme3.math.FastMath;
-import com.jme3.system.android.JmeAndroidSystem;
 import com.jme3.util.IntMap;
 import com.jme3.util.IntMap.Entry;
 import java.util.ArrayList;
@@ -63,7 +61,7 @@ import java.util.logging.Logger;
  * A single joystick is configured and includes data for all configured sensors
  * as seperate axes of the joystick.
  *
- * Each axis is named accounting to the static strings in SensorJoystickAxis.
+ * Each axis is named according to the static strings in SensorJoystickAxis.
  * Refer to the strings defined in SensorJoystickAxis for a list of supported
  * sensors and their axis data.  Each sensor type defined in SensorJoystickAxis
  * will be attempted to be configured.  If the device does not support a particular
@@ -72,46 +70,21 @@ import java.util.logging.Logger;
  * The joystick.getXAxis and getYAxis methods of the joystick are configured to
  * return the device orientation values in the device's X and Y directions.
  *
- * This joystick also supports the joystick.rumble(rumbleAmount) method.  In this
- * case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate
- * if the device has a built in vibrate motor.
- *
- * Because Andorid does not allow for the user to define the intensity of the
- * vibration, the rumble amount (ie strength) is converted into vibration pulses
- * The stronger the strength amount, the shorter the delay between pulses.  If
- * amount is 1, then the vibration stays on the whole time.  If amount is 0.5,
- * the vibration will a pulse of equal parts vibration and delay.
- * To turn off vibration, set rumble amount to 0.
- *
- * MainActivity needs the following line to enable Joysticks on Android platforms
- *    joystickEventsEnabled = true;
- * This is done to allow for battery conservation when sensor data is not required
- * by the application.
- *
- * To use the joystick rumble feature, the following line needs to be
- * added to the Android Manifest File
- *     <uses-permission android:name="android.permission.VIBRATE"/>
- *
  * @author iwgeric
  */
-public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
+public class AndroidSensorJoyInput implements SensorEventListener {
     private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName());
 
-    private Context context = null;
-    private InputManager inputManager = null;
+    private AndroidJoyInputHandler joyHandler;
     private SensorManager sensorManager = null;
     private WindowManager windowManager = null;
-    private Vibrator vibrator = null;
-    private boolean vibratorActive = false;
-    private long maxRumbleTime = 250;  // 250ms
-    private RawInputListener listener = null;
     private IntMap<SensorData> sensors = new IntMap<SensorData>();
-    private AndroidJoystick[] joysticks;
     private int lastRotation = 0;
-    private boolean initialized = false;
     private boolean loaded = false;
 
-    private final ArrayList<JoyAxisEvent> eventQueue = new ArrayList<JoyAxisEvent>();
+    public AndroidSensorJoyInput(AndroidJoyInputHandler joyHandler) {
+        this.joyHandler = joyHandler;
+    }
 
     /**
      * Internal class to enclose data for each sensor.
@@ -120,7 +93,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
         int androidSensorType = -1;
         int androidSensorSpeed = SensorManager.SENSOR_DELAY_GAME;
         Sensor sensor = null;
-        int sensorAccuracy = 0;
+        int sensorAccuracy = -1;
         float[] lastValues;
         final Object valuesLock = new Object();
         ArrayList<AndroidJoystickAxis> axes = new ArrayList<AndroidJoystickAxis>();
@@ -134,16 +107,19 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
 
     }
 
-    private void initSensorManager() {
-        this.context = JmeAndroidSystem.getView().getContext();
-        // Get instance of the WindowManager from the current Context
-        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        // Get instance of the SensorManager from the current Context
-        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
-        // Get instance of Vibrator from current Context
-        vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        if (vibrator == null) {
-            logger.log(Level.FINE, "Vibrator Service not found.");
+    public void setView(GLSurfaceView view) {
+        pauseSensors();
+        if (sensorManager != null) {
+            sensorManager.unregisterListener(this);
+        }
+        if (view == null) {
+            windowManager = null;
+            sensorManager = null;
+        } else {
+            // Get instance of the WindowManager from the current Context
+            windowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
+            // Get instance of the SensorManager from the current Context
+            sensorManager = (SensorManager) view.getContext().getSystemService(Context.SENSOR_SERVICE);
         }
     }
 
@@ -222,9 +198,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
                 unRegisterListener(entry.getKey());
             }
         }
-        if (vibrator != null && vibratorActive) {
-            vibrator.cancel();
-        }
     }
 
     /**
@@ -400,10 +373,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
                             if (!sensorData.haveData) {
                                 sensorData.haveData = true;
                             } else {
-                                synchronized (eventQueue){
-                                    if (axis.isChanged()) {
-                                        eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
-                                    }
+                                if (axis.isChanged()) {
+                                    joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
                                 }
                             }
                         }
@@ -428,47 +399,14 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
 
     // Start of JoyInput methods
 
-    public void setJoyRumble(int joyId, float amount) {
-        // convert amount to pulses since Android doesn't allow intensity
-        if (vibrator != null) {
-            final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on
-            final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses
-            final long[] rumblePattern = {
-                0, // start immediately
-                rumbleOnDur, // time to leave vibration on
-                rumbleOffDur // time to delay between vibrations
-            };
-            final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from
-
-            logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}",
-                    new Object[]{amount, rumbleOnDur, rumbleOffDur});
-
-            if (rumbleOnDur > 0) {
-                vibrator.vibrate(rumblePattern, rumbleRepeatFrom);
-                vibratorActive = true;
-            } else {
-                vibrator.cancel();
-                vibratorActive = false;
-            }
-        }
-
-    }
-
-    public Joystick[] loadJoysticks(InputManager inputManager) {
-        this.inputManager = inputManager;
-
-        initSensorManager();
-
+    public Joystick loadJoystick(int joyId, InputManager inputManager) {
         SensorData sensorData;
-        List<Joystick> list = new ArrayList<Joystick>();
-        AndroidJoystick joystick;
         AndroidJoystickAxis axis;
 
-        joystick = new AndroidJoystick(inputManager,
-                                    this,
-                                    list.size(),
+        AndroidJoystick joystick = new AndroidJoystick(inputManager,
+                                    joyHandler,
+                                    joyId,
                                     "AndroidSensorsJoystick");
-        list.add(joystick);
 
         List<Sensor> availSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
         for (Sensor sensor: availSensors) {
@@ -555,14 +493,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
 //        }
 
 
-        joysticks = list.toArray( new AndroidJoystick[list.size()] );
         loaded = true;
-        return joysticks;
-    }
-
-    public void initialize() {
-        initialized = true;
-        loaded = false;
+        return joystick;
     }
 
     public void update() {
@@ -570,15 +502,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
             return;
         }
         updateOrientation();
-        synchronized (eventQueue){
-            // flush events to listener
-            if (listener != null && eventQueue.size() > 0) {
-                for (int i = 0; i < eventQueue.size(); i++){
-                    listener.onJoyAxisEvent(eventQueue.get(i));
-                }
-                eventQueue.clear();
-            }
-        }
     }
 
     public void destroy() {
@@ -588,39 +511,27 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
             sensorManager.unregisterListener(this);
         }
         sensors.clear();
-        eventQueue.clear();
-        initialized = false;
         loaded = false;
-        joysticks = null;
         sensorManager = null;
-        vibrator = null;
-        context = null;
-    }
-
-    public boolean isInitialized() {
-        return initialized;
-    }
-
-    public void setInputListener(RawInputListener listener) {
-        this.listener = listener;
-    }
-
-    public long getInputTimeNanos() {
-        return System.nanoTime();
     }
 
-    // End of JoyInput methods
-
     // Start of Android SensorEventListener methods
 
+    @Override
     public void onSensorChanged(SensorEvent se) {
-        if (!initialized || !loaded) {
+        if (!loaded) {
             return;
         }
+        logger.log(Level.FINE, "onSensorChanged for {0}: accuracy: {1}, values: {2}",
+                new Object[]{se.sensor.getName(), se.accuracy, se.values});
 
         int sensorType = se.sensor.getType();
 
         SensorData sensorData = sensors.get(sensorType);
+        if (sensorData != null) {
+            logger.log(Level.FINE, "sensorData name: {0}, enabled: {1}, unreliable: {2}",
+                    new Object[]{sensorData.sensor.getName(), sensorData.enabled, sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE});
+        }
         if (sensorData != null && sensorData.sensor.equals(se.sensor) && sensorData.enabled) {
 
             if (sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
@@ -641,10 +552,11 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
                         if (!sensorData.haveData) {
                             sensorData.haveData = true;
                         } else {
-                            synchronized (eventQueue){
-                                if (axis.isChanged()) {
-                                    eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
-                                }
+                            if (axis.isChanged()) {
+                                JoyAxisEvent event = new JoyAxisEvent(axis, axis.getJoystickAxisValue());
+                                logger.log(Level.INFO, "adding JoyAxisEvent: {0}", event);
+                                joyHandler.addEvent(event);
+//                                joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue()));
                             }
                         }
                     }
@@ -658,6 +570,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
         }
     }
 
+    @Override
     public void onAccuracyChanged(Sensor sensor, int i) {
         int sensorType = sensor.getType();
         SensorData sensorData = sensors.get(sensorType);
@@ -697,7 +610,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
             AndroidJoystickAxis axis;
 
             axis = new AndroidJoystickAxis(
-                    inputManager,               // InputManager (InputManager)
+                    getInputManager(),          // InputManager (InputManager)
                     this,                       // parent Joystick (Joystick)
                     axisNum,                    // Axis Index (int)
                     axisName,                   // Axis Name (String)
@@ -758,10 +671,12 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
             this.maxRawValue = maxRawValue;
         }
 
+        @Override
         public float getMaxRawValue() {
             return maxRawValue;
         }
 
+        @Override
         public void setMaxRawValue(float maxRawValue) {
             this.maxRawValue = maxRawValue;
         }
@@ -787,6 +702,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
             return hasChanged;
         }
 
+        @Override
         public void calibrateCenter() {
             zeroRawValue = lastRawValue;
             logger.log(Level.FINE, "Calibrating axis {0} to {1}",

+ 12 - 8
jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java

@@ -46,17 +46,15 @@ import android.view.ViewGroup.LayoutParams;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import com.jme3.input.*;
-import com.jme3.input.android.AndroidSensorJoyInput;
 import com.jme3.input.android.AndroidInputHandler;
+import com.jme3.input.android.AndroidJoyInputHandler;
 import com.jme3.input.controls.SoftTextDialogInputListener;
 import com.jme3.input.dummy.DummyKeyInput;
 import com.jme3.input.dummy.DummyMouseInput;
 import com.jme3.renderer.android.AndroidGL;
 import com.jme3.renderer.opengl.GL;
-import com.jme3.renderer.opengl.GLDebugES;
 import com.jme3.renderer.opengl.GLExt;
 import com.jme3.renderer.opengl.GLRenderer;
-import com.jme3.renderer.opengl.GLTracer;
 import com.jme3.system.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
@@ -77,9 +75,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
     protected SystemListener listener;
     protected boolean autoFlush = true;
     protected AndroidInputHandler androidInput;
+    protected AndroidJoyInputHandler androidJoyInput = null;
     protected long minFrameDuration = 0;                   // No FPS cap
     protected long lastUpdateTime = 0;
-    protected JoyInput androidSensorJoyInput = null;
 
     public OGLESContext() {
     }
@@ -119,6 +117,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
         androidInput.setView(view);
         androidInput.loadSettings(settings);
 
+        if (androidJoyInput == null) {
+            androidJoyInput = new AndroidJoyInputHandler();
+        }
+        androidJoyInput.setView(view);
+        androidJoyInput.loadSettings(settings);
+
         // setEGLContextClientVersion must be set before calling setRenderer
         // this means it cannot be set in AndroidConfigChooser (too late)
         view.setEGLContextClientVersion(2);
@@ -231,6 +235,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
         if (androidInput != null) {
             androidInput.loadSettings(settings);
         }
+        if (androidJoyInput != null) {
+            androidJoyInput.loadSettings(settings);
+        }
 
         if (settings.getFrameRate() > 0) {
             minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms
@@ -267,10 +274,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
 
     @Override
     public JoyInput getJoyInput() {
-        if (androidSensorJoyInput == null) {
-            androidSensorJoyInput = new AndroidSensorJoyInput();
-        }
-        return androidSensorJoyInput;
+        return androidJoyInput;
     }
 
     @Override