diff -r 48ca0191d7ee android-project/app/src/main/AndroidManifest.xml
--- a/android-project/app/src/main/AndroidManifest.xml Wed Jun 03 14:58:38 2020 -0700
+++ b/android-project/app/src/main/AndroidManifest.xml Thu Jun 04 13:34:11 2020 +0200
@@ -69,6 +69,7 @@
@@ -85,6 +86,12 @@
-->
+
+
+
diff -r 48ca0191d7ee android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java Wed Jun 03 14:58:38 2020 -0700
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java Thu Jun 04 13:34:11 2020 +0200
@@ -35,10 +35,9 @@
/**
SDL Activity
*/
-public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
+public class SDLActivity extends Activity {
private static final String TAG = "SDL";
- public static boolean mIsResumedCalled, mHasFocus;
public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24);
// Cursor types
@@ -65,22 +64,13 @@
protected static int mCurrentOrientation;
protected static Locale mCurrentLocale;
- // Handle the state of the native layer
- public enum NativeState {
- INIT, RESUMED, PAUSED
- }
-
- public static NativeState mNextNativeState;
- public static NativeState mCurrentNativeState;
-
/** If shared libraries (e.g. SDL or the native application) could not be loaded. */
public static boolean mBrokenLibraries;
// Main components
protected static SDLActivity mSingleton;
- protected static SDLSurface mSurface;
- protected static View mTextEdit;
- protected static boolean mScreenKeyboardShown;
+ public static View mTextEdit;
+ public static boolean mScreenKeyboardShown;
protected static ViewGroup mLayout;
protected static SDLClipboardHandler mClipboardHandler;
protected static Hashtable mCursors;
@@ -91,6 +81,11 @@
// This is what SDL runs in. It invokes SDL_main(), eventually
protected static Thread mSDLThread;
+ // TODO
+ public static int getRootWindowID() {
+ return 1;
+ }
+
protected static SDLGenericMotionListener_API12 getMotionListener() {
if (mMotionListener == null) {
if (Build.VERSION.SDK_INT >= 26) {
@@ -170,7 +165,6 @@
// The static nature of the singleton and Android quirkyness force us to initialize everything here
// Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
mSingleton = null;
- mSurface = null;
mTextEdit = null;
mLayout = null;
mClipboardHandler = null;
@@ -178,10 +172,6 @@
mLastCursorID = 0;
mSDLThread = null;
mBrokenLibraries = false;
- mIsResumedCalled = false;
- mHasFocus = true;
- mNextNativeState = NativeState.INIT;
- mCurrentNativeState = NativeState.INIT;
}
// Setup
@@ -249,16 +239,10 @@
mHIDDeviceManager = HIDDeviceManager.acquire(this);
- // Set up the surface
- mSurface = new SDLSurface(getApplication());
-
- mLayout = new RelativeLayout(this);
- mLayout.addView(mSurface);
-
// Get our current screen orientation and pass it down.
mCurrentOrientation = SDLActivity.getCurrentOrientation();
// Only record current orientation
- SDLActivity.onNativeOrientationChanged(mCurrentOrientation);
+ SDLActivity.onNativeOrientationChanged(-1, mCurrentOrientation);
try {
if (Build.VERSION.SDK_INT < 24) {
@@ -269,12 +253,6 @@
} catch(Exception ignored) {
}
- setContentView(mLayout);
-
- setWindowStyle(false);
-
- getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
-
// Get filename from "Open with" of another application
Intent intent = getIntent();
if (intent != null && intent.getData() != null) {
@@ -284,30 +262,16 @@
SDLActivity.onNativeDropFile(filename);
}
}
+
+ // 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?
+
+ mSDLThread = new Thread(new SDLMain(), "SDLThread");
+ mSDLThread.start();
}
- protected void pauseNativeThread() {
- mNextNativeState = NativeState.PAUSED;
- mIsResumedCalled = false;
-
- if (SDLActivity.mBrokenLibraries) {
- return;
- }
-
- SDLActivity.handleNativeState();
- }
-
- protected void resumeNativeThread() {
- mNextNativeState = NativeState.RESUMED;
- mIsResumedCalled = true;
-
- if (SDLActivity.mBrokenLibraries) {
- return;
- }
-
- SDLActivity.handleNativeState();
- }
-
+
// Events
@Override
protected void onPause() {
@@ -317,9 +281,6 @@
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(true);
}
- if (!mHasMultiWindow) {
- pauseNativeThread();
- }
}
@Override
@@ -330,8 +291,15 @@
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(false);
}
- if (!mHasMultiWindow) {
- resumeNativeThread();
+
+ // After a background/foreground, SDLActivity is brought to front (but it has no UI).
+ // So bring an existing SDL window to front, instead.
+ if (SDLWindowActivity.mMapThis.size() != 0) {
+ Log.v(TAG, "SDLActivity resumes, bring to front some existing window");
+ Intent i = new Intent(mSingleton.getApplicationContext(), SDLWindowActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); // optionnal
+ i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ mSingleton.startActivity(i);
}
}
@@ -339,18 +307,12 @@
protected void onStop() {
Log.v(TAG, "onStop()");
super.onStop();
- if (mHasMultiWindow) {
- pauseNativeThread();
- }
}
@Override
protected void onStart() {
Log.v(TAG, "onStart()");
super.onStart();
- if (mHasMultiWindow) {
- resumeNativeThread();
- }
}
public static int getCurrentOrientation() {
@@ -381,32 +343,6 @@
}
@Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
-
- if (SDLActivity.mBrokenLibraries) {
- return;
- }
-
- mHasFocus = hasFocus;
- if (hasFocus) {
- mNextNativeState = NativeState.RESUMED;
- SDLActivity.getMotionListener().reclaimRelativeMouseModeIfNeeded();
-
- SDLActivity.handleNativeState();
- nativeFocusChanged(true);
-
- } else {
- nativeFocusChanged(false);
- if (!mHasMultiWindow) {
- mNextNativeState = NativeState.PAUSED;
- SDLActivity.handleNativeState();
- }
- }
- }
-
- @Override
public void onLowMemory() {
Log.v(TAG, "onLowMemory()");
super.onLowMemory();
@@ -433,6 +369,17 @@
protected void onDestroy() {
Log.v(TAG, "onDestroy()");
+
+ Log.v(TAG, "onDestroy() remaining windows=" + SDLWindowActivity.mMapThis.size());
+ for (int id : SDLWindowActivity.mMapThis.keySet()) {
+ destroyWindow(id);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
if (mHIDDeviceManager != null) {
HIDDeviceManager.release(mHIDDeviceManager);
mHIDDeviceManager = null;
@@ -522,57 +469,6 @@
return super.dispatchKeyEvent(event);
}
- /* Transition to next state */
- public static void handleNativeState() {
-
- if (mNextNativeState == mCurrentNativeState) {
- // Already in same state, discard.
- return;
- }
-
- // Try a transition to init state
- if (mNextNativeState == NativeState.INIT) {
-
- mCurrentNativeState = mNextNativeState;
- return;
- }
-
- // Try a transition to paused state
- if (mNextNativeState == NativeState.PAUSED) {
- if (mSDLThread != null) {
- nativePause();
- }
- if (mSurface != null) {
- mSurface.handlePause();
- }
- mCurrentNativeState = mNextNativeState;
- return;
- }
-
- // Try a transition to resumed state
- if (mNextNativeState == NativeState.RESUMED) {
- if (mSurface.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?
-
- mSDLThread = new Thread(new SDLMain(), "SDLThread");
- mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
- mSDLThread.start();
-
- // No nativeResume(), don't signal Android_ResumeSem
- mSurface.handleResume();
- } else {
- nativeResume();
- mSurface.handleResume();
- }
-
- mCurrentNativeState = mNextNativeState;
- }
- }
- }
-
// Messages from the SDLMain thread
static final int COMMAND_CHANGE_TITLE = 1;
static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
@@ -582,8 +478,6 @@
protected static final int COMMAND_USER = 0x8000;
- protected static boolean mFullscreenModeActive;
-
/**
* This method is called by SDL if SDL did not handle a message itself.
* This happens if a received message contains an unsupported command.
@@ -596,214 +490,34 @@
return false;
}
- /**
- * A Handler class for Messages from native SDL applications.
- * It uses current Activities as target (e.g. for the title).
- * static to prevent implicit references to enclosing object.
- */
- protected static class SDLCommandHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- Context context = SDL.getContext();
- if (context == null) {
- Log.e(TAG, "error handling message, getContext() returned null");
- return;
- }
- switch (msg.arg1) {
- case COMMAND_CHANGE_TITLE:
- if (context instanceof Activity) {
- ((Activity) context).setTitle((String)msg.obj);
- } else {
- Log.e(TAG, "error handling message, getContext() returned no Activity");
- }
- break;
- case COMMAND_CHANGE_WINDOW_STYLE:
- if (Build.VERSION.SDK_INT < 19) {
- // This version of Android doesn't support the immersive fullscreen mode
- break;
- }
- if (context instanceof Activity) {
- Window window = ((Activity) context).getWindow();
- if (window != null) {
- if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
- int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
- window.getDecorView().setSystemUiVisibility(flags);
- window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- SDLActivity.mFullscreenModeActive = true;
- } else {
- int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
- window.getDecorView().setSystemUiVisibility(flags);
- window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- SDLActivity.mFullscreenModeActive = false;
- }
- }
- } else {
- Log.e(TAG, "error handling message, getContext() returned no Activity");
- }
- break;
- case COMMAND_TEXTEDIT_HIDE:
- if (mTextEdit != null) {
- // Note: On some devices setting view to GONE creates a flicker in landscape.
- // Setting the View's sizes to 0 is similar to GONE but without the flicker.
- // The sizes will be set to useful values when the keyboard is shown again.
- mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
-
- InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
-
- mScreenKeyboardShown = false;
-
- mSurface.requestFocus();
- }
- break;
- case COMMAND_SET_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;
- }
- case COMMAND_CHANGE_SURFACEVIEW_FORMAT:
- {
- int format = (Integer) msg.obj;
- int pf;
-
- if (SDLActivity.mSurface == null) {
- return;
- }
-
- SurfaceHolder holder = SDLActivity.mSurface.getHolder();
- if (holder == null) {
- return;
- }
-
- if (format == 1) {
- pf = PixelFormat.RGBA_8888;
- } else if (format == 2) {
- pf = PixelFormat.RGBX_8888;
- } else {
- pf = PixelFormat.RGB_565;
- }
-
- holder.setFormat(pf);
-
- break;
- }
- default:
- if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
- Log.e(TAG, "error handling message, command is " + msg.arg1);
- }
- }
- }
- }
-
- // Handler for the messages
- Handler commandHandler = new SDLCommandHandler();
-
- // Send a message from the SDLMain thread
- boolean sendCommand(int command, Object data) {
- Message msg = commandHandler.obtainMessage();
- msg.arg1 = command;
- msg.obj = data;
- boolean result = commandHandler.sendMessage(msg);
-
- if ((Build.VERSION.SDK_INT >= 19) && (command == COMMAND_CHANGE_WINDOW_STYLE)) {
- // Ensure we don't return until the resize has actually happened,
- // or 500ms have passed.
-
- boolean bShouldWait = false;
-
- if (data instanceof Integer) {
- // Let's figure out if we're already laid out fullscreen or not.
- Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- android.util.DisplayMetrics realMetrics = new android.util.DisplayMetrics();
- display.getRealMetrics( realMetrics );
-
- boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
- (realMetrics.heightPixels == mSurface.getHeight()));
-
- if (((Integer)data).intValue() == 1) {
- // If we aren't laid out fullscreen or actively in fullscreen mode already, we're going
- // to change size and should wait for surfaceChanged() before we return, so the size
- // is right back in native code. If we're already laid out fullscreen, though, we're
- // not going to change size even if we change decor modes, so we shouldn't wait for
- // surfaceChanged() -- which may not even happen -- and should return immediately.
- bShouldWait = !bFullscreenLayout;
- }
- else {
- // If we're laid out fullscreen (even if the status bar and nav bar are present),
- // or are actively in fullscreen, we're going to change size and should wait for
- // surfaceChanged before we return, so the size is right back in native code.
- bShouldWait = bFullscreenLayout;
- }
- }
-
- if (bShouldWait && (SDLActivity.getContext() != null)) {
- // We'll wait for the surfaceChanged() method, which will notify us
- // when called. That way, we know our current size is really the
- // size we need, instead of grabbing a size that's still got
- // the navigation and/or status bars before they're hidden.
- //
- // We'll wait for up to half a second, because some devices
- // take a surprisingly long time for the surface resize, but
- // then we'll just give up and return.
- //
- synchronized(SDLActivity.getContext()) {
- try {
- SDLActivity.getContext().wait(500);
- }
- catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- }
- }
-
- return result;
- }
-
// C functions we call
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 nativeSendQuit();
public static native void nativeQuit();
- public static native void nativePause();
- public static native void nativeResume();
- public static native void nativeFocusChanged(boolean hasFocus);
+ public static native void nativePause(int windowID);
+ public static native void nativeResume(int windowID);
+ public static native void nativeFocusChanged(int windowID, boolean hasFocus);
public static native void onNativeDropFile(String filename);
- public static native void nativeSetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, int format, float rate);
- public static native void onNativeResize();
+ public static native void nativeSetScreenResolution(int windowID, int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, int format, float rate);
+ public static native void onNativeResize(int windowID);
public static native void onNativeKeyDown(int keycode);
public static native void onNativeKeyUp(int keycode);
public static native boolean onNativeSoftReturnKey();
public static native void onNativeKeyboardFocusLost();
- public static native void onNativeMouse(int button, int action, float x, float y, boolean relative);
- public static native void onNativeTouch(int touchDevId, int pointerFingerId,
+ public static native void onNativeMouse(int windowID, int button, int action, float x, float y, boolean relative);
+ public static native void onNativeTouch(int windowID, int touchDevId, int pointerFingerId,
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 onNativeSurfaceCreated();
- public static native void onNativeSurfaceChanged();
- public static native void onNativeSurfaceDestroyed();
+ public static native void onNativeSurfaceCreated(int windowID);
+ public static native void onNativeSurfaceChanged(int windowID);
+ public static native void onNativeSurfaceDestroyed(int windowID);
public static native String nativeGetHint(String name);
public static native void nativeSetenv(String name, String value);
- public static native void onNativeOrientationChanged(int orientation);
+ public static native void onNativeOrientationChanged(int windowID, int orientation);
public static native void nativeAddTouch(int touchId, String name);
public static native void nativePermissionResult(int requestCode, boolean result);
public static native void onNativeLocaleChanged();
@@ -811,17 +525,22 @@
/**
* This method is called by SDL using JNI.
*/
- public static boolean setActivityTitle(String title) {
- // Called from SDLMain() thread and can't directly affect the view
- return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+ public static boolean setActivityTitle(int windowID, String title) {
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (window != null) {
+ return window.sendCommand(COMMAND_CHANGE_TITLE, title);
+ }
+ return false;
}
/**
* This method is called by SDL using JNI.
*/
- public static void setWindowStyle(boolean fullscreen) {
- // Called from SDLMain() thread and can't directly affect the view
- mSingleton.sendCommand(COMMAND_CHANGE_WINDOW_STYLE, fullscreen ? 1 : 0);
+ public static void setWindowStyle(int windowID, boolean fullscreen) {
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (window != null) {
+ window.sendCommand(COMMAND_CHANGE_WINDOW_STYLE, fullscreen ? 1 : 0);
+ }
}
/**
@@ -829,17 +548,17 @@
* This is a static method for JNI convenience, it calls a non-static method
* so that is can be overridden
*/
- public static void setOrientation(int w, int h, boolean resizable, String hint)
+ public static void setOrientation(int windowID, int w, int h, boolean resizable, String hint)
{
if (mSingleton != null) {
- mSingleton.setOrientationBis(w, h, resizable, hint);
+ mSingleton.setOrientationBis(windowID, w, h, resizable, hint);
}
}
/**
* This can be overridden
*/
- public void setOrientationBis(int w, int h, boolean resizable, String hint)
+ public void setOrientationBis(int windowID, int w, int h, boolean resizable, String hint)
{
int orientation_landscape = -1;
int orientation_portrait = -1;
@@ -996,10 +715,12 @@
* This method is called by SDL using JNI.
*/
public static boolean sendMessage(int command, int param) {
- if (mSingleton == null) {
- return false;
+ for (SDLWindowActivity window : SDLWindowActivity.mMapThis.values()) {
+ if (window != null) {
+ window.sendCommand(command, Integer.valueOf(param));
+ }
}
- return mSingleton.sendCommand(command, Integer.valueOf(param));
+ return true; // TODO
}
/**
@@ -1170,7 +891,12 @@
*/
public static boolean showTextInput(int x, int y, int w, int h) {
// Transfer the task to the main thread as a Runnable
- return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
+ for (SDLWindowActivity window : SDLWindowActivity.mMapThis.values()) {
+ if (window != null) {
+ window.commandHandler.post(new ShowTextInputTask(x, y, w, h));
+ }
+ }
+ return true; // TODO
}
public static boolean isTextInputEvent(KeyEvent event) {
@@ -1186,19 +912,42 @@
/**
* This method is called by SDL using JNI.
*/
- public static Surface getNativeSurface() {
- if (SDLActivity.mSurface == null) {
- return null;
+ public static Surface getNativeSurface(int windowID) {
+ Log.v(TAG, "getNativeSurface windowID=" + windowID);
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (window != null) {
+ SDLSurface surface = window.mSurface;
+ if (surface != null) {
+ return surface.getNativeSurface();
+ }
}
- return SDLActivity.mSurface.getNativeSurface();
+ return null;
}
/**
* This method is called by SDL using JNI.
*/
- public static void setSurfaceViewFormat(int format) {
- mSingleton.sendCommand(COMMAND_CHANGE_SURFACEVIEW_FORMAT, format);
- return;
+ public static boolean isSurfaceReady(int windowID) {
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (window != null) {
+ SDLSurface surface = window.mSurface;
+ if (surface != null) {
+ return surface.isSurfaceReady();
+ } else {
+ Log.v(TAG, "Surface was destroyed - isSurfaceReady windowID=" + windowID);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void setSurfaceViewFormat(int windowID, int format) {
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (window != null) {
+ window.sendCommand(COMMAND_CHANGE_SURFACEVIEW_FORMAT, format);
+ }
}
// Input
@@ -1492,32 +1241,6 @@
return dialog;
}
- private final Runnable rehideSystemUi = new Runnable() {
- @Override
- public void run() {
- int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
-
- SDLActivity.this.getWindow().getDecorView().setSystemUiVisibility(flags);
- }
- };
-
- public void onSystemUiVisibilityChange(int visibility) {
- if (SDLActivity.mFullscreenModeActive && ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0 || (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0)) {
-
- Handler handler = getWindow().getDecorView().getHandler();
- if (handler != null) {
- handler.removeCallbacks(rehideSystemUi); // Prevent a hide loop.
- handler.postDelayed(rehideSystemUi, 2000);
- }
-
- }
- }
-
/**
* This method is called by SDL using JNI.
*/
@@ -1565,7 +1288,12 @@
if (Build.VERSION.SDK_INT >= 24) {
try {
- mSurface.setPointerIcon(mCursors.get(cursorID));
+ for (SDLWindowActivity window : SDLWindowActivity.mMapThis.values()) {
+ SDLSurface surface = window.mSurface;
+ if (surface != null) {
+ surface.setPointerIcon(mCursors.get(cursorID));
+ }
+ }
} catch (Exception e) {
return false;
}
@@ -1620,7 +1348,12 @@
}
if (Build.VERSION.SDK_INT >= 24) {
try {
- mSurface.setPointerIcon(PointerIcon.getSystemIcon(SDL.getContext(), cursor_type));
+ for (SDLWindowActivity window : SDLWindowActivity.mMapThis.values()) {
+ SDLSurface surface = window.mSurface;
+ if (surface != null) {
+ surface.setPointerIcon(PointerIcon.getSystemIcon(SDL.getContext(), cursor_type));
+ }
+ }
} catch (Exception e) {
return false;
}
@@ -1653,6 +1386,46 @@
nativePermissionResult(requestCode, false);
}
}
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void createWindow(int windowID) {
+ Log.v(TAG, "Create activity windowID=" + windowID);
+
+ Intent i = new Intent(mSingleton.getApplicationContext(), SDLWindowActivity.class);
+ Bundle b = new Bundle();
+ b.putInt("windowID", windowID);
+ i.putExtras(b);
+ i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); // optionnal
+// i.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); // optionnal
+ i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ mSingleton.startActivity(i);
+
+ // Wait for the activity to be created
+ while (SDLWindowActivity.mMapThis.containsKey(windowID) == false) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ Log.v(TAG, "Create activity windowID=" + windowID + " done!");
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void destroyWindow(int windowID) {
+ Log.v(TAG, "Delete activity windowID=" + windowID);
+ if (windowID != 1) {
+ SDLWindowActivity window = SDLWindowActivity.mMapThis.get(windowID);
+ if (!window.isFinishing()) {
+ SDLWindowActivity.mMapThis.get(windowID).finish();
+ }
+ SDLWindowActivity.mMapThis.remove(windowID);
+ }
+ }
}
/**
@@ -1698,6 +1471,19 @@
class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
View.OnKeyListener, View.OnTouchListener, SensorEventListener {
+ public int mWindowID;
+
+ public boolean mIsResumedCalled, mHasFocus;
+
+ // Handle the state of the native layer
+ public enum NativeState {
+ INIT, RESUMED, PAUSED
+ }
+
+ public NativeState mNextNativeState;
+ public NativeState mCurrentNativeState;
+
+
// Sensors
protected SensorManager mSensorManager;
protected Display mDisplay;
@@ -1709,8 +1495,15 @@
public boolean mIsSurfaceReady;
// Startup
- public SDLSurface(Context context) {
+ public SDLSurface(Context context, int windowID) {
super(context);
+
+ mIsResumedCalled = false;
+ mHasFocus = false;
+ mNextNativeState = NativeState.INIT;
+ mCurrentNativeState = NativeState.INIT;
+ mIsSurfaceReady = false;
+
getHolder().addCallback(this);
setFocusable(true);
@@ -1719,6 +1512,7 @@
setOnKeyListener(this);
setOnTouchListener(this);
+ mWindowID = windowID;
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
@@ -1727,8 +1521,29 @@
// Some arbitrary defaults to avoid a potential division by zero
mWidth = 1.0f;
mHeight = 1.0f;
+ }
- mIsSurfaceReady = false;
+
+ protected void pauseNativeThread() {
+ mNextNativeState = NativeState.PAUSED;
+ mIsResumedCalled = false;
+
+ if (SDLActivity.mBrokenLibraries) {
+ return;
+ }
+
+ handleNativeState();
+ }
+
+ protected void resumeNativeThread() {
+ mNextNativeState = NativeState.RESUMED;
+ mIsResumedCalled = true;
+
+ if (SDLActivity.mBrokenLibraries) {
+ return;
+ }
+
+ handleNativeState();
}
public void handlePause() {
@@ -1744,6 +1559,53 @@
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
}
+ /* Transition to next state */
+ public void handleNativeState() {
+
+ if (mNextNativeState == mCurrentNativeState) {
+ // Already in same state, discard.
+ return;
+ }
+
+ // Try a transition to init state
+ if (mNextNativeState == NativeState.INIT) {
+
+ mCurrentNativeState = mNextNativeState;
+ return;
+ }
+
+ // Try a transition to paused state
+ if (mNextNativeState == NativeState.PAUSED) {
+ if (SDLActivity.mSDLThread != null) {
+ SDLActivity.nativePause(mWindowID);
+ }
+
+ handlePause();
+ mCurrentNativeState = mNextNativeState;
+ return;
+ }
+
+ // Try a transition to resumed state
+ if (mNextNativeState == NativeState.RESUMED) {
+ if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
+ if (SDLActivity.mSDLThread != null) {
+ SDLActivity.nativeResume(mWindowID);
+ }
+
+ handleResume();
+ mCurrentNativeState = mNextNativeState;
+ }
+ }
+ }
+
+ public boolean isSurfaceReady() {
+ if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public Surface getNativeSurface() {
return getHolder().getSurface();
}
@@ -1751,28 +1613,28 @@
// Called when we have a valid drawing surface
@Override
public void surfaceCreated(SurfaceHolder holder) {
- Log.v("SDL", "surfaceCreated()");
- SDLActivity.onNativeSurfaceCreated();
+ Log.v("SDL", "surfaceCreated() windowID=" + mWindowID);
+ SDLActivity.onNativeSurfaceCreated(mWindowID);
}
// Called when we lose the surface
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v("SDL", "surfaceDestroyed()");
+ Log.v("SDL", "surfaceDestroyed() windowID=" + mWindowID);
// Transition to pause, if needed
- SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
- SDLActivity.handleNativeState();
+ mNextNativeState = NativeState.PAUSED;
+ handleNativeState();
mIsSurfaceReady = false;
- SDLActivity.onNativeSurfaceDestroyed();
+ SDLActivity.onNativeSurfaceDestroyed(mWindowID);
}
// Called when the surface is resized
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
- Log.v("SDL", "surfaceChanged()");
+ Log.v("SDL", "surfaceChanged() windowID=" + mWindowID);
if (SDLActivity.mSingleton == null) {
return;
@@ -1824,8 +1686,8 @@
Log.v("SDL", "Window size: " + width + "x" + height);
Log.v("SDL", "Device size: " + nDeviceWidth + "x" + nDeviceHeight);
- SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, sdlFormat, mDisplay.getRefreshRate());
- SDLActivity.onNativeResize();
+ SDLActivity.nativeSetScreenResolution(mWindowID, width, height, nDeviceWidth, nDeviceHeight, sdlFormat, mDisplay.getRefreshRate());
+ SDLActivity.onNativeResize(mWindowID);
// Prevent a screen distortion glitch,
// for instance when the device is in Landscape and a Portrait App is resumed.
@@ -1875,13 +1737,35 @@
}
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
- SDLActivity.onNativeSurfaceChanged();
+ SDLActivity.onNativeSurfaceChanged(mWindowID);
/* Surface is ready */
mIsSurfaceReady = true;
- SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
- SDLActivity.handleNativeState();
+ mNextNativeState = NativeState.RESUMED;
+ handleNativeState();
+ }
+
+ public void focusChanged(boolean hasFocus) {
+ if (SDLActivity.mBrokenLibraries) {
+ return;
+ }
+
+ mHasFocus = hasFocus;
+ if (hasFocus) {
+ mNextNativeState = NativeState.RESUMED;
+ SDLActivity.getMotionListener().reclaimRelativeMouseModeIfNeeded();
+
+ handleNativeState();
+ SDLActivity.nativeFocusChanged(mWindowID, true);
+
+ } else {
+ SDLActivity.nativeFocusChanged(mWindowID, false);
+ if (!SDLActivity.mHasMultiWindow) {
+ mNextNativeState = NativeState.PAUSED;
+ handleNativeState();
+ }
+ }
}
// Key events
@@ -1982,7 +1866,7 @@
x = motionListener.getEventX(event);
y = motionListener.getEventY(event);
- SDLActivity.onNativeMouse(mouseButton, action, x, y, motionListener.inRelativeMode());
+ SDLActivity.onNativeMouse(mWindowID, mouseButton, action, x, y, motionListener.inRelativeMode());
} else {
switch(action) {
case MotionEvent.ACTION_MOVE:
@@ -1996,7 +1880,7 @@
// see the documentation of getPressure(i)
p = 1.0f;
}
- SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ SDLActivity.onNativeTouch(mWindowID, touchDevId, pointerFingerId, action, x, y, p);
}
break;
@@ -2020,7 +1904,7 @@
// see the documentation of getPressure(i)
p = 1.0f;
}
- SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ SDLActivity.onNativeTouch(mWindowID, touchDevId, pointerFingerId, action, x, y, p);
break;
case MotionEvent.ACTION_CANCEL:
@@ -2034,7 +1918,7 @@
// see the documentation of getPressure(i)
p = 1.0f;
}
- SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
+ SDLActivity.onNativeTouch(mWindowID, touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
}
break;
@@ -2098,7 +1982,7 @@
if (newOrientation != SDLActivity.mCurrentOrientation) {
SDLActivity.mCurrentOrientation = newOrientation;
- SDLActivity.onNativeOrientationChanged(newOrientation);
+ SDLActivity.onNativeOrientationChanged(mWindowID, newOrientation);
}
SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
@@ -2119,14 +2003,14 @@
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(mWindowID, 0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_MOVE:
x = event.getX(0);
y = event.getY(0);
- SDLActivity.onNativeMouse(0, action, x, y, true);
+ SDLActivity.onNativeMouse(mWindowID, 0, action, x, y, true);
return true;
case MotionEvent.ACTION_BUTTON_PRESS:
@@ -2144,7 +2028,7 @@
y = event.getY(0);
int button = event.getButtonState();
- SDLActivity.onNativeMouse(button, action, x, y, true);
+ SDLActivity.onNativeMouse(mWindowID, button, action, x, y, true);
return true;
}
diff -r 48ca0191d7ee android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
--- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java Wed Jun 03 14:58:38 2020 -0700
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java Thu Jun 04 13:34:11 2020 +0200
@@ -560,14 +560,14 @@
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, false);
return true;
default:
@@ -625,7 +625,7 @@
if (action == MotionEvent.ACTION_HOVER_MOVE) {
float x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
float y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
- SDLActivity.onNativeMouse(0, action, x, y, true);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, true);
return true;
}
}
@@ -696,13 +696,13 @@
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, false);
return true;
default:
@@ -716,13 +716,13 @@
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
- SDLActivity.onNativeMouse(0, action, x, y, false);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
- SDLActivity.onNativeMouse(0, action, x, y, true);
+ SDLActivity.onNativeMouse(SDLActivity.mSingleton.getRootWindowID(), 0, action, x, y, true);
return true;
default:
diff -r 48ca0191d7ee android-project/app/src/main/java/org/libsdl/app/SDLWindowActivity.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLWindowActivity.java Thu Jun 04 13:34:11 2020 +0200
@@ -0,0 +1,350 @@
+package org.libsdl.app;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.lang.reflect.Method;
+import java.lang.Math;
+
+import android.app.*;
+import android.content.*;
+import android.content.res.Configuration;
+import android.text.InputType;
+import android.view.*;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.RelativeLayout;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.os.*;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseArray;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.hardware.*;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ApplicationInfo;
+
+import java.util.HashMap;
+
+public class SDLWindowActivity extends Activity implements View.OnSystemUiVisibilityChangeListener
+{
+ public static final boolean mHasMultiWindow = SDLActivity.mHasMultiWindow;
+ private static final String TAG = "SDLWindow";
+
+ public static HashMap mMapThis = new HashMap();
+
+ protected SDLSurface mSurface;
+ protected ViewGroup mLayout;
+ protected int mWindowID;
+
+ // Handler for the messages
+ Handler commandHandler;
+
+
+ protected boolean mFullscreenModeActive;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle b = getIntent().getExtras();
+ if(b != null) {
+ mWindowID = b.getInt("windowID");
+ } else {
+ mWindowID = -1;
+ }
+
+ Log.v(TAG, "onCreate() windowID=" + mWindowID);
+
+ boolean launchedFromHistory = (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY;
+ if (launchedFromHistory) {
+ Log.v(TAG, "launchedFromHistory finish() windowID=" + mWindowID);
+ finish();
+ return;
+ }
+
+
+ commandHandler= new SDLCommandHandler();
+
+ // Set up the surface
+ mSurface = new SDLSurface(getApplication(), mWindowID);
+
+ mLayout = new RelativeLayout(this);
+ mLayout.addView(mSurface);
+
+ setContentView(mLayout);
+
+ mMapThis.put(mWindowID, this);
+
+
+ SDLActivity.setWindowStyle(mWindowID, false);
+
+ getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
+
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.v(TAG, "onDestroy() windowID=" + mWindowID);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ Log.v(TAG, "onWindowFocusChanged() windowID=" + mWindowID + " hasFocus=" + hasFocus);
+ mSurface.focusChanged(hasFocus);
+ }
+
+ // Events
+ @Override
+ protected void onPause() {
+ Log.v(TAG, "onPause() windowID=" + mWindowID);
+ super.onPause();
+ if (!mHasMultiWindow) {
+ mSurface.pauseNativeThread();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ Log.v(TAG, "onResume() windowID=" + mWindowID);
+ super.onResume();
+ if (!mHasMultiWindow) {
+ mSurface.resumeNativeThread();
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ Log.v(TAG, "onStop() windowID=" + mWindowID);
+ super.onStop();
+ if (mHasMultiWindow) {
+ mSurface.pauseNativeThread();
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ Log.v(TAG, "onStart() windowID=" + mWindowID);
+ super.onStart();
+ if (mHasMultiWindow) {
+ mSurface.resumeNativeThread();
+ }
+ }
+
+ /**
+ * A Handler class for Messages from native SDL applications.
+ * It uses current Activities as target (e.g. for the title).
+ * static to prevent implicit references to enclosing object.
+ */
+ protected class SDLCommandHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ Context context = SDL.getContext();
+ if (context == null) {
+ Log.e(TAG, "error handling message, getContext() returned null");
+ return;
+ }
+ switch (msg.arg1) {
+ case SDLActivity.COMMAND_CHANGE_TITLE:
+ if (context instanceof Activity) {
+ ((Activity) context).setTitle((String)msg.obj);
+ } else {
+ Log.e(TAG, "error handling message, getContext() returned no Activity");
+ }
+ break;
+ case SDLActivity.COMMAND_CHANGE_WINDOW_STYLE:
+ if (Build.VERSION.SDK_INT < 19) {
+ // This version of Android doesn't support the immersive fullscreen mode
+ break;
+ }
+ if (context instanceof Activity) {
+ Window window = ((Activity) context).getWindow();
+ if (window != null) {
+ if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
+ int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
+ window.getDecorView().setSystemUiVisibility(flags);
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ mFullscreenModeActive = true;
+ } else {
+ int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
+ window.getDecorView().setSystemUiVisibility(flags);
+ window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ mFullscreenModeActive = false;
+ }
+ }
+ } else {
+ Log.e(TAG, "error handling message, getContext() returned no Activity");
+ }
+ break;
+ case SDLActivity.COMMAND_TEXTEDIT_HIDE:
+ if (SDLActivity.mSingleton.mTextEdit != null) {
+ // Note: On some devices setting view to GONE creates a flicker in landscape.
+ // Setting the View's sizes to 0 is similar to GONE but without the flicker.
+ // The sizes will be set to useful values when the keyboard is shown again.
+ SDLActivity.mSingleton.mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
+
+ InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(SDLActivity.mSingleton.mTextEdit.getWindowToken(), 0);
+
+ SDLActivity.mSingleton.mScreenKeyboardShown = false;
+
+ mSurface.requestFocus();
+ }
+ break;
+ case SDLActivity.COMMAND_SET_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;
+ }
+ case SDLActivity.COMMAND_CHANGE_SURFACEVIEW_FORMAT:
+ {
+ int format = (Integer) msg.obj;
+ int pf;
+
+ if (mSurface == null) {
+ return;
+ }
+
+ SurfaceHolder holder = mSurface.getHolder();
+ if (holder == null) {
+ return;
+ }
+
+ if (format == 1) {
+ pf = PixelFormat.RGBA_8888;
+ } else if (format == 2) {
+ pf = PixelFormat.RGBX_8888;
+ } else {
+ pf = PixelFormat.RGB_565;
+ }
+
+ holder.setFormat(pf);
+
+ break;
+ }
+ default:
+ if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
+ Log.e(TAG, "error handling message, command is " + msg.arg1);
+ }
+ }
+ }
+ }
+
+ // Send a message from the SDLMain thread
+ boolean sendCommand(int command, Object data) {
+ Message msg = commandHandler.obtainMessage();
+ msg.arg1 = command;
+ msg.obj = data;
+ boolean result = commandHandler.sendMessage(msg);
+
+ if ((Build.VERSION.SDK_INT >= 19) && (command == SDLActivity.COMMAND_CHANGE_WINDOW_STYLE)) {
+ // Ensure we don't return until the resize has actually happened,
+ // or 500ms have passed.
+
+ boolean bShouldWait = false;
+
+ if (data instanceof Integer) {
+ // Let's figure out if we're already laid out fullscreen or not.
+ Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ android.util.DisplayMetrics realMetrics = new android.util.DisplayMetrics();
+ display.getRealMetrics( realMetrics );
+
+ boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
+ (realMetrics.heightPixels == mSurface.getHeight()));
+
+ if (((Integer)data).intValue() == 1) {
+ // If we aren't laid out fullscreen or actively in fullscreen mode already, we're going
+ // to change size and should wait for surfaceChanged() before we return, so the size
+ // is right back in native code. If we're already laid out fullscreen, though, we're
+ // not going to change size even if we change decor modes, so we shouldn't wait for
+ // surfaceChanged() -- which may not even happen -- and should return immediately.
+ bShouldWait = !bFullscreenLayout;
+ }
+ else {
+ // If we're laid out fullscreen (even if the status bar and nav bar are present),
+ // or are actively in fullscreen, we're going to change size and should wait for
+ // surfaceChanged before we return, so the size is right back in native code.
+ bShouldWait = bFullscreenLayout;
+ }
+ }
+
+ if (bShouldWait && (SDLActivity.getContext() != null)) {
+ // We'll wait for the surfaceChanged() method, which will notify us
+ // when called. That way, we know our current size is really the
+ // size we need, instead of grabbing a size that's still got
+ // the navigation and/or status bars before they're hidden.
+ //
+ // We'll wait for up to half a second, because some devices
+ // take a surprisingly long time for the surface resize, but
+ // then we'll just give up and return.
+ //
+ synchronized(SDLActivity.getContext()) {
+ try {
+ SDLActivity.getContext().wait(500);
+ }
+ catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ private final Runnable rehideSystemUi = new Runnable() {
+ @Override
+ public void run() {
+ int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
+
+ getWindow().getDecorView().setSystemUiVisibility(flags);
+ }
+ };
+
+ public void onSystemUiVisibilityChange(int visibility) {
+ if (mFullscreenModeActive && ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0 || (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0)) {
+
+ Handler handler = getWindow().getDecorView().getHandler();
+ if (handler != null) {
+ handler.removeCallbacks(rehideSystemUi); // Prevent a hide loop.
+ handler.postDelayed(rehideSystemUi, 2000);
+ }
+
+ }
+ }
+}
+
+
diff -r 48ca0191d7ee src/core/android/SDL_android.c
--- a/src/core/android/SDL_android.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/core/android/SDL_android.c Thu Jun 04 13:34:11 2020 +0200
@@ -79,20 +79,25 @@
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint surfaceWidth, jint surfaceHeight,
jint deviceWidth, jint deviceHeight, jint format, jfloat rate);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
- JNIEnv *env, jclass cls);
+ JNIEnv *env, jclass cls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(
- JNIEnv *env, jclass jcls);
+ JNIEnv *env, jclass jcls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(
- JNIEnv *env, jclass jcls);
+ JNIEnv *env, jclass jcls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(
- JNIEnv *env, jclass jcls);
+ JNIEnv *env, jclass jcls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeKeyDown)(
JNIEnv *env, jclass jcls,
@@ -110,11 +115,13 @@
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint touch_device_id_in, jint pointer_finger_id_in,
jint action, jfloat x, jfloat y, jfloat p);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint button, jint action, jfloat x, jfloat y, jboolean relative);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
@@ -137,13 +144,16 @@
JNIEnv *env, jclass cls);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)(
- JNIEnv *env, jclass cls);
+ JNIEnv *env, jclass cls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
- JNIEnv *env, jclass cls);
+ JNIEnv *env, jclass cls,
+ jint windowID);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
- JNIEnv *env, jclass cls, jboolean hasFocus);
+ JNIEnv *env, jclass cls,
+ jint windowID, jboolean hasFocus);
JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)(
JNIEnv *env, jclass cls,
@@ -155,7 +165,7 @@
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
JNIEnv *env, jclass cls,
- jint orientation);
+ jint windowID, jint orientation);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
JNIEnv* env, jclass cls,
@@ -169,29 +179,29 @@
{ "nativeSetupJNI", "()I", SDL_JAVA_INTERFACE(nativeSetupJNI) },
{ "nativeRunMain", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) },
{ "onNativeDropFile", "(Ljava/lang/String;)V", SDL_JAVA_INTERFACE(onNativeDropFile) },
- { "nativeSetScreenResolution", "(IIIIIF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
- { "onNativeResize", "()V", SDL_JAVA_INTERFACE(onNativeResize) },
- { "onNativeSurfaceCreated", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceCreated) },
- { "onNativeSurfaceChanged", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceChanged) },
- { "onNativeSurfaceDestroyed", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed) },
+ { "nativeSetScreenResolution", "(IIIIIIF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
+ { "onNativeResize", "(I)V", SDL_JAVA_INTERFACE(onNativeResize) },
+ { "onNativeSurfaceCreated", "(I)V", SDL_JAVA_INTERFACE(onNativeSurfaceCreated) },
+ { "onNativeSurfaceChanged", "(I)V", SDL_JAVA_INTERFACE(onNativeSurfaceChanged) },
+ { "onNativeSurfaceDestroyed", "(I)V", SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed) },
{ "onNativeKeyDown", "(I)V", SDL_JAVA_INTERFACE(onNativeKeyDown) },
{ "onNativeKeyUp", "(I)V", SDL_JAVA_INTERFACE(onNativeKeyUp) },
{ "onNativeSoftReturnKey", "()Z", SDL_JAVA_INTERFACE(onNativeSoftReturnKey) },
{ "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) },
- { "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) },
- { "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
+ { "onNativeTouch", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) },
+ { "onNativeMouse", "(IIIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
{ "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) },
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
{ "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
{ "onNativeLocaleChanged", "()V", SDL_JAVA_INTERFACE(onNativeLocaleChanged) },
{ "nativeSendQuit", "()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
{ "nativeQuit", "()V", SDL_JAVA_INTERFACE(nativeQuit) },
- { "nativePause", "()V", SDL_JAVA_INTERFACE(nativePause) },
- { "nativeResume", "()V", SDL_JAVA_INTERFACE(nativeResume) },
- { "nativeFocusChanged", "(Z)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
+ { "nativePause", "(I)V", SDL_JAVA_INTERFACE(nativePause) },
+ { "nativeResume", "(I)V", SDL_JAVA_INTERFACE(nativeResume) },
+ { "nativeFocusChanged", "(IZ)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
{ "nativeGetHint", "(Ljava/lang/String;)Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetHint) },
{ "nativeSetenv", "(Ljava/lang/String;Ljava/lang/String;)V", SDL_JAVA_INTERFACE(nativeSetenv) },
- { "onNativeOrientationChanged", "(I)V", SDL_JAVA_INTERFACE(onNativeOrientationChanged) },
+ { "onNativeOrientationChanged", "(II)V", SDL_JAVA_INTERFACE(onNativeOrientationChanged) },
{ "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) },
{ "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) }
};
@@ -299,6 +309,8 @@
static jmethodID midClipboardHasText;
static jmethodID midClipboardSetText;
static jmethodID midCreateCustomCursor;
+static jmethodID midCreateWindow;
+static jmethodID midDestroyWindow;
static jmethodID midGetContext;
static jmethodID midGetDisplayDPI;
static jmethodID midGetManifestEnvironmentVariables;
@@ -307,6 +319,7 @@
static jmethodID midIsAndroidTV;
static jmethodID midIsChromebook;
static jmethodID midIsDeXMode;
+static jmethodID midIsSurfaceReady;
static jmethodID midIsScreenKeyboardShown;
static jmethodID midIsTablet;
static jmethodID midManualBackButton;
@@ -550,7 +563,7 @@
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to found a JavaVM");
}
- /* Use a mutex to prevent concurrency issues between Java Activity and Native thread code, when using 'Android_Window'.
+ /* Use a mutex to prevent concurrency issues between Java Activities and Native thread code, when accessing shared datas.
* (Eg. Java sending Touch events, while native code is destroying the main SDL_Window. )
*/
if (Android_ActivityMutex == NULL) {
@@ -578,14 +591,17 @@
midClipboardHasText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardHasText", "()Z");
midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardSetText", "(Ljava/lang/String;)V");
midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
+ midCreateWindow = (*env)->GetStaticMethodID(env, mActivityClass, "createWindow", "(I)V");
+ midDestroyWindow = (*env)->GetStaticMethodID(env, mActivityClass, "destroyWindow", "(I)V");
midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext","()Landroid/content/Context;");
midGetDisplayDPI = (*env)->GetStaticMethodID(env, mActivityClass, "getDisplayDPI", "()Landroid/util/DisplayMetrics;");
midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z");
- midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface","()Landroid/view/Surface;");
+ midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface","(I)Landroid/view/Surface;");
midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
midIsAndroidTV = (*env)->GetStaticMethodID(env, mActivityClass, "isAndroidTV","()Z");
midIsChromebook = (*env)->GetStaticMethodID(env, mActivityClass, "isChromebook", "()Z");
midIsDeXMode = (*env)->GetStaticMethodID(env, mActivityClass, "isDeXMode", "()Z");
+ midIsSurfaceReady = (*env)->GetStaticMethodID(env, mActivityClass, "isSurfaceReady", "(I)Z");
midIsScreenKeyboardShown = (*env)->GetStaticMethodID(env, mActivityClass, "isScreenKeyboardShown","()Z");
midIsTablet = (*env)->GetStaticMethodID(env, mActivityClass, "isTablet", "()Z");
midManualBackButton = (*env)->GetStaticMethodID(env, mActivityClass, "manualBackButton", "()V");
@@ -593,13 +609,13 @@
midOpenAPKExpansionInputStream = (*env)->GetStaticMethodID(env, mActivityClass, "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
midRequestPermission = (*env)->GetStaticMethodID(env, mActivityClass, "requestPermission", "(Ljava/lang/String;I)V");
midSendMessage = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z");
- midSetActivityTitle = (*env)->GetStaticMethodID(env, mActivityClass, "setActivityTitle","(Ljava/lang/String;)Z");
+ midSetActivityTitle = (*env)->GetStaticMethodID(env, mActivityClass, "setActivityTitle","(ILjava/lang/String;)Z");
midSetCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setCustomCursor", "(I)Z");
- midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass, "setOrientation","(IIZLjava/lang/String;)V");
+ midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass, "setOrientation","(IIIZLjava/lang/String;)V");
midSetRelativeMouseEnabled = (*env)->GetStaticMethodID(env, mActivityClass, "setRelativeMouseEnabled", "(Z)Z");
- midSetSurfaceViewFormat = (*env)->GetStaticMethodID(env, mActivityClass, "setSurfaceViewFormat","(I)V");
+ midSetSurfaceViewFormat = (*env)->GetStaticMethodID(env, mActivityClass, "setSurfaceViewFormat","(II)V");
midSetSystemCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setSystemCursor", "(I)Z");
- midSetWindowStyle = (*env)->GetStaticMethodID(env, mActivityClass, "setWindowStyle","(Z)V");
+ midSetWindowStyle = (*env)->GetStaticMethodID(env, mActivityClass, "setWindowStyle","(IZ)V");
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss","()Z");
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
@@ -608,6 +624,8 @@
!midClipboardHasText ||
!midClipboardSetText ||
!midCreateCustomCursor ||
+ !midCreateWindow ||
+ !midDestroyWindow ||
!midGetContext ||
!midGetDisplayDPI ||
!midGetManifestEnvironmentVariables ||
@@ -616,6 +634,7 @@
!midIsAndroidTV ||
!midIsChromebook ||
!midIsDeXMode ||
+ !midIsSurfaceReady ||
!midIsScreenKeyboardShown ||
!midIsTablet ||
!midManualBackButton ||
@@ -707,14 +726,24 @@
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls, jstring library, jstring function, jobject array)
{
int status = -1;
+#if 0
const char *library_file;
void *library_handle;
+#endif
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeRunMain()");
/* Save JNIEnv of SDLThread */
Android_JNI_SetEnv(env);
+#if 1
+ /* Compiling a unique shared library, main() will be added afterward.
+ * need to be marked as weak */
+ {
+ extern int main(int argc, char **argv) __attribute__((weak));
+ status = main(0, NULL);
+ }
+#else
library_file = (*env)->GetStringUTFChars(env, library, NULL);
library_handle = dlopen(library_file, RTLD_GLOBAL);
@@ -789,7 +818,7 @@
__android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't load library %s", library_file);
}
(*env)->ReleaseStringUTFChars(env, library, library_file);
-
+#endif
/* This is a Java thread, it doesn't need to be Detached from the JVM.
* Set to mThreadKey value to NULL not to call pthread_create destructor 'Android_JNI_ThreadDestroyed' */
Android_JNI_SetEnv(NULL);
@@ -811,6 +840,13 @@
SDL_SendDropComplete(NULL);
}
+
+static SDL_bool SDL_IsSurfaceReady(int windowID)
+{
+ JNIEnv *env = Android_JNI_GetEnv();
+ return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsSurfaceReady, windowID);
+}
+
/* Lock / Unlock Mutex */
void Android_ActivityMutex_Lock() {
SDL_LockMutex(Android_ActivityMutex);
@@ -821,65 +857,66 @@
}
/* Lock the Mutex when the Activity is in its 'Running' state */
-void Android_ActivityMutex_Lock_Running() {
- int pauseSignaled = 0;
- int resumeSignaled = 0;
-
+void Android_ActivityMutex_Lock_Running(SDL_Window *window) {
retry:
-
SDL_LockMutex(Android_ActivityMutex);
-
- pauseSignaled = SDL_SemValue(Android_PauseSem);
- resumeSignaled = SDL_SemValue(Android_ResumeSem);
-
- if (pauseSignaled > resumeSignaled) {
- SDL_UnlockMutex(Android_ActivityMutex);
- SDL_Delay(50);
- goto retry;
+ {
+ int windowID = SDL_GetWindowID(window);
+ if (! SDL_IsSurfaceReady(windowID)) {
+ SDL_UnlockMutex(Android_ActivityMutex);
+ SDL_Delay(20);
+ goto retry;
+ }
}
}
/* Set screen resolution */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint surfaceWidth, jint surfaceHeight,
jint deviceWidth, jint deviceHeight, jint format, jfloat rate)
{
SDL_LockMutex(Android_ActivityMutex);
-
- Android_SetScreenResolution(surfaceWidth, surfaceHeight, deviceWidth, deviceHeight, format, rate);
-
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ Android_SetScreenResolution(window, surfaceWidth, surfaceHeight, deviceWidth, deviceHeight, format, rate);
+ }
SDL_UnlockMutex(Android_ActivityMutex);
}
/* Resize */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
- JNIEnv *env, jclass jcls)
+ JNIEnv *env, jclass jcls,
+ jint windowID)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (Android_Window)
{
- Android_SendResize(Android_Window);
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ if (window) {
+ Android_SendResize(window);
+ }
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
JNIEnv *env, jclass jcls,
- jint orientation)
+ jint windowID, jint orientation)
{
SDL_LockMutex(Android_ActivityMutex);
-
- displayOrientation = (SDL_DisplayOrientation)orientation;
-
- if (Android_Window)
{
- SDL_VideoDisplay *display = SDL_GetDisplay(0);
- SDL_SendDisplayEvent(display, SDL_DISPLAYEVENT_ORIENTATION, orientation);
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ displayOrientation = (SDL_DisplayOrientation)orientation;
+
+ if (window) {
+ SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+ SDL_SendDisplayEvent(display, SDL_DISPLAYEVENT_ORIENTATION, orientation);
+ }
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
@@ -980,83 +1017,85 @@
}
/* Called from surfaceCreated() */
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(JNIEnv *env, jclass jcls)
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(JNIEnv *env, jclass jcls,
+ jint windowID)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (Android_Window)
{
- SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
-
- data->native_window = Android_JNI_GetNativeWindow();
- if (data->native_window == NULL) {
- SDL_SetError("Could not fetch native window from UI thread");
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ if (window) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ data->native_window = Android_JNI_GetNativeWindow(windowID);
+ if (data->native_window == NULL) {
+ SDL_SetError("Could not fetch native window from UI thread");
+ }
}
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
/* Called from surfaceChanged() */
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, jclass jcls)
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, jclass jcls,
+ jint windowID)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (Android_Window)
{
- SDL_VideoDevice *_this = SDL_GetVideoDevice();
- SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
-
- /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
- if (data->egl_surface == EGL_NO_SURFACE) {
- data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ if (window) {
+ SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
+ if (data->egl_surface == EGL_NO_SURFACE) {
+ data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);
+ }
+ /* GL Context handling is done in the event loop because this function is run from the Java thread */
}
-
- /* GL Context handling is done in the event loop because this function is run from the Java thread */
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
/* Called from surfaceDestroyed() */
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls)
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls,
+ jint windowID)
{
int nb_attempt = 50;
-
retry:
SDL_LockMutex(Android_ActivityMutex);
-
- if (Android_Window)
{
- SDL_VideoDevice *_this = SDL_GetVideoDevice();
- SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
-
- /* Wait for Main thread being paused and context un-activated to release 'egl_surface' */
- if (! data->backup_done) {
- nb_attempt -= 1;
- if (nb_attempt == 0) {
- SDL_SetError("Try to release egl_surface with context probably still active");
- } else {
- SDL_UnlockMutex(Android_ActivityMutex);
- SDL_Delay(10);
- goto retry;
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+ if (window) {
+ SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (data) {
+ /* Wait for Main thread being paused and context un-activated to release 'egl_surface' */
+ if (data->backup_done != 2) {
+ nb_attempt -= 1;
+ if (nb_attempt == 0) {
+ SDL_SetError("Try to release egl_surface with context probably still active. windowID=%d", windowID);
+ } else {
+ SDL_UnlockMutex(Android_ActivityMutex);
+ SDL_Delay(10);
+ goto retry;
+ }
+ }
+
+ if (data->egl_surface != EGL_NO_SURFACE) {
+ SDL_EGL_DestroySurface(_this, data->egl_surface);
+ data->egl_surface = EGL_NO_SURFACE;
+ }
+
+ if (data->native_window) {
+ ANativeWindow_release(data->native_window);
+ data->native_window = NULL;
+ }
+
+ /* GL Context handling is done in the event loop because this function is run from the Java thread */
}
}
-
- if (data->egl_surface != EGL_NO_SURFACE) {
- SDL_EGL_DestroySurface(_this, data->egl_surface);
- data->egl_surface = EGL_NO_SURFACE;
- }
-
- if (data->native_window) {
- ANativeWindow_release(data->native_window);
- data->native_window = NULL;
- }
-
- /* GL Context handling is done in the event loop because this function is run from the Java thread */
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
@@ -1099,25 +1138,33 @@
/* Touch */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint touch_device_id_in, jint pointer_finger_id_in,
jint action, jfloat x, jfloat y, jfloat p)
{
SDL_LockMutex(Android_ActivityMutex);
-
- Android_OnTouch(Android_Window, touch_device_id_in, pointer_finger_id_in, action, x, y, p);
-
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+ if (window) {
+ Android_OnTouch(window, touch_device_id_in, pointer_finger_id_in, action, x, y, p);
+ }
+ }
SDL_UnlockMutex(Android_ActivityMutex);
}
/* Mouse */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
JNIEnv *env, jclass jcls,
+ jint windowID,
jint button, jint action, jfloat x, jfloat y, jboolean relative)
{
SDL_LockMutex(Android_ActivityMutex);
-
- Android_OnMouse(Android_Window, button, action, x, y, relative);
-
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+ if (window) {
+ Android_OnMouse(window, button, action, x, y, relative);
+ }
+ }
SDL_UnlockMutex(Android_ActivityMutex);
}
@@ -1208,9 +1255,22 @@
/* Pause */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)(
- JNIEnv *env, jclass cls)
+ JNIEnv *env, jclass cls,
+ jint windowID)
{
- __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()");
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause() windowID=%d", windowID);
+
+ SDL_LockMutex(Android_ActivityMutex);
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+ if (window) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (data) {
+ data->activity_state = ACTIVITY_PAUSED;
+ }
+ }
+ }
+ SDL_UnlockMutex(Android_ActivityMutex);
/* Signal the pause semaphore so the event loop knows to pause and (optionally) block itself.
* Sometimes 2 pauses can be queued (eg pause/resume/pause), so it's always increased. */
@@ -1219,9 +1279,26 @@
/* Resume */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
- JNIEnv *env, jclass cls)
+ JNIEnv *env, jclass cls,
+ jint windowID)
{
- __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume()");
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume() windowID=%d", windowID);
+
+ SDL_LockMutex(Android_ActivityMutex);
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+ if (window) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (data) {
+ data->activity_state = ACTIVITY_RESUMED;
+ } else {
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume() windowID=%d -- NO DATA", windowID);
+ }
+ } else {
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeResume() windowID=%d -- NO WINDOW", windowID);
+ }
+ }
+ SDL_UnlockMutex(Android_ActivityMutex);
/* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
* We can't restore the GL Context here because it needs to be done on the SDL main thread
@@ -1231,15 +1308,18 @@
}
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
- JNIEnv *env, jclass cls, jboolean hasFocus)
+ JNIEnv *env, jclass cls,
+ jint windowID, jboolean hasFocus)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (Android_Window) {
- __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()");
- SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0);
+ {
+ SDL_Window *window = SDL_GetWindowFromID(windowID);
+
+ if (window) {
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged() windowID=%d hasFocus=%d", windowID, hasFocus);
+ SDL_SendWindowEvent(window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0);
+ }
}
-
SDL_UnlockMutex(Android_ActivityMutex);
}
@@ -1367,13 +1447,13 @@
}
}
-ANativeWindow* Android_JNI_GetNativeWindow(void)
+ANativeWindow* Android_JNI_GetNativeWindow(int windowID)
{
ANativeWindow *anw = NULL;
jobject s;
JNIEnv *env = Android_JNI_GetEnv();
- s = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetNativeSurface);
+ s = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetNativeSurface, windowID);
if (s) {
anw = ANativeWindow_fromSurface(env, s);
(*env)->DeleteLocalRef(env, s);
@@ -1382,7 +1462,7 @@
return anw;
}
-void Android_JNI_SetSurfaceViewFormat(int format)
+void Android_JNI_SetSurfaceViewFormat(int windowID, int format)
{
JNIEnv *env = Android_JNI_GetEnv();
int new_format = 0;
@@ -1399,30 +1479,30 @@
new_format = 0;
}
- (*env)->CallStaticVoidMethod(env, mActivityClass, midSetSurfaceViewFormat, new_format);
+ (*env)->CallStaticVoidMethod(env, mActivityClass, midSetSurfaceViewFormat, windowID, new_format);
}
-void Android_JNI_SetActivityTitle(const char *title)
+void Android_JNI_SetActivityTitle(int windowID, const char *title)
{
JNIEnv *env = Android_JNI_GetEnv();
jstring jtitle = (*env)->NewStringUTF(env, title);
- (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetActivityTitle, jtitle);
+ (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetActivityTitle, windowID, jtitle);
(*env)->DeleteLocalRef(env, jtitle);
}
-void Android_JNI_SetWindowStyle(SDL_bool fullscreen)
+void Android_JNI_SetWindowStyle(int windowID, SDL_bool fullscreen)
{
JNIEnv *env = Android_JNI_GetEnv();
- (*env)->CallStaticVoidMethod(env, mActivityClass, midSetWindowStyle, fullscreen ? 1 : 0);
+ (*env)->CallStaticVoidMethod(env, mActivityClass, midSetWindowStyle, windowID, fullscreen ? 1 : 0);
}
-void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint)
+void Android_JNI_SetOrientation(int windowID, int w, int h, int resizable, const char *hint)
{
JNIEnv *env = Android_JNI_GetEnv();
jstring jhint = (*env)->NewStringUTF(env, (hint ? hint : ""));
- (*env)->CallStaticVoidMethod(env, mActivityClass, midSetOrientation, w, h, (resizable? 1 : 0), jhint);
+ (*env)->CallStaticVoidMethod(env, mActivityClass, midSetOrientation, windowID, w, h, (resizable? 1 : 0), jhint);
(*env)->DeleteLocalRef(env, jhint);
}
@@ -2819,6 +2899,19 @@
return custom_cursor;
}
+int Android_JNI_CreateWindow(int windowID)
+{
+ JNIEnv *env = Android_JNI_GetEnv();
+ (*env)->CallStaticVoidMethod(env, mActivityClass, midCreateWindow, windowID);
+ return 0;
+}
+
+int Android_JNI_DestroyWindow(int windowID)
+{
+ JNIEnv *env = Android_JNI_GetEnv();
+ (*env)->CallStaticVoidMethod(env, mActivityClass, midDestroyWindow, windowID);
+ return 0;
+}
SDL_bool Android_JNI_SetCustomCursor(int cursorID)
{
diff -r 48ca0191d7ee src/core/android/SDL_android.h
--- a/src/core/android/SDL_android.h Wed Jun 03 14:58:38 2020 -0700
+++ b/src/core/android/SDL_android.h Thu Jun 04 13:34:11 2020 +0200
@@ -36,9 +36,9 @@
#include "SDL_video.h"
/* Interface from the SDL library into the Android Java activity */
-extern void Android_JNI_SetActivityTitle(const char *title);
-extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen);
-extern void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint);
+extern void Android_JNI_SetActivityTitle(int windowID, const char *title);
+extern void Android_JNI_SetWindowStyle(int windowID, SDL_bool fullscreen);
+extern void Android_JNI_SetOrientation(int windowID, int w, int h, int resizable, const char *hint);
extern void Android_JNI_MinizeWindow(void);
extern SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss(void);
@@ -46,8 +46,8 @@
extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
extern void Android_JNI_HideTextInput(void);
extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
-extern ANativeWindow* Android_JNI_GetNativeWindow(void);
-extern void Android_JNI_SetSurfaceViewFormat(int format);
+extern ANativeWindow* Android_JNI_GetNativeWindow(int i);
+extern void Android_JNI_SetSurfaceViewFormat(int windowID, int format);
extern SDL_DisplayOrientation Android_JNI_GetDisplayOrientation(void);
extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
@@ -129,6 +129,10 @@
/* Request permission */
SDL_bool Android_JNI_RequestPermission(const char *permission);
+/* Multi-SDL_Window */
+int Android_JNI_CreateWindow(int windowID);
+int Android_JNI_DestroyWindow(int windowID);
+
int SDL_GetAndroidSDKVersion(void);
SDL_bool SDL_IsAndroidTablet(void);
@@ -138,7 +142,7 @@
void Android_ActivityMutex_Lock(void);
void Android_ActivityMutex_Unlock(void);
-void Android_ActivityMutex_Lock_Running(void);
+void Android_ActivityMutex_Lock_Running(SDL_Window *window);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
diff -r 48ca0191d7ee src/render/SDL_render.c
--- a/src/render/SDL_render.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/render/SDL_render.c Thu Jun 04 13:34:11 2020 +0200
@@ -773,7 +773,7 @@
const char *hint;
#if defined(__ANDROID__)
- Android_ActivityMutex_Lock_Running();
+ Android_ActivityMutex_Lock_Running(window);
#endif
if (!window) {
diff -r 48ca0191d7ee src/video/SDL_egl.c
--- a/src/video/SDL_egl.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/SDL_egl.c Thu Jun 04 13:34:11 2020 +0200
@@ -1099,7 +1099,7 @@
/* Update SurfaceView holder format.
* May triggers a sequence surfaceDestroyed(), surfaceCreated(), surfaceChanged(). */
- Android_JNI_SetSurfaceViewFormat(format);
+ Android_JNI_SetSurfaceViewFormat(-1 /* TODO WindowID */, format);
}
#endif
if (_this->gl_config.framebuffer_srgb_capable) {
diff -r 48ca0191d7ee src/video/android/SDL_androidevents.c
--- a/src/video/android/SDL_androidevents.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidevents.c Thu Jun 04 13:34:11 2020 +0200
@@ -55,34 +55,56 @@
return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type);
}
+static int
+SDL_IsMinimizedEventConsummed(int windowID)
+{
+#define NB_EVENTS 16
+ SDL_Event tab[NB_EVENTS];
+ int i;
+ int cnt = SDL_PeepEvents(tab, NB_EVENTS, SDL_PEEKEVENT, SDL_WINDOWEVENT_MINIMIZED, SDL_WINDOWEVENT_MINIMIZED);
+
+ if (cnt == 0) {
+ return 1;
+ }
+
+ for (i = 0; i < cnt && i < NB_EVENTS; i++) {
+ SDL_Event *evt = &tab[i];
+ if (evt->window.windowID == windowID) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
static void
android_egl_context_restore(SDL_Window *window)
{
- if (window) {
- SDL_Event event;
- SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
- if (SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context) < 0) {
- /* The context is no longer valid, create a new one */
- data->egl_context = (EGLContext) SDL_GL_CreateContext(window);
- SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context);
- event.type = SDL_RENDER_DEVICE_RESET;
- SDL_PushEvent(&event);
- }
- data->backup_done = 0;
+ SDL_Event event;
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context) < 0) {
+ /* The context is no longer valid, create a new one */
+ SDL_Log("SDL_RENDER_DEVICE_RESET ...");
+ data->egl_context = (EGLContext) SDL_GL_CreateContext(window);
+ SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context);
+ event.type = SDL_RENDER_DEVICE_RESET;
+ SDL_PushEvent(&event);
}
+ data->backup_done = 0;
}
static void
android_egl_context_backup(SDL_Window *window)
{
- if (window) {
- /* Keep a copy of the EGL Context so we can try to restore it when we resume */
- SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
- data->egl_context = SDL_GL_GetCurrentContext();
+ /* Keep a copy of the EGL Context so we can try to restore it when we resume */
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ data->egl_context = SDL_GL_GetCurrentContext();
+ if (data->egl_context) {
/* We need to do this so the EGLSurface can be freed */
SDL_GL_MakeCurrent(window, NULL);
- data->backup_done = 1;
}
+ data->backup_done = 2;
}
@@ -93,74 +115,187 @@
* No polling necessary
*/
+const static int debug = 1; /* 0, 1, 2 */
+
+#define NEXT_STATE(state) \
+{ \
+ if (debug) { \
+ if (videodata->loop_state != state) { \
+ SDL_Log("event loop state " # state); \
+ } \
+ videodata->loop_state = state; \
+ } \
+}
+
+
void
Android_PumpEvents_Blocking(_THIS)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
- if (videodata->isPaused) {
- SDL_bool isContextExternal = SDL_IsVideoContextExternal();
+
+
+ if (debug == 2) {
+ SDL_LockMutex(Android_ActivityMutex);
+ SDL_Window *window;
+ SDL_Log("=== Android_PumpEvents_Blocking === Start ===");
+ for (window = _this->windows; window; window = window->next) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_Log("loop_state = %d windowID=%d activity_state=%d backup_done=%d", videodata->loop_state, SDL_GetWindowID(window), data->activity_state, data->backup_done);
+ }
+ SDL_UnlockMutex(Android_ActivityMutex);
+ }
+
+ if (videodata->loop_state == LOOP_SENDING_BG_EVENTS) {
+#if 0
+ /* we need to make sure that the very last event (of the first pause sequence, if several)
+ * has reached the app */
+ if (SDL_NumberOfEvents(SDL_APP_DIDENTERBACKGROUND) > SDL_SemValue(Android_PauseSem)) {
+ /* Wait for the event to be consumed */
+ } else {
+ NEXT_STATE(LOOP_BLOCKED);
+ }
+#else
+ if (SDL_NumberOfEvents(SDL_APP_DIDENTERBACKGROUND) == 0) {
+ NEXT_STATE(LOOP_BLOCKED);
+ }
+#endif
+ } else if (videodata->loop_state == LOOP_BLOCKED) {
+
+ /* Double-check before blocking, because an activity may have created in the meantimes */
+ int all_paused = 1;
+
+#if 0
+ /* Browse all SDL_Window */
+ SDL_LockMutex(Android_ActivityMutex);
+ {
+ SDL_Window *window;
+ for (window = _this->windows; window; window = window->next) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (data->activity_state != ACTIVITY_PAUSED || data->backup_done != 2) {
+ all_paused = 0;
+
+ if (debug == 1) {
+ SDL_Log("loop_state: LOOP_BLOCKED (canceled!) windowID=%d activity_state=%d backup_done=%d",
+ SDL_GetWindowID(window), data->activity_state, data->backup_done);
+ }
+
+ break;
+ }
+ }
+
+ if (all_paused == 0) {
+ NEXT_STATE(LOOP_TOGGLING_WINDOWS);
+ SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
+ SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
+ }
+ }
+ SDL_UnlockMutex(Android_ActivityMutex);
+#endif
+ if (all_paused == 1) {
+ ANDROIDAUDIO_PauseDevices();
+ openslES_PauseDevices();
+
+ if (debug == 1) {
+ SDL_Log("loop_state: LOOP_BLOCKED (blocked!)");
+ }
+
+ if (SDL_SemWait(Android_ResumeSem) == 0) {
- /* Make sure this is the last thing we do before pausing */
- if (!isContextExternal) {
- SDL_LockMutex(Android_ActivityMutex);
- android_egl_context_backup(Android_Window);
- SDL_UnlockMutex(Android_ActivityMutex);
+ NEXT_STATE(LOOP_TOGGLING_WINDOWS);
+
+ /* Android_ResumeSem was signaled */
+ SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
+ SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
+
+ ANDROIDAUDIO_ResumeDevices();
+ openslES_ResumeDevices();
+
+ /* Make sure SW Keyboard is restored when an app becomes foreground */
+ if (SDL_IsTextInputActive()) {
+ Android_StartTextInput(_this); /* Only showTextInput */
+ }
+ }
+ }
+ } else if (SDL_SemTryWait(Android_PauseSem) == 0 || SDL_SemTryWait(Android_ResumeSem) == 0 || videodata->loop_state == LOOP_TOGGLING_WINDOWS) {
+ int all_paused = 1;
+ int wait_minimized_event = 0;
+
+ /* Browse all SDL_Window */
+ SDL_LockMutex(Android_ActivityMutex);
+ {
+ SDL_Window *window;
+ SDL_bool should_restore = !SDL_IsVideoContextExternal() && !SDL_HasEvent(SDL_QUIT);
+
+ for (window = _this->windows; window; window = window->next) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+ if (data->activity_state == ACTIVITY_PAUSED) {
+ if (data->backup_done == 0) {
+ data->backup_done = 1;
+ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+ all_paused = 0;
+ wait_minimized_event = 1;
+ } else if (data->backup_done == 1) {
+ // If the event is consumed, then backup.
+ if (SDL_IsMinimizedEventConsummed(SDL_GetWindowID(window))) {
+ SDL_Log("android_egl_context_backup windowID=%d", SDL_GetWindowID(window));
+ android_egl_context_backup(window);
+ } else {
+ wait_minimized_event = 1;
+ all_paused = 0;
+ }
+
+ }
+ } else if (data->activity_state == ACTIVITY_RESUMED) {
+ all_paused = 0;
+ if (data->backup_done == 2) {
+ /* Restore the GL Context from here, as this operation is thread dependent */
+ if (should_restore) {
+ SDL_Log("android_egl_context_restore windowID=%d", SDL_GetWindowID(window));
+ android_egl_context_restore(window);
+ }
+ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+ }
+ } else /* ACTIVITY_INIT */ {
+ all_paused = 0;
+ }
+ }
+ }
+ SDL_UnlockMutex(Android_ActivityMutex);
+
+ if (wait_minimized_event) {
+ NEXT_STATE(LOOP_TOGGLING_WINDOWS);
+ } else if (all_paused) {
+ SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
+ SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
+
+ NEXT_STATE(LOOP_SENDING_BG_EVENTS);
+ } else {
+ NEXT_STATE(LOOP_INIT);
}
- ANDROIDAUDIO_PauseDevices();
- openslES_PauseDevices();
-
- if (SDL_SemWait(Android_ResumeSem) == 0) {
-
- videodata->isPaused = 0;
-
- /* Android_ResumeSem was signaled */
- SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
- SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
- SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
-
- ANDROIDAUDIO_ResumeDevices();
- openslES_ResumeDevices();
-
- /* Restore the GL Context from here, as this operation is thread dependent */
- if (!isContextExternal && !SDL_HasEvent(SDL_QUIT)) {
- SDL_LockMutex(Android_ActivityMutex);
- android_egl_context_restore(Android_Window);
- SDL_UnlockMutex(Android_ActivityMutex);
- }
+ }
- /* Make sure SW Keyboard is restored when an app becomes foreground */
- if (SDL_IsTextInputActive()) {
- Android_StartTextInput(_this); /* Only showTextInput */
- }
+ if (debug == 2) {
+ SDL_Window *window;
+ SDL_Log("===========================================");
+ for (window = _this->windows; window; window = window->next) {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_Log("loop_state = %d windowID=%d activity_state=%d backup_done=%d", videodata->loop_state, SDL_GetWindowID(window), data->activity_state, data->backup_done);
}
- } else {
- if (videodata->isPausing || SDL_SemTryWait(Android_PauseSem) == 0) {
+
+ SDL_Log("=== Android_PumpEvents_Blocking === End ===");
+ }
- /* Android_PauseSem was signaled */
- if (videodata->isPausing == 0) {
- SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
- SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
- SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
- }
- /* We've been signaled to pause (potentially several times), but before we block ourselves,
- * we need to make sure that the very last event (of the first pause sequence, if several)
- * has reached the app */
- if (SDL_NumberOfEvents(SDL_APP_DIDENTERBACKGROUND) > SDL_SemValue(Android_PauseSem)) {
- videodata->isPausing = 1;
- } else {
- videodata->isPausing = 0;
- videodata->isPaused = 1;
- }
- }
- }
+
}
void
Android_PumpEvents_NonBlocking(_THIS)
{
+#if 0
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
static int backup_context = 0;
@@ -228,6 +363,7 @@
}
}
}
+#endif
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */
diff -r 48ca0191d7ee src/video/android/SDL_androidgl.c
--- a/src/video/android/SDL_androidgl.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidgl.c Thu Jun 04 13:34:11 2020 +0200
@@ -51,7 +51,7 @@
{
SDL_GLContext ret;
- Android_ActivityMutex_Lock_Running();
+ Android_ActivityMutex_Lock_Running(window);
ret = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
diff -r 48ca0191d7ee src/video/android/SDL_androidvideo.c
--- a/src/video/android/SDL_androidvideo.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidvideo.c Thu Jun 04 13:34:11 2020 +0200
@@ -180,14 +180,10 @@
int
Android_VideoInit(_THIS)
{
- SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
int display_index;
SDL_VideoDisplay *display;
SDL_DisplayMode mode;
- videodata->isPaused = SDL_FALSE;
- videodata->isPausing = SDL_FALSE;
-
mode.format = Android_ScreenFormat;
mode.w = Android_DeviceWidth;
mode.h = Android_DeviceHeight;
@@ -227,7 +223,7 @@
}
void
-Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, Uint32 format, float rate)
+Android_SetScreenResolution(SDL_Window *window, int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, Uint32 format, float rate)
{
Android_SurfaceWidth = surfaceWidth;
Android_SurfaceHeight = surfaceHeight;
diff -r 48ca0191d7ee src/video/android/SDL_androidvideo.h
--- a/src/video/android/SDL_androidvideo.h Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidvideo.h Thu Jun 04 13:34:11 2020 +0200
@@ -28,16 +28,21 @@
#include "../SDL_sysvideo.h"
/* Called by the JNI layer when the screen changes size or format */
-extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, Uint32 format, float rate);
+extern void Android_SetScreenResolution(SDL_Window *window, int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, Uint32 format, float rate);
extern void Android_SendResize(SDL_Window *window);
/* Private display data */
+
+#define LOOP_INIT 0
+#define LOOP_TOGGLING_WINDOWS 1
+#define LOOP_SENDING_BG_EVENTS 2
+#define LOOP_BLOCKED 3
+
typedef struct SDL_VideoData
{
SDL_Rect textRect;
- int isPaused;
- int isPausing;
+ int loop_state;
} SDL_VideoData;
extern int Android_SurfaceWidth;
diff -r 48ca0191d7ee src/video/android/SDL_androidwindow.c
--- a/src/video/android/SDL_androidwindow.c Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidwindow.c Thu Jun 04 13:34:11 2020 +0200
@@ -33,24 +33,29 @@
#include "SDL_androidwindow.h"
#include "SDL_hints.h"
-/* Currently only one window */
-SDL_Window *Android_Window = NULL;
-
int
Android_CreateWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *data;
int retval = 0;
-
- Android_ActivityMutex_Lock_Running();
+ int windowID = SDL_GetWindowID(window);
- if (Android_Window) {
- retval = SDL_SetError("Android only supports one window");
+ /* Allocate this memory first, because for a 2nd SDL_Window, we start a new Activty and surfaceView,
+ * they try fill data->native_window */
+ data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ retval = SDL_OutOfMemory();
goto endfunction;
}
+ window->driverdata = data;
+
+ /* Start a new Activity */
+ Android_JNI_CreateWindow(windowID);
+
+ Android_ActivityMutex_Lock_Running(window);
/* Set orientation */
- Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
+ Android_JNI_SetOrientation(SDL_GetWindowID(window), window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
/* Adjust the window data to match the screen */
window->x = 0;
@@ -65,35 +70,33 @@
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
- data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- retval = SDL_OutOfMemory();
- goto endfunction;
- }
-
- data->native_window = Android_JNI_GetNativeWindow();
-
- if (!data->native_window) {
- SDL_free(data);
- retval = SDL_SetError("Could not fetch native window");
- goto endfunction;
+#if 0
+ if (data->native_window == NULL) {
+ data->native_window = Android_JNI_GetNativeWindow(windowID);
+ if (!data->native_window) {
+ SDL_free(data);
+ retval = SDL_SetError("Could not fetch native window windowID=%d", windowID);
+ goto endfunction;
+ }
}
/* Do not create EGLSurface for Vulkan window since it will then make the window
incompatible with vkCreateAndroidSurfaceKHR */
if ((window->flags & SDL_WINDOW_OPENGL) != 0) {
- data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);
+ if (data->egl_surface == EGL_NO_SURFACE) {
+
+ data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);
- if (data->egl_surface == EGL_NO_SURFACE) {
- ANativeWindow_release(data->native_window);
- SDL_free(data);
- retval = -1;
- goto endfunction;
+ if (data->egl_surface == EGL_NO_SURFACE) {
+ ANativeWindow_release(data->native_window);
+ SDL_free(data);
+ retval = -1;
+ goto endfunction;
+ }
}
}
+#endif
- window->driverdata = data;
- Android_Window = window;
endfunction:
@@ -105,19 +108,18 @@
void
Android_SetWindowTitle(_THIS, SDL_Window *window)
{
- Android_JNI_SetActivityTitle(window->title);
+ Android_JNI_SetActivityTitle(SDL_GetWindowID(window), window->title);
}
void
Android_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (window == Android_Window) {
+ {
/* If the window is being destroyed don't change visible state */
if (!window->is_destroying) {
- Android_JNI_SetWindowStyle(fullscreen);
+ Android_JNI_SetWindowStyle(SDL_GetWindowID(window), fullscreen);
}
/* Ensure our size matches reality after we've executed the window style change.
@@ -169,12 +171,9 @@
Android_DestroyWindow(_THIS, SDL_Window *window)
{
SDL_LockMutex(Android_ActivityMutex);
-
- if (window == Android_Window) {
- Android_Window = NULL;
-
- if (window->driverdata) {
- SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ {
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ if (data) {
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
@@ -182,11 +181,12 @@
ANativeWindow_release(data->native_window);
}
SDL_free(window->driverdata);
- window->driverdata = NULL;
}
+ window->driverdata = NULL;
}
+ SDL_UnlockMutex(Android_ActivityMutex);
- SDL_UnlockMutex(Android_ActivityMutex);
+ Android_JNI_DestroyWindow(SDL_GetWindowID(window));
}
SDL_bool
diff -r 48ca0191d7ee src/video/android/SDL_androidwindow.h
--- a/src/video/android/SDL_androidwindow.h Wed Jun 03 14:58:38 2020 -0700
+++ b/src/video/android/SDL_androidwindow.h Thu Jun 04 13:34:11 2020 +0200
@@ -35,13 +35,17 @@
extern SDL_bool Android_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info);
extern SDL_Window *Android_Window;
+#define ACTIVITY_INIT 0
+#define ACTIVITY_RESUMED 1
+#define ACTIVITY_PAUSED 2
+
typedef struct
{
- EGLSurface egl_surface;
- EGLContext egl_context; /* We use this to preserve the context when losing focus */
- SDL_bool backup_done;
- ANativeWindow *native_window;
-
+ EGLSurface egl_surface;
+ EGLContext egl_context; /* We use this to preserve the context when losing focus */
+ int backup_done; /* 0:running 1:pending backup 2:backup done */
+ int activity_state; /* 0:INIT 1:RESUMED 2:PAUSED */
+ ANativeWindow *native_window; /* handle SurfaceView */
} SDL_WindowData;
#endif /* SDL_androidwindow_h_ */