Implement showSoftKeyboard for Android.

Also changed JmeAndroidSystem to store the view instead of the activity.
When users call JmeSystem.showSoftKeyboard(true), the default Android soft keyboard is displayed and any key presses are sent to jME as touch events.  Key events are also generated so the user can use the same key listeners as Desktop to keep the user code common between Desktop and Android platforms.
experimental
iwgeric 10 years ago
parent d42a777909
commit 858fd433ca
  1. 11
      jme3-android/src/main/java/com/jme3/app/AndroidHarness.java
  2. 12
      jme3-android/src/main/java/com/jme3/asset/plugins/AndroidLocator.java
  3. 18
      jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java
  4. 36
      jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
  5. 33
      jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java

@ -195,7 +195,6 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
logger.fine("onCreate"); logger.fine("onCreate");
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
JmeAndroidSystem.setActivity(this);
if (screenFullScreen) { if (screenFullScreen) {
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
@ -231,7 +230,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
settings.setDepthBits(eglDepthBits); settings.setDepthBits(eglDepthBits);
settings.setSamples(eglSamples); settings.setSamples(eglSamples);
settings.setStencilBits(eglStencilBits); settings.setStencilBits(eglStencilBits);
settings.setResolution(disp.getWidth(), disp.getHeight()); settings.setResolution(disp.getWidth(), disp.getHeight());
settings.setAudioRenderer(audioRendererType); settings.setAudioRenderer(audioRendererType);
@ -252,7 +251,9 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
} }
ctx = (OGLESContext) app.getContext(); ctx = (OGLESContext) app.getContext();
view = ctx.createView(); view = ctx.createView(this);
// store the glSurfaceView in JmeAndroidSystem for future use
JmeAndroidSystem.setView(view);
// AndroidHarness wraps the app as a SystemListener. // AndroidHarness wraps the app as a SystemListener.
ctx.setSystemListener(this); ctx.setSystemListener(this);
layoutDisplay(); layoutDisplay();
@ -307,10 +308,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
} }
} }
setContentView(new TextView(this)); setContentView(new TextView(this));
JmeAndroidSystem.setActivity(null);
ctx = null; ctx = null;
app = null; app = null;
view = null; view = null;
JmeAndroidSystem.setView(null);
super.onDestroy(); super.onDestroy();
} }
@ -479,7 +480,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) { if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) {
app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT); app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT);
} }
app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK)); app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK));
app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT}); app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT});
} }

