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");
super.onCreate(savedInstanceState);
JmeAndroidSystem.setActivity(this);
if (screenFullScreen) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
@ -231,7 +230,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
settings.setDepthBits(eglDepthBits);
settings.setSamples(eglSamples);
settings.setStencilBits(eglStencilBits);
settings.setResolution(disp.getWidth(), disp.getHeight());
settings.setAudioRenderer(audioRendererType);
@ -252,7 +251,9 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
}
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.
ctx.setSystemListener(this);
layoutDisplay();
@ -307,10 +308,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
}
}
setContentView(new TextView(this));
JmeAndroidSystem.setActivity(null);
ctx = null;
app = null;
view = null;
JmeAndroidSystem.setView(null);
super.onDestroy();
}
@ -479,7 +480,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) {
app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT);
}
app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK));
app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT});
}

@ -11,7 +11,7 @@ import java.util.logging.Logger;
public class AndroidLocator implements AssetLocator {
private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName());
private android.content.res.AssetManager androidManager;
private String rootPath = "";
@ -25,7 +25,7 @@ public class AndroidLocator implements AssetLocator {
this.assetPath = assetPath;
this.in = in;
}
public AssetFileDescriptor openFileDescriptor() {
try {
return androidManager.openFd(assetPath);
@ -33,7 +33,7 @@ public class AndroidLocator implements AssetLocator {
throw new AssetLoadException("Failed to open asset " + assetPath, ex);
}
}
@Override
public InputStream openStream() {
if (in != null){
@ -66,9 +66,9 @@ public class AndroidLocator implements AssetLocator {
return null;
}
}
public AndroidLocator() {
androidManager = JmeAndroidSystem.getActivity().getAssets();
androidManager = JmeAndroidSystem.getView().getContext().getAssets();
}
public void setRootPath(String rootPath) {
@ -89,7 +89,7 @@ public class AndroidLocator implements AssetLocator {
return create(manager, key, assetPath);
} catch (IOException ex) {
// 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...
throw new AssetLoadException("Failed to open asset " + assetPath, ex);
}

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

@ -1,10 +1,11 @@
package com.jme3.system.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import com.jme3.asset.AndroidAssetManager;
import com.jme3.asset.AndroidImageInfo;
import com.jme3.asset.AssetManager;
@ -31,7 +32,7 @@ import java.util.logging.Level;
public class JmeAndroidSystem extends JmeSystemDelegate {
private static Activity activity;
private static View view;
private static String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;
static {
@ -82,9 +83,9 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
public void showErrorDialog(String message) {
final String finalMsg = message;
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
public void run() {
AlertDialog dialog = new AlertDialog.Builder(context)
@ -184,7 +185,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
// The files can only be accessed by this application
storageFolder = storageFolders.get(type);
if (storageFolder == null) {
storageFolder = activity.getApplicationContext().getDir("", Context.MODE_PRIVATE);
storageFolder = view.getContext().getDir("", Context.MODE_PRIVATE);
storageFolders.put(type, storageFolder);
}
break;
@ -203,7 +204,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
String state = Environment.getExternalStorageState();
logger.log(Level.FINE, "ExternalStorageState: {0}", state);
if (state.equals(Environment.MEDIA_MOUNTED)) {
storageFolder = activity.getApplicationContext().getExternalFilesDir(null);
storageFolder = view.getContext().getExternalFilesDir(null);
storageFolders.put(type, storageFolder);
}
}
@ -219,12 +220,12 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
return storageFolder;
}
public static void setActivity(Activity activity) {
JmeAndroidSystem.activity = activity;
public static void setView(View view) {
JmeAndroidSystem.view = view;
}
public static Activity getActivity() {
return activity;
public static View getView() {
return view;
}
public static String getAudioRendererType() {
@ -232,6 +233,19 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
}
@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;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.Context;
@ -42,6 +41,7 @@ import android.opengl.GLSurfaceView;
import android.os.Build;
import android.text.InputType;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
import android.widget.FrameLayout;
@ -56,7 +56,6 @@ import com.jme3.system.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@ -96,21 +95,19 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
*
* @return GLSurfaceView The newly created view
*/
public GLSurfaceView createView() {
Context appContext = JmeAndroidSystem.getActivity().getApplication();
public GLSurfaceView createView(Context context) {
// NOTE: We assume all ICS devices have OpenGL ES 2.0.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// 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();
if (info.reqGlEsVersion < 0x20000) {
throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device");
}
}
// Start to set up the view
GLSurfaceView view = new GLSurfaceView(appContext);
GLSurfaceView view = new GLSurfaceView(context);
if (androidInput == null) {
androidInput = new AndroidInputHandler();
}
@ -123,7 +120,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
view.setFocusableInTouchMode(true);
view.setFocusable(true);
// setFormat must be set before AndroidConfigChooser is called by the surfaceview.
// if setFormat is called after ConfigChooser is called, then execution
// 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);
view.setEGLConfigChooser(configChooser);
view.setRenderer(this);
// 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
// reloading all the OpenGL objects.
if (Build.VERSION.SDK_INT >= 11) {
view.setPreserveEGLContextOnPause(true);
}
return view;
}
// renderer:initialize
@Override
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}",
new Object[]{title, initialValue});
final Activity activity = JmeAndroidSystem.getActivity();
activity.runOnUiThread(new Runnable() {
final View view = JmeAndroidSystem.getView();
view.getHandler().post(new Runnable() {
@Override
public void run() {
final FrameLayout layoutTextDialogInput = new FrameLayout(activity);
final EditText editTextDialogInput = new EditText(activity);
final FrameLayout layoutTextDialogInput = new FrameLayout(view.getContext());
final EditText editTextDialogInput = new EditText(view.getContext());
editTextDialogInput.setWidth(LayoutParams.FILL_PARENT);
editTextDialogInput.setHeight(LayoutParams.FILL_PARENT);
editTextDialogInput.setPadding(20, 20, 20, 20);
@ -425,7 +422,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
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() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK, send COMPLETE action

Loading…
Cancel
Save