|
|
@@ -2,12 +2,9 @@ package org.libsdl.app;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
-import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.List;
|
|
|
import java.lang.reflect.Method;
|
|
|
+import java.util.Objects;
|
|
|
|
|
|
import android.app.*;
|
|
|
import android.content.*;
|
|
|
@@ -26,7 +23,6 @@ import android.util.Log;
|
|
|
import android.util.SparseArray;
|
|
|
import android.graphics.*;
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
-import android.media.*;
|
|
|
import android.hardware.*;
|
|
|
import android.content.pm.ActivityInfo;
|
|
|
|
|
|
@@ -36,8 +32,16 @@ import android.content.pm.ActivityInfo;
|
|
|
public class SDLActivity extends Activity {
|
|
|
private static final String TAG = "SDL";
|
|
|
|
|
|
- // Keep track of the paused state
|
|
|
- public static boolean mIsPaused, mIsSurfaceReady, mHasFocus;
|
|
|
+ public static boolean mIsResumedCalled, mIsSurfaceReady, mHasFocus;
|
|
|
+
|
|
|
+ // Handle the state of the native layer
|
|
|
+ public enum NativeState {
|
|
|
+ INIT, RESUMED, PAUSED
|
|
|
+ }
|
|
|
+
|
|
|
+ public static NativeState mNextNativeState;
|
|
|
+ public static NativeState mCurrentNativeState;
|
|
|
+
|
|
|
public static boolean mExitCalledFromJava;
|
|
|
|
|
|
/** If shared libraries (e.g. SDL or the native application) could not be loaded. */
|
|
|
@@ -51,15 +55,36 @@ public class SDLActivity extends Activity {
|
|
|
protected static SDLActivity mSingleton;
|
|
|
protected static SDLSurface mSurface;
|
|
|
protected static View mTextEdit;
|
|
|
+ protected static boolean mScreenKeyboardShown;
|
|
|
protected static ViewGroup mLayout;
|
|
|
- protected static SDLJoystickHandler mJoystickHandler;
|
|
|
+ protected static SDLClipboardHandler mClipboardHandler;
|
|
|
+
|
|
|
|
|
|
// This is what SDL runs in. It invokes SDL_main(), eventually
|
|
|
protected static Thread mSDLThread;
|
|
|
|
|
|
- // Audio
|
|
|
- protected static AudioTrack mAudioTrack;
|
|
|
- protected static AudioRecord mAudioRecord;
|
|
|
+ /**
|
|
|
+ * This method returns the name of the shared object with the application entry point
|
|
|
+ * It can be overridden by derived classes.
|
|
|
+ */
|
|
|
+ protected String getMainSharedObject() {
|
|
|
+ String library;
|
|
|
+ String[] libraries = SDLActivity.mSingleton.getLibraries();
|
|
|
+ if (libraries.length > 0) {
|
|
|
+ library = "lib" + libraries[libraries.length - 1] + ".so";
|
|
|
+ } else {
|
|
|
+ library = "libmain.so";
|
|
|
+ }
|
|
|
+ return library;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method returns the name of the application entry point
|
|
|
+ * It can be overridden by derived classes.
|
|
|
+ */
|
|
|
+ protected String getMainFunction() {
|
|
|
+ return "SDL_main";
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* This method is called by SDL before loading the native shared libraries.
|
|
|
@@ -104,15 +129,15 @@ public class SDLActivity extends Activity {
|
|
|
mSurface = null;
|
|
|
mTextEdit = null;
|
|
|
mLayout = null;
|
|
|
- mJoystickHandler = null;
|
|
|
+ mClipboardHandler = null;
|
|
|
mSDLThread = null;
|
|
|
- mAudioTrack = null;
|
|
|
- mAudioRecord = null;
|
|
|
mExitCalledFromJava = false;
|
|
|
mBrokenLibraries = false;
|
|
|
- mIsPaused = false;
|
|
|
+ mIsResumedCalled = false;
|
|
|
mIsSurfaceReady = false;
|
|
|
mHasFocus = true;
|
|
|
+ mNextNativeState = NativeState.INIT;
|
|
|
+ mCurrentNativeState = NativeState.INIT;
|
|
|
}
|
|
|
|
|
|
// Setup
|
|
|
@@ -120,13 +145,9 @@ public class SDLActivity extends Activity {
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
Log.v(TAG, "Device: " + android.os.Build.DEVICE);
|
|
|
Log.v(TAG, "Model: " + android.os.Build.MODEL);
|
|
|
- Log.v(TAG, "onCreate(): " + mSingleton);
|
|
|
+ Log.v(TAG, "onCreate()");
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
|
- SDLActivity.initialize();
|
|
|
- // So we can call stuff from static callbacks
|
|
|
- mSingleton = this;
|
|
|
-
|
|
|
// Load shared libraries
|
|
|
String errorMsgBrokenLib = "";
|
|
|
try {
|
|
|
@@ -163,16 +184,26 @@ public class SDLActivity extends Activity {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Set up the surface
|
|
|
- mSurface = new SDLSurface(getApplication());
|
|
|
+ // Set up JNI
|
|
|
+ SDL.setupJNI();
|
|
|
|
|
|
- if(Build.VERSION.SDK_INT >= 12) {
|
|
|
- mJoystickHandler = new SDLJoystickHandler_API12();
|
|
|
- }
|
|
|
- else {
|
|
|
- mJoystickHandler = new SDLJoystickHandler();
|
|
|
+ // Initialize state
|
|
|
+ SDL.initialize();
|
|
|
+
|
|
|
+ // So we can call stuff from static callbacks
|
|
|
+ mSingleton = this;
|
|
|
+ SDL.setContext(this);
|
|
|
+
|
|
|
+ if (Build.VERSION.SDK_INT >= 11) {
|
|
|
+ mClipboardHandler = new SDLClipboardHandler_API11();
|
|
|
+ } else {
|
|
|
+ /* Before API 11, no clipboard notification (eg no SDL_CLIPBOARDUPDATE) */
|
|
|
+ mClipboardHandler = new SDLClipboardHandler_Old();
|
|
|
}
|
|
|
|
|
|
+ // Set up the surface
|
|
|
+ mSurface = new SDLSurface(getApplication());
|
|
|
+
|
|
|
mLayout = new RelativeLayout(this);
|
|
|
mLayout.addView(mSurface);
|
|
|
|
|
|
@@ -180,7 +211,6 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
// Get filename from "Open with" of another application
|
|
|
Intent intent = getIntent();
|
|
|
-
|
|
|
if (intent != null && intent.getData() != null) {
|
|
|
String filename = intent.getData().getPath();
|
|
|
if (filename != null) {
|
|
|
@@ -195,24 +225,28 @@ public class SDLActivity extends Activity {
|
|
|
protected void onPause() {
|
|
|
Log.v(TAG, "onPause()");
|
|
|
super.onPause();
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
+ mIsResumedCalled = false;
|
|
|
|
|
|
if (SDLActivity.mBrokenLibraries) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SDLActivity.handlePause();
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
protected void onResume() {
|
|
|
Log.v(TAG, "onResume()");
|
|
|
super.onResume();
|
|
|
+ mNextNativeState = NativeState.RESUMED;
|
|
|
+ mIsResumedCalled = true;
|
|
|
|
|
|
if (SDLActivity.mBrokenLibraries) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SDLActivity.handleResume();
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -227,8 +261,12 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
SDLActivity.mHasFocus = hasFocus;
|
|
|
if (hasFocus) {
|
|
|
- SDLActivity.handleResume();
|
|
|
+ mNextNativeState = NativeState.RESUMED;
|
|
|
+ } else {
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
}
|
|
|
+
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -254,6 +292,9 @@ public class SDLActivity extends Activity {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
+
|
|
|
// Send a quit message to the application
|
|
|
SDLActivity.mExitCalledFromJava = true;
|
|
|
SDLActivity.nativeQuit();
|
|
|
@@ -271,6 +312,7 @@ public class SDLActivity extends Activity {
|
|
|
}
|
|
|
|
|
|
super.onDestroy();
|
|
|
+
|
|
|
// Reset everything in case the user re opens the app
|
|
|
SDLActivity.initialize();
|
|
|
}
|
|
|
@@ -287,35 +329,73 @@ public class SDLActivity extends Activity {
|
|
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
|
|
|
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
|
|
keyCode == KeyEvent.KEYCODE_CAMERA ||
|
|
|
- keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
|
|
|
- keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
|
|
|
+ keyCode == KeyEvent.KEYCODE_ZOOM_IN || /* API 11 */
|
|
|
+ keyCode == KeyEvent.KEYCODE_ZOOM_OUT /* API 11 */
|
|
|
) {
|
|
|
return false;
|
|
|
}
|
|
|
return super.dispatchKeyEvent(event);
|
|
|
}
|
|
|
|
|
|
- /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed
|
|
|
- * is the first to be called, mIsSurfaceReady should still be set
|
|
|
- * to 'true' during the call to onPause (in a usual scenario).
|
|
|
- */
|
|
|
- public static void handlePause() {
|
|
|
- if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
|
|
|
- SDLActivity.mIsPaused = true;
|
|
|
- SDLActivity.nativePause();
|
|
|
- mSurface.handlePause();
|
|
|
+ /* Transition to next state */
|
|
|
+ public static void handleNativeState() {
|
|
|
+
|
|
|
+ if (mNextNativeState == mCurrentNativeState) {
|
|
|
+ // Already in same state, discard.
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready.
|
|
|
- * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume
|
|
|
- * every time we get one of those events, only if it comes after surfaceDestroyed
|
|
|
- */
|
|
|
- public static void handleResume() {
|
|
|
- if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady && SDLActivity.mHasFocus) {
|
|
|
- SDLActivity.mIsPaused = false;
|
|
|
- SDLActivity.nativeResume();
|
|
|
- mSurface.handleResume();
|
|
|
+ // Try a transition to init state
|
|
|
+ if (mNextNativeState == NativeState.INIT) {
|
|
|
+
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try a transition to paused state
|
|
|
+ if (mNextNativeState == NativeState.PAUSED) {
|
|
|
+ nativePause();
|
|
|
+ mSurface.handlePause();
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try a transition to resumed state
|
|
|
+ if (mNextNativeState == NativeState.RESUMED) {
|
|
|
+ if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
|
|
|
+ if (mSDLThread == null) {
|
|
|
+ // This is the entry point to the C app.
|
|
|
+ // Start up the C app thread and enable sensor input for the first time
|
|
|
+ // FIXME: Why aren't we enabling sensor input at start?
|
|
|
+
|
|
|
+ final Thread sdlThread = new Thread(new SDLMain(), "SDLThread");
|
|
|
+ mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
+ sdlThread.start();
|
|
|
+
|
|
|
+ // Set up a listener thread to catch when the native thread ends
|
|
|
+ mSDLThread = new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ sdlThread.join();
|
|
|
+ } catch (Exception e) {
|
|
|
+ // Ignore any exception
|
|
|
+ } finally {
|
|
|
+ // Native thread has finished
|
|
|
+ if (!mExitCalledFromJava) {
|
|
|
+ handleNativeExit();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, "SDLThreadListener");
|
|
|
+
|
|
|
+ mSDLThread.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ nativeResume();
|
|
|
+ mSurface.handleResume();
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -354,7 +434,7 @@ public class SDLActivity extends Activity {
|
|
|
protected static class SDLCommandHandler extends Handler {
|
|
|
@Override
|
|
|
public void handleMessage(Message msg) {
|
|
|
- Context context = getContext();
|
|
|
+ Context context = SDL.getContext();
|
|
|
if (context == null) {
|
|
|
Log.e(TAG, "error handling message, getContext() returned null");
|
|
|
return;
|
|
|
@@ -376,16 +456,20 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
|
|
|
+
|
|
|
+ mScreenKeyboardShown = false;
|
|
|
}
|
|
|
break;
|
|
|
case COMMAND_SET_KEEP_SCREEN_ON:
|
|
|
{
|
|
|
- Window window = ((Activity) context).getWindow();
|
|
|
- if (window != null) {
|
|
|
- if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
|
|
|
- window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
- } else {
|
|
|
- window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
+ if (context instanceof Activity) {
|
|
|
+ Window window = ((Activity) context).getWindow();
|
|
|
+ if (window != null) {
|
|
|
+ if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
|
|
|
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
+ } else {
|
|
|
+ window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -410,19 +494,14 @@ public class SDLActivity extends Activity {
|
|
|
}
|
|
|
|
|
|
// C functions we call
|
|
|
- public static native int nativeInit(Object arguments);
|
|
|
+ public static native int nativeSetupJNI();
|
|
|
+ public static native int nativeRunMain(String library, String function, Object arguments);
|
|
|
public static native void nativeLowMemory();
|
|
|
public static native void nativeQuit();
|
|
|
public static native void nativePause();
|
|
|
public static native void nativeResume();
|
|
|
public static native void onNativeDropFile(String filename);
|
|
|
public static native void onNativeResize(int x, int y, int format, float rate);
|
|
|
- public static native int onNativePadDown(int device_id, int keycode);
|
|
|
- public static native int onNativePadUp(int device_id, int keycode);
|
|
|
- public static native void onNativeJoy(int device_id, int axis,
|
|
|
- float value);
|
|
|
- public static native void onNativeHat(int device_id, int hat_id,
|
|
|
- int x, int y);
|
|
|
public static native void onNativeKeyDown(int keycode);
|
|
|
public static native void onNativeKeyUp(int keycode);
|
|
|
public static native void onNativeKeyboardFocusLost();
|
|
|
@@ -431,12 +510,9 @@ public class SDLActivity extends Activity {
|
|
|
int action, float x,
|
|
|
float y, float p);
|
|
|
public static native void onNativeAccel(float x, float y, float z);
|
|
|
+ public static native void onNativeClipboardChanged();
|
|
|
public static native void onNativeSurfaceChanged();
|
|
|
public static native void onNativeSurfaceDestroyed();
|
|
|
- public static native int nativeAddJoystick(int device_id, String name,
|
|
|
- int is_accelerometer, int nbuttons,
|
|
|
- int naxes, int nhats, int nballs);
|
|
|
- public static native int nativeRemoveJoystick(int device_id);
|
|
|
public static native String nativeGetHint(String name);
|
|
|
|
|
|
/**
|
|
|
@@ -449,45 +525,92 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
+ * This is a static method for JNI convenience, it calls a non-static method
|
|
|
+ * so that is can be overridden
|
|
|
*/
|
|
|
- public static boolean sendMessage(int command, int param) {
|
|
|
- return mSingleton.sendCommand(command, Integer.valueOf(param));
|
|
|
+ public static void setOrientation(int w, int h, boolean resizable, String hint)
|
|
|
+ {
|
|
|
+ if (mSingleton != null) {
|
|
|
+ mSingleton.setOrientationBis(w, h, resizable, hint);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This can be overridden
|
|
|
+ */
|
|
|
+ public void setOrientationBis(int w, int h, boolean resizable, String hint)
|
|
|
+ {
|
|
|
+ int orientation = -1;
|
|
|
+
|
|
|
+ if (!Objects.equals(hint, "")) {
|
|
|
+ if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
|
|
+ } else if (hint.contains("LandscapeRight")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
|
|
+ } else if (hint.contains("LandscapeLeft")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
|
|
+ } else if (hint.contains("Portrait") && hint.contains("PortraitUpsideDown")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
|
|
+ } else if (hint.contains("Portrait")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
|
|
+ } else if (hint.contains("PortraitUpsideDown")) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* no valid hint */
|
|
|
+ if (orientation == -1) {
|
|
|
+ if (resizable) {
|
|
|
+ /* no fixed orientation */
|
|
|
+ } else {
|
|
|
+ if (w > h) {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
|
|
+ } else {
|
|
|
+ orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Log.v("SDL", "setOrientation() orientation=" + orientation + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
|
|
|
+ if (orientation != -1) {
|
|
|
+ mSingleton.setRequestedOrientation(orientation);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
*/
|
|
|
- public static Context getContext() {
|
|
|
- return mSingleton;
|
|
|
+ public static boolean isScreenKeyboardShown()
|
|
|
+ {
|
|
|
+ if (mTextEdit == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!mScreenKeyboardShown) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
+ return imm.isAcceptingText();
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
- * @return result of getSystemService(name) but executed on UI thread.
|
|
|
*/
|
|
|
- public Object getSystemServiceFromUiThread(final String name) {
|
|
|
- final Object lock = new Object();
|
|
|
- final Object[] results = new Object[2]; // array for writable variables
|
|
|
- synchronized (lock) {
|
|
|
- runOnUiThread(new Runnable() {
|
|
|
- @Override
|
|
|
- public void run() {
|
|
|
- synchronized (lock) {
|
|
|
- results[0] = getSystemService(name);
|
|
|
- results[1] = Boolean.TRUE;
|
|
|
- lock.notify();
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- if (results[1] == null) {
|
|
|
- try {
|
|
|
- lock.wait();
|
|
|
- } catch (InterruptedException ex) {
|
|
|
- ex.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
+ public static boolean sendMessage(int command, int param) {
|
|
|
+ if (mSingleton == null) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- return results[0];
|
|
|
+ return mSingleton.sendCommand(command, Integer.valueOf(param));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method is called by SDL using JNI.
|
|
|
+ */
|
|
|
+ public static Context getContext() {
|
|
|
+ return SDL.getContext();
|
|
|
}
|
|
|
|
|
|
static class ShowTextInputTask implements Runnable {
|
|
|
@@ -514,7 +637,7 @@ public class SDLActivity extends Activity {
|
|
|
params.topMargin = y;
|
|
|
|
|
|
if (mTextEdit == null) {
|
|
|
- mTextEdit = new DummyEdit(getContext());
|
|
|
+ mTextEdit = new DummyEdit(SDL.getContext());
|
|
|
|
|
|
mLayout.addView(mTextEdit, params);
|
|
|
} else {
|
|
|
@@ -524,8 +647,10 @@ public class SDLActivity extends Activity {
|
|
|
mTextEdit.setVisibility(View.VISIBLE);
|
|
|
mTextEdit.requestFocus();
|
|
|
|
|
|
- InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
+ InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
imm.showSoftInput(mTextEdit, 0);
|
|
|
+
|
|
|
+ mScreenKeyboardShown = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -537,163 +662,28 @@ public class SDLActivity extends Activity {
|
|
|
return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * This method is called by SDL using JNI.
|
|
|
- */
|
|
|
- public static Surface getNativeSurface() {
|
|
|
- return SDLActivity.mSurface.getNativeSurface();
|
|
|
- }
|
|
|
-
|
|
|
- // Audio
|
|
|
-
|
|
|
- /**
|
|
|
- * This method is called by SDL using JNI.
|
|
|
- */
|
|
|
- public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
|
|
- int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
|
|
- int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
|
|
- int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
|
|
-
|
|
|
- Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
|
|
-
|
|
|
- // Let the user pick a larger buffer if they really want -- but ye
|
|
|
- // gods they probably shouldn't, the minimums are horrifyingly high
|
|
|
- // latency already
|
|
|
- desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
|
|
-
|
|
|
- if (mAudioTrack == null) {
|
|
|
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
|
|
|
- channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
|
|
|
-
|
|
|
- // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
|
|
|
- // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
|
|
|
- // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
|
|
|
-
|
|
|
- if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
|
|
|
- Log.e(TAG, "Failed during initialization of Audio Track");
|
|
|
- mAudioTrack = null;
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- mAudioTrack.play();
|
|
|
- }
|
|
|
-
|
|
|
- Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
|
|
-
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * This method is called by SDL using JNI.
|
|
|
- */
|
|
|
- public static void audioWriteShortBuffer(short[] buffer) {
|
|
|
- for (int i = 0; i < buffer.length; ) {
|
|
|
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
|
|
- if (result > 0) {
|
|
|
- i += result;
|
|
|
- } else if (result == 0) {
|
|
|
- try {
|
|
|
- Thread.sleep(1);
|
|
|
- } catch(InterruptedException e) {
|
|
|
- // Nom nom
|
|
|
- }
|
|
|
- } else {
|
|
|
- Log.w(TAG, "SDL audio: error return from write(short)");
|
|
|
- return;
|
|
|
- }
|
|
|
+ public static boolean isTextInputEvent(KeyEvent event) {
|
|
|
+
|
|
|
+ // Key pressed with Ctrl should be sent as SDL_KEYDOWN/SDL_KEYUP and not SDL_TEXTINPUT
|
|
|
+ if (android.os.Build.VERSION.SDK_INT >= 11) {
|
|
|
+ if (event.isCtrlPressed()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /**
|
|
|
- * This method is called by SDL using JNI.
|
|
|
- */
|
|
|
- public static void audioWriteByteBuffer(byte[] buffer) {
|
|
|
- for (int i = 0; i < buffer.length; ) {
|
|
|
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
|
|
- if (result > 0) {
|
|
|
- i += result;
|
|
|
- } else if (result == 0) {
|
|
|
- try {
|
|
|
- Thread.sleep(1);
|
|
|
- } catch(InterruptedException e) {
|
|
|
- // Nom nom
|
|
|
- }
|
|
|
- } else {
|
|
|
- Log.w(TAG, "SDL audio: error return from write(byte)");
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
+ return event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
*/
|
|
|
- public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
|
|
- int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
|
|
- int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
|
|
- int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
|
|
-
|
|
|
- Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
|
|
-
|
|
|
- // Let the user pick a larger buffer if they really want -- but ye
|
|
|
- // gods they probably shouldn't, the minimums are horrifyingly high
|
|
|
- // latency already
|
|
|
- desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
|
|
-
|
|
|
- if (mAudioRecord == null) {
|
|
|
- mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
|
|
|
- channelConfig, audioFormat, desiredFrames * frameSize);
|
|
|
-
|
|
|
- // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
|
|
|
- if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
|
|
|
- Log.e(TAG, "Failed during initialization of AudioRecord");
|
|
|
- mAudioRecord.release();
|
|
|
- mAudioRecord = null;
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- mAudioRecord.startRecording();
|
|
|
- }
|
|
|
-
|
|
|
- Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
|
|
-
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /** This method is called by SDL using JNI. */
|
|
|
- public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
|
|
|
- // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
|
|
- //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
|
|
- return mAudioRecord.read(buffer, 0, buffer.length);
|
|
|
- }
|
|
|
-
|
|
|
- /** This method is called by SDL using JNI. */
|
|
|
- public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
|
|
|
- // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
|
|
- //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
|
|
- return mAudioRecord.read(buffer, 0, buffer.length);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /** This method is called by SDL using JNI. */
|
|
|
- public static void audioClose() {
|
|
|
- if (mAudioTrack != null) {
|
|
|
- mAudioTrack.stop();
|
|
|
- mAudioTrack.release();
|
|
|
- mAudioTrack = null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /** This method is called by SDL using JNI. */
|
|
|
- public static void captureClose() {
|
|
|
- if (mAudioRecord != null) {
|
|
|
- mAudioRecord.stop();
|
|
|
- mAudioRecord.release();
|
|
|
- mAudioRecord = null;
|
|
|
+ public static Surface getNativeSurface() {
|
|
|
+ if (SDLActivity.mSurface == null) {
|
|
|
+ return null;
|
|
|
}
|
|
|
+ return SDLActivity.mSurface.getNativeSurface();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// Input
|
|
|
|
|
|
/**
|
|
|
@@ -713,49 +703,20 @@ public class SDLActivity extends Activity {
|
|
|
return Arrays.copyOf(filtered, used);
|
|
|
}
|
|
|
|
|
|
- // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
|
|
|
- public static boolean handleJoystickMotionEvent(MotionEvent event) {
|
|
|
- return mJoystickHandler.handleMotionEvent(event);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * This method is called by SDL using JNI.
|
|
|
- */
|
|
|
- public static void pollInputDevices() {
|
|
|
- if (SDLActivity.mSDLThread != null) {
|
|
|
- mJoystickHandler.pollInputDevices();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Check if a given device is considered a possible SDL joystick
|
|
|
- public static boolean isDeviceSDLJoystick(int deviceId) {
|
|
|
- InputDevice device = InputDevice.getDevice(deviceId);
|
|
|
- // We cannot use InputDevice.isVirtual before API 16, so let's accept
|
|
|
- // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
|
|
|
- if ((device == null) || (deviceId < 0)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- int sources = device.getSources();
|
|
|
- return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
|
|
|
- ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
|
|
|
- ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
// APK expansion files support
|
|
|
|
|
|
/** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
|
|
|
- private Object expansionFile;
|
|
|
+ private static Object expansionFile;
|
|
|
|
|
|
/** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
|
|
|
- private Method expansionFileMethod;
|
|
|
+ private static Method expansionFileMethod;
|
|
|
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
* @return an InputStream on success or null if no expansion file was used.
|
|
|
* @throws IOException on errors. Message is set for the SDL error message.
|
|
|
*/
|
|
|
- public InputStream openAPKExpansionInputStream(String fileName) throws IOException {
|
|
|
+ public static InputStream openAPKExpansionInputStream(String fileName) throws IOException {
|
|
|
// Get a ZipResourceFile representing a merger of both the main and patch files
|
|
|
if (expansionFile == null) {
|
|
|
String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
|
|
|
@@ -782,7 +743,7 @@ public class SDLActivity extends Activity {
|
|
|
// not a part of Android SDK we access it using reflection
|
|
|
expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
|
|
|
.getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
|
|
|
- .invoke(null, this, mainVersion, patchVersion);
|
|
|
+ .invoke(null, SDL.getContext(), mainVersion, patchVersion);
|
|
|
|
|
|
expansionFileMethod = expansionFile.getClass()
|
|
|
.getMethod("getInputStream", String.class);
|
|
|
@@ -961,7 +922,7 @@ public class SDLActivity extends Activity {
|
|
|
mapping.put(KeyEvent.KEYCODE_ENTER, button);
|
|
|
}
|
|
|
if ((buttonFlags[i] & 0x00000002) != 0) {
|
|
|
- mapping.put(111, button); /* API 11: KeyEvent.KEYCODE_ESCAPE */
|
|
|
+ mapping.put(KeyEvent.KEYCODE_ESCAPE, button); /* API 11 */
|
|
|
}
|
|
|
}
|
|
|
button.setText(buttonTexts[i]);
|
|
|
@@ -1016,18 +977,45 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
return dialog;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method is called by SDL using JNI.
|
|
|
+ */
|
|
|
+ public static boolean clipboardHasText() {
|
|
|
+ return mClipboardHandler.clipboardHasText();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method is called by SDL using JNI.
|
|
|
+ */
|
|
|
+ public static String clipboardGetText() {
|
|
|
+ return mClipboardHandler.clipboardGetText();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This method is called by SDL using JNI.
|
|
|
+ */
|
|
|
+ public static void clipboardSetText(String string) {
|
|
|
+ mClipboardHandler.clipboardSetText(string);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- Simple nativeInit() runnable
|
|
|
+ Simple runnable to start the SDL application
|
|
|
*/
|
|
|
class SDLMain implements Runnable {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
// Runs SDL_main()
|
|
|
- SDLActivity.nativeInit(SDLActivity.mSingleton.getArguments());
|
|
|
+ String library = SDLActivity.mSingleton.getMainSharedObject();
|
|
|
+ String function = SDLActivity.mSingleton.getMainFunction();
|
|
|
+ String[] arguments = SDLActivity.mSingleton.getArguments();
|
|
|
+
|
|
|
+ Log.v("SDL", "Running main function " + function + " from library " + library);
|
|
|
+ SDLActivity.nativeRunMain(library, function, arguments);
|
|
|
|
|
|
- //Log.v("SDL", "SDL thread terminated");
|
|
|
+ Log.v("SDL", "Finished main function");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1062,7 +1050,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
|
|
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
|
|
|
|
|
|
- if(Build.VERSION.SDK_INT >= 12) {
|
|
|
+ if (Build.VERSION.SDK_INT >= 12) {
|
|
|
setOnGenericMotionListener(new SDLGenericMotionListener_API12());
|
|
|
}
|
|
|
|
|
|
@@ -1099,8 +1087,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
@Override
|
|
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
|
Log.v("SDL", "surfaceDestroyed()");
|
|
|
- // Call this *before* setting mIsSurfaceReady to 'false'
|
|
|
- SDLActivity.handlePause();
|
|
|
+
|
|
|
+ // Transition to pause, if needed
|
|
|
+ SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
+
|
|
|
SDLActivity.mIsSurfaceReady = false;
|
|
|
SDLActivity.onNativeSurfaceDestroyed();
|
|
|
}
|
|
|
@@ -1169,12 +1160,12 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
{
|
|
|
// Accept any
|
|
|
}
|
|
|
- else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
|
|
|
+ else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
|
|
|
{
|
|
|
if (mWidth > mHeight) {
|
|
|
skip = true;
|
|
|
}
|
|
|
- } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
|
|
|
+ } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
|
|
|
if (mWidth < mHeight) {
|
|
|
skip = true;
|
|
|
}
|
|
|
@@ -1193,45 +1184,17 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
|
|
|
if (skip) {
|
|
|
Log.v("SDL", "Skip .. Surface is not ready.");
|
|
|
+ SDLActivity.mIsSurfaceReady = false;
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- // Set mIsSurfaceReady to 'true' *before* making a call to handleResume
|
|
|
+
|
|
|
+ /* Surface is ready */
|
|
|
SDLActivity.mIsSurfaceReady = true;
|
|
|
- SDLActivity.onNativeSurfaceChanged();
|
|
|
|
|
|
+ /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
|
|
|
+ SDLActivity.onNativeSurfaceChanged();
|
|
|
|
|
|
- if (SDLActivity.mSDLThread == null) {
|
|
|
- // This is the entry point to the C app.
|
|
|
- // Start up the C app thread and enable sensor input for the first time
|
|
|
-
|
|
|
- final Thread sdlThread = new Thread(new SDLMain(), "SDLThread");
|
|
|
- enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
- sdlThread.start();
|
|
|
-
|
|
|
- // Set up a listener thread to catch when the native thread ends
|
|
|
- SDLActivity.mSDLThread = new Thread(new Runnable(){
|
|
|
- @Override
|
|
|
- public void run(){
|
|
|
- try {
|
|
|
- sdlThread.join();
|
|
|
- }
|
|
|
- catch(Exception e){}
|
|
|
- finally{
|
|
|
- // Native thread has finished
|
|
|
- if (! SDLActivity.mExitCalledFromJava) {
|
|
|
- SDLActivity.handleNativeExit();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }, "SDLThreadListener");
|
|
|
- SDLActivity.mSDLThread.start();
|
|
|
- }
|
|
|
-
|
|
|
- if (SDLActivity.mHasFocus) {
|
|
|
- SDLActivity.handleResume();
|
|
|
- }
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
// Key events
|
|
|
@@ -1244,14 +1207,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
|
|
|
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
|
|
|
// So, retrieve the device itself and check all of its sources
|
|
|
- if (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) {
|
|
|
+ if (SDLControllerManager.isDeviceSDLJoystick(event.getDeviceId())) {
|
|
|
// Note that we process events with specific key codes here
|
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
- if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
|
|
|
+ if (SDLControllerManager.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
|
|
|
return true;
|
|
|
}
|
|
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
- if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
|
|
|
+ if (SDLControllerManager.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
@@ -1441,23 +1404,19 @@ class DummyEdit extends View implements View.OnKeyListener {
|
|
|
|
|
|
@Override
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
-
|
|
|
- // This handles the hardware keyboard input
|
|
|
- if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
|
|
|
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
+ /*
|
|
|
+ * This handles the hardware keyboard input
|
|
|
+ */
|
|
|
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
+ if (SDLActivity.isTextInputEvent(event)) {
|
|
|
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
|
|
}
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
SDLActivity.onNativeKeyDown(keyCode);
|
|
|
return true;
|
|
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
SDLActivity.onNativeKeyUp(keyCode);
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -1484,7 +1443,7 @@ class DummyEdit extends View implements View.OnKeyListener {
|
|
|
|
|
|
outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
|
|
|
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
|
|
- | 33554432 /* API 11: EditorInfo.IME_FLAG_NO_FULLSCREEN */;
|
|
|
+ | EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
|
|
|
|
|
|
return ic;
|
|
|
}
|
|
|
@@ -1499,20 +1458,17 @@ class SDLInputConnection extends BaseInputConnection {
|
|
|
|
|
|
@Override
|
|
|
public boolean sendKeyEvent(KeyEvent event) {
|
|
|
-
|
|
|
/*
|
|
|
- * This handles the keycodes from soft keyboard (and IME-translated
|
|
|
- * input from hardkeyboard)
|
|
|
+ * This handles the keycodes from soft keyboard (and IME-translated input from hardkeyboard)
|
|
|
*/
|
|
|
int keyCode = event.getKeyCode();
|
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
- if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
|
|
|
+ if (SDLActivity.isTextInputEvent(event)) {
|
|
|
commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
|
|
}
|
|
|
SDLActivity.onNativeKeyDown(keyCode);
|
|
|
return true;
|
|
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
|
-
|
|
|
SDLActivity.onNativeKeyUp(keyCode);
|
|
|
return true;
|
|
|
}
|
|
|
@@ -1542,201 +1498,98 @@ class SDLInputConnection extends BaseInputConnection {
|
|
|
@Override
|
|
|
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
|
|
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
|
|
|
- if (beforeLength == 1 && afterLength == 0) {
|
|
|
- // backspace
|
|
|
- return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
|
|
|
- && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
|
|
|
+ // and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
|
|
+ if (beforeLength > 0 && afterLength == 0) {
|
|
|
+ boolean ret = true;
|
|
|
+ // backspace(s)
|
|
|
+ while (beforeLength-- > 0) {
|
|
|
+ boolean ret_key = sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
|
|
|
+ && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
|
|
|
+ ret = ret && ret_key;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
return super.deleteSurroundingText(beforeLength, afterLength);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
|
|
|
-class SDLJoystickHandler {
|
|
|
+interface SDLClipboardHandler {
|
|
|
|
|
|
- /**
|
|
|
- * Handles given MotionEvent.
|
|
|
- * @param event the event to be handled.
|
|
|
- * @return if given event was processed.
|
|
|
- */
|
|
|
- public boolean handleMotionEvent(MotionEvent event) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ public boolean clipboardHasText();
|
|
|
+ public String clipboardGetText();
|
|
|
+ public void clipboardSetText(String string);
|
|
|
|
|
|
- /**
|
|
|
- * Handles adding and removing of input devices.
|
|
|
- */
|
|
|
- public void pollInputDevices() {
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
-/* Actual joystick functionality available for API >= 12 devices */
|
|
|
-class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
|
|
|
|
|
- static class SDLJoystick {
|
|
|
- public int device_id;
|
|
|
- public String name;
|
|
|
- public ArrayList<InputDevice.MotionRange> axes;
|
|
|
- public ArrayList<InputDevice.MotionRange> hats;
|
|
|
- }
|
|
|
- static class RangeComparator implements Comparator<InputDevice.MotionRange> {
|
|
|
- @Override
|
|
|
- public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
|
|
|
- return arg0.getAxis() - arg1.getAxis();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private ArrayList<SDLJoystick> mJoysticks;
|
|
|
+class SDLClipboardHandler_API11 implements
|
|
|
+ SDLClipboardHandler,
|
|
|
+ android.content.ClipboardManager.OnPrimaryClipChangedListener {
|
|
|
|
|
|
- public SDLJoystickHandler_API12() {
|
|
|
+ protected android.content.ClipboardManager mClipMgr;
|
|
|
|
|
|
- mJoysticks = new ArrayList<SDLJoystick>();
|
|
|
+ SDLClipboardHandler_API11() {
|
|
|
+ mClipMgr = (android.content.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
|
|
+ mClipMgr.addPrimaryClipChangedListener(this);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void pollInputDevices() {
|
|
|
- int[] deviceIds = InputDevice.getDeviceIds();
|
|
|
- // It helps processing the device ids in reverse order
|
|
|
- // For example, in the case of the XBox 360 wireless dongle,
|
|
|
- // so the first controller seen by SDL matches what the receiver
|
|
|
- // considers to be the first controller
|
|
|
-
|
|
|
- for(int i=deviceIds.length-1; i>-1; i--) {
|
|
|
- SDLJoystick joystick = getJoystick(deviceIds[i]);
|
|
|
- if (joystick == null) {
|
|
|
- joystick = new SDLJoystick();
|
|
|
- InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
|
|
|
- if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) {
|
|
|
- joystick.device_id = deviceIds[i];
|
|
|
- joystick.name = joystickDevice.getName();
|
|
|
- joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
|
|
- joystick.hats = new ArrayList<InputDevice.MotionRange>();
|
|
|
-
|
|
|
- List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
|
|
|
- Collections.sort(ranges, new RangeComparator());
|
|
|
- for (InputDevice.MotionRange range : ranges ) {
|
|
|
- if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
|
|
- if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
|
|
|
- range.getAxis() == MotionEvent.AXIS_HAT_Y) {
|
|
|
- joystick.hats.add(range);
|
|
|
- }
|
|
|
- else {
|
|
|
- joystick.axes.add(range);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- mJoysticks.add(joystick);
|
|
|
- SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
|
|
|
- joystick.axes.size(), joystick.hats.size()/2, 0);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Check removed devices */
|
|
|
- ArrayList<Integer> removedDevices = new ArrayList<Integer>();
|
|
|
- for(int i=0; i < mJoysticks.size(); i++) {
|
|
|
- int device_id = mJoysticks.get(i).device_id;
|
|
|
- int j;
|
|
|
- for (j=0; j < deviceIds.length; j++) {
|
|
|
- if (device_id == deviceIds[j]) break;
|
|
|
- }
|
|
|
- if (j == deviceIds.length) {
|
|
|
- removedDevices.add(Integer.valueOf(device_id));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for(int i=0; i < removedDevices.size(); i++) {
|
|
|
- int device_id = removedDevices.get(i).intValue();
|
|
|
- SDLActivity.nativeRemoveJoystick(device_id);
|
|
|
- for (int j=0; j < mJoysticks.size(); j++) {
|
|
|
- if (mJoysticks.get(j).device_id == device_id) {
|
|
|
- mJoysticks.remove(j);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ public boolean clipboardHasText() {
|
|
|
+ return mClipMgr.hasText();
|
|
|
}
|
|
|
|
|
|
- protected SDLJoystick getJoystick(int device_id) {
|
|
|
- for(int i=0; i < mJoysticks.size(); i++) {
|
|
|
- if (mJoysticks.get(i).device_id == device_id) {
|
|
|
- return mJoysticks.get(i);
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public String clipboardGetText() {
|
|
|
+ CharSequence text;
|
|
|
+ text = mClipMgr.getText();
|
|
|
+ if (text != null) {
|
|
|
+ return text.toString();
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public boolean handleMotionEvent(MotionEvent event) {
|
|
|
- if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
|
|
|
- int actionPointerIndex = event.getActionIndex();
|
|
|
- int action = event.getActionMasked();
|
|
|
- switch(action) {
|
|
|
- case MotionEvent.ACTION_MOVE:
|
|
|
- SDLJoystick joystick = getJoystick(event.getDeviceId());
|
|
|
- if ( joystick != null ) {
|
|
|
- for (int i = 0; i < joystick.axes.size(); i++) {
|
|
|
- InputDevice.MotionRange range = joystick.axes.get(i);
|
|
|
- /* Normalize the value to -1...1 */
|
|
|
- float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
|
|
|
- SDLActivity.onNativeJoy(joystick.device_id, i, value );
|
|
|
- }
|
|
|
- for (int i = 0; i < joystick.hats.size(); i+=2) {
|
|
|
- int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
|
|
|
- int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
|
|
|
- SDLActivity.onNativeHat(joystick.device_id, i/2, hatX, hatY );
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
+ public void clipboardSetText(String string) {
|
|
|
+ mClipMgr.removePrimaryClipChangedListener(this);
|
|
|
+ mClipMgr.setText(string);
|
|
|
+ mClipMgr.addPrimaryClipChangedListener(this);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onPrimaryClipChanged() {
|
|
|
+ SDLActivity.onNativeClipboardChanged();
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
-class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
|
|
|
- // Generic Motion (mouse hover, joystick...) events go here
|
|
|
+class SDLClipboardHandler_Old implements
|
|
|
+ SDLClipboardHandler {
|
|
|
+
|
|
|
+ protected android.text.ClipboardManager mClipMgrOld;
|
|
|
+
|
|
|
+ SDLClipboardHandler_Old() {
|
|
|
+ mClipMgrOld = (android.text.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
- public boolean onGenericMotion(View v, MotionEvent event) {
|
|
|
- float x, y;
|
|
|
- int action;
|
|
|
-
|
|
|
- switch ( event.getSource() ) {
|
|
|
- case InputDevice.SOURCE_JOYSTICK:
|
|
|
- case InputDevice.SOURCE_GAMEPAD:
|
|
|
- case InputDevice.SOURCE_DPAD:
|
|
|
- return SDLActivity.handleJoystickMotionEvent(event);
|
|
|
-
|
|
|
- case InputDevice.SOURCE_MOUSE:
|
|
|
- action = event.getActionMasked();
|
|
|
- switch (action) {
|
|
|
- case MotionEvent.ACTION_SCROLL:
|
|
|
- x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
|
|
|
- y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
|
|
|
- SDLActivity.onNativeMouse(0, action, x, y);
|
|
|
- return true;
|
|
|
-
|
|
|
- case MotionEvent.ACTION_HOVER_MOVE:
|
|
|
- x = event.getX(0);
|
|
|
- y = event.getY(0);
|
|
|
-
|
|
|
- SDLActivity.onNativeMouse(0, action, x, y);
|
|
|
- return true;
|
|
|
-
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
+ public boolean clipboardHasText() {
|
|
|
+ return mClipMgrOld.hasText();
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public String clipboardGetText() {
|
|
|
+ CharSequence text;
|
|
|
+ text = mClipMgrOld.getText();
|
|
|
+ if (text != null) {
|
|
|
+ return text.toString();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- // Event was not managed
|
|
|
- return false;
|
|
|
+ @Override
|
|
|
+ public void clipboardSetText(String string) {
|
|
|
+ mClipMgrOld.setText(string);
|
|
|
}
|
|
|
}
|
|
|
+
|