@ -11,7 +11,7 @@ import java.util.logging.Logger;
public class AndroidLocator implements AssetLocator { public class AndroidLocator implements AssetLocator {
private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName()); private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName());
private android.content.res.AssetManager androidManager; private android.content.res.AssetManager androidManager;
private String rootPath = ""; private String rootPath = "";
@ -25,7 +25,7 @@ public class AndroidLocator implements AssetLocator {
this.assetPath = assetPath; this.assetPath = assetPath;
this.in = in; this.in = in;
} }
public AssetFileDescriptor openFileDescriptor() { public AssetFileDescriptor openFileDescriptor() {
try { try {
return androidManager.openFd(assetPath); return androidManager.openFd(assetPath);
@ -33,7 +33,7 @@ public class AndroidLocator implements AssetLocator {
throw new AssetLoadException("Failed to open asset " + assetPath, ex); throw new AssetLoadException("Failed to open asset " + assetPath, ex);
} }
} }
@Override @Override
public InputStream openStream() { public InputStream openStream() {
if (in != null){ if (in != null){
@ -66,9 +66,9 @@ public class AndroidLocator implements AssetLocator {
return null; return null;
} }
} }
public AndroidLocator() { public AndroidLocator() {
androidManager = JmeAndroidSystem.getActivity().getAssets(); androidManager = JmeAndroidSystem.getView().getContext().getAssets();
} }
public void setRootPath(String rootPath) { public void setRootPath(String rootPath) {
@ -89,7 +89,7 @@ public class AndroidLocator implements AssetLocator {
return create(manager, key, assetPath); return create(manager, key, assetPath);
} catch (IOException ex) { } catch (IOException ex) {
// This is different handling than URL locator // This is different handling than URL locator
// since classpath locating would return null at the getResource() // since classpath locating would return null at the getResource()
// call, otherwise there's a more critical error... // call, otherwise there's a more critical error...
throw new AssetLoadException("Failed to open asset " + assetPath, ex); throw new AssetLoadException("Failed to open asset " + assetPath, ex);
} }

@ -32,7 +32,6 @@
package com.jme3.input.android; package com.jme3.input.android;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
@ -40,7 +39,7 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager; import android.hardware.SensorManager;
import android.os.Vibrator; import android.os.Vibrator;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.view.WindowManager;
import com.jme3.input.AbstractJoystick; import com.jme3.input.AbstractJoystick;
import com.jme3.input.DefaultJoystickAxis; import com.jme3.input.DefaultJoystickAxis;
import com.jme3.input.InputManager; import com.jme3.input.InputManager;
@ -98,9 +97,10 @@ import java.util.logging.Logger;
public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName()); private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName());
private Activity activity = null; private Context context = null;
private InputManager inputManager = null; private InputManager inputManager = null;
private SensorManager sensorManager = null; private SensorManager sensorManager = null;
private WindowManager windowManager = null;
private Vibrator vibrator = null; private Vibrator vibrator = null;
private boolean vibratorActive = false; private boolean vibratorActive = false;
private long maxRumbleTime = 250; // 250ms private long maxRumbleTime = 250; // 250ms
@ -135,11 +135,13 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
} }
private void initSensorManager() { private void initSensorManager() {
this.activity = JmeAndroidSystem.getActivity(); 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 // Get instance of the SensorManager from the current Context
sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE); sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
// Get instance of Vibrator from current Context // Get instance of Vibrator from current Context
vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator == null) { if (vibrator == null) {
logger.log(Level.FINE, "Vibrator Service not found."); logger.log(Level.FINE, "Vibrator Service not found.");
} }
@ -306,7 +308,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
* @return Current device rotation amount * @return Current device rotation amount
*/ */
private int getScreenRotation() { private int getScreenRotation() {
return activity.getWindowManager().getDefaultDisplay().getRotation(); return windowManager.getDefaultDisplay().getRotation();
} }
/** /**
@ -592,7 +594,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener {
joysticks = null; joysticks = null;
sensorManager = null; sensorManager = null;
vibrator = null; vibrator = null;
activity = null; context = null;
} }
public boolean isInitialized() { public boolean isInitialized() {

@ -1,10 +1,11 @@
package com.jme3.system.android; package com.jme3.system.android;
import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.os.Environment; import android.os.Environment;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import com.jme3.asset.AndroidAssetManager; import com.jme3.asset.AndroidAssetManager;
import com.jme3.asset.AndroidImageInfo; import com.jme3.asset.AndroidImageInfo;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
@ -31,7 +32,7 @@ import java.util.logging.Level;
public class JmeAndroidSystem extends JmeSystemDelegate { public class JmeAndroidSystem extends JmeSystemDelegate {
private static Activity activity; private static View view;
private static String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT; private static String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;
static { static {
@ -82,9 +83,9 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
public void showErrorDialog(String message) { public void showErrorDialog(String message) {
final String finalMsg = message; final String finalMsg = message;
final String finalTitle = "Error in application"; final String finalTitle = "Error in application";
final Activity context = JmeAndroidSystem.getActivity(); final Context context = JmeAndroidSystem.getView().getContext();
context.runOnUiThread(new Runnable() { view.getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
AlertDialog dialog = new AlertDialog.Builder(context) AlertDialog dialog = new AlertDialog.Builder(context)
@ -184,7 +185,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
// The files can only be accessed by this application // The files can only be accessed by this application
storageFolder = storageFolders.get(type); storageFolder = storageFolders.get(type);
if (storageFolder == null) { if (storageFolder == null) {
storageFolder = activity.getApplicationContext().getDir("", Context.MODE_PRIVATE); storageFolder = view.getContext().getDir("", Context.MODE_PRIVATE);
storageFolders.put(type, storageFolder); storageFolders.put(type, storageFolder);
} }
break; break;
@ -203,7 +204,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
String state = Environment.getExternalStorageState(); String state = Environment.getExternalStorageState();
logger.log(Level.FINE, "ExternalStorageState: {0}", state); logger.log(Level.FINE, "ExternalStorageState: {0}", state);
if (state.equals(Environment.MEDIA_MOUNTED)) { if (state.equals(Environment.MEDIA_MOUNTED)) {
storageFolder = activity.getApplicationContext().getExternalFilesDir(null); storageFolder = view.getContext().getExternalFilesDir(null);
storageFolders.put(type, storageFolder); storageFolders.put(type, storageFolder);
} }
} }
@ -219,12 +220,12 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
return storageFolder; return storageFolder;
} }
public static void setActivity(Activity activity) { public static void setView(View view) {
JmeAndroidSystem.activity = activity; JmeAndroidSystem.view = view;
} }
public static Activity getActivity() { public static View getView() {
return activity; return view;
} }
public static String getAudioRendererType() { public static String getAudioRendererType() {
@ -232,6 +233,19 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
} }
@Override @Override
public void showSoftKeyboard(boolean show) { public void showSoftKeyboard(final boolean show) {
view.getHandler().post(new Runnable() {
public void run() {
InputMethodManager manager =
(InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (show) {
manager.showSoftInput(view, 0);
} else {
manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
});
} }
} }

@ -31,7 +31,6 @@
*/ */
package com.jme3.system.android; package com.jme3.system.android;
import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
@ -42,6 +41,7 @@ import android.opengl.GLSurfaceView;
import android.os.Build; import android.os.Build;
import android.text.InputType; import android.text.InputType;
import android.view.Gravity; import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -56,7 +56,6 @@ import com.jme3.system.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
@ -96,21 +95,19 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
* *
* @return GLSurfaceView The newly created view * @return GLSurfaceView The newly created view
*/ */
public GLSurfaceView createView() { public GLSurfaceView createView(Context context) {
Context appContext = JmeAndroidSystem.getActivity().getApplication();
// NOTE: We assume all ICS devices have OpenGL ES 2.0. // NOTE: We assume all ICS devices have OpenGL ES 2.0.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// below 4.0, check OpenGL ES 2.0 support. // below 4.0, check OpenGL ES 2.0 support.
ActivityManager am = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo(); ConfigurationInfo info = am.getDeviceConfigurationInfo();
if (info.reqGlEsVersion < 0x20000) { if (info.reqGlEsVersion < 0x20000) {
throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device"); throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device");
} }
} }
// Start to set up the view // Start to set up the view
GLSurfaceView view = new GLSurfaceView(appContext); GLSurfaceView view = new GLSurfaceView(context);
if (androidInput == null) { if (androidInput == null) {
androidInput = new AndroidInputHandler(); androidInput = new AndroidInputHandler();
} }
@ -123,7 +120,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
view.setFocusableInTouchMode(true); view.setFocusableInTouchMode(true);
view.setFocusable(true); view.setFocusable(true);
// setFormat must be set before AndroidConfigChooser is called by the surfaceview. // setFormat must be set before AndroidConfigChooser is called by the surfaceview.
// if setFormat is called after ConfigChooser is called, then execution // if setFormat is called after ConfigChooser is called, then execution
// stops at the setFormat call without a crash. // stops at the setFormat call without a crash.
@ -148,18 +145,18 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
AndroidConfigChooser configChooser = new AndroidConfigChooser(settings); AndroidConfigChooser configChooser = new AndroidConfigChooser(settings);
view.setEGLConfigChooser(configChooser); view.setEGLConfigChooser(configChooser);
view.setRenderer(this); view.setRenderer(this);
// Attempt to preserve the EGL Context on app pause/resume. // Attempt to preserve the EGL Context on app pause/resume.
// Not destroying and recreating the EGL context // Not destroying and recreating the EGL context
// will help with resume time by reusing the existing context to avoid // will help with resume time by reusing the existing context to avoid
// reloading all the OpenGL objects. // reloading all the OpenGL objects.
if (Build.VERSION.SDK_INT >= 11) { if (Build.VERSION.SDK_INT >= 11) {
view.setPreserveEGLContextOnPause(true); view.setPreserveEGLContextOnPause(true);
} }
return view; return view;
} }
// renderer:initialize // renderer:initialize
@Override @Override
public void onSurfaceCreated(GL10 gl, EGLConfig cfg) { public void onSurfaceCreated(GL10 gl, EGLConfig cfg) {
@ -388,13 +385,13 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
logger.log(Level.FINE, "requestDialog: title: {0}, initialValue: {1}", logger.log(Level.FINE, "requestDialog: title: {0}, initialValue: {1}",
new Object[]{title, initialValue}); new Object[]{title, initialValue});
final Activity activity = JmeAndroidSystem.getActivity(); final View view = JmeAndroidSystem.getView();
activity.runOnUiThread(new Runnable() { view.getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
final FrameLayout layoutTextDialogInput = new FrameLayout(activity); final FrameLayout layoutTextDialogInput = new FrameLayout(view.getContext());
final EditText editTextDialogInput = new EditText(activity); final EditText editTextDialogInput = new EditText(view.getContext());
editTextDialogInput.setWidth(LayoutParams.FILL_PARENT); editTextDialogInput.setWidth(LayoutParams.FILL_PARENT);
editTextDialogInput.setHeight(LayoutParams.FILL_PARENT); editTextDialogInput.setHeight(LayoutParams.FILL_PARENT);
editTextDialogInput.setPadding(20, 20, 20, 20); editTextDialogInput.setPadding(20, 20, 20, 20);
@ -425,7 +422,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
layoutTextDialogInput.addView(editTextDialogInput); layoutTextDialogInput.addView(editTextDialogInput);
AlertDialog dialogTextInput = new AlertDialog.Builder(activity).setTitle(title).setView(layoutTextDialogInput).setPositiveButton("OK", AlertDialog dialogTextInput = new AlertDialog.Builder(view.getContext()).setTitle(title).setView(layoutTextDialogInput).setPositiveButton("OK",
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) { public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK, send COMPLETE action /* User clicked OK, send COMPLETE action

Loading…
Cancel
Save