https://github.com/libsdl-org/SDL/commit/4231848791dae4e0a9afb32e2f9e897985b7dde2
From 4231848791dae4e0a9afb32e2f9e897985b7dde2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 10 Jan 2025 15:27:08 -0800
Subject: [PATCH] Revert "Separate android initialization from Activity
(#11891)"
This reverts commit d14c93c4b11c116ab897f004ca15e726a77c4469.
This is a major breaking change for activities that inherit SDLActivity
---
android-project/app/build.gradle | 5 -
android-project/app/proguard-rules.pro | 2 +-
.../java/org/libsdl/app/ActivityHook.java | 15 -
.../app/src/main/java/org/libsdl/app/SDL.java | 4 +-
.../main/java/org/libsdl/app/SDLActivity.java | 2120 +++++++++++++++-
.../org/libsdl/app/SDLActivityComponent.java | 2201 -----------------
.../org/libsdl/app/SDLComponentReceiver.java | 5 -
.../org/libsdl/app/SDLControllerManager.java | 19 +-
.../java/org/libsdl/app/SDLDummyEdit.java | 7 +-
.../org/libsdl/app/SDLInputConnection.java | 5 +-
.../main/java/org/libsdl/app/SDLSurface.java | 57 +-
build-scripts/release-info.json | 2 +-
build-scripts/test-versioning.sh | 10 +-
build-scripts/update-version.sh | 6 +-
docs/README-android.md | 3 +-
src/core/android/SDL_android.c | 10 +-
16 files changed, 2154 insertions(+), 2317 deletions(-)
delete mode 100644 android-project/app/src/main/java/org/libsdl/app/ActivityHook.java
delete mode 100644 android-project/app/src/main/java/org/libsdl/app/SDLActivityComponent.java
delete mode 100644 android-project/app/src/main/java/org/libsdl/app/SDLComponentReceiver.java
diff --git a/android-project/app/build.gradle b/android-project/app/build.gradle
index 50a44c99aa76e..8946de66778aa 100644
--- a/android-project/app/build.gradle
+++ b/android-project/app/build.gradle
@@ -55,11 +55,6 @@ android {
lint {
abortOnError false
}
- compileOptions {
- // our minSdk, lollipop (API 21) uses java 7
- sourceCompatibility JavaVersion.VERSION_1_7
- targetCompatibility JavaVersion.VERSION_1_7
- }
}
dependencies {
diff --git a/android-project/app/proguard-rules.pro b/android-project/app/proguard-rules.pro
index e29a7e07d9851..fc0a4f5c9264b 100644
--- a/android-project/app/proguard-rules.pro
+++ b/android-project/app/proguard-rules.pro
@@ -16,7 +16,7 @@
# public *;
#}
--keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivityComponent {
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it
java.lang.String clipboardGetText();
boolean clipboardHasText();
diff --git a/android-project/app/src/main/java/org/libsdl/app/ActivityHook.java b/android-project/app/src/main/java/org/libsdl/app/ActivityHook.java
deleted file mode 100644
index d64adf5a4373e..0000000000000
--- a/android-project/app/src/main/java/org/libsdl/app/ActivityHook.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.libsdl.app;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation for {@link SDLActivityComponent} methods that correspond to
- * events in {@link android.app.Activity}.
- */
-@Retention(RetentionPolicy.SOURCE)
-@Target(ElementType.METHOD)
-public @interface ActivityHook {
-}
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDL.java b/android-project/app/src/main/java/org/libsdl/app/SDL.java
index d9a73a39c43a4..b132fea088b74 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDL.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDL.java
@@ -13,7 +13,7 @@ public class SDL {
// This function should be called first and sets up the native code
// so it can call into the Java classes
public static void setupJNI() {
- SDLActivityComponent.nativeSetupJNI();
+ SDLActivity.nativeSetupJNI();
SDLAudioManager.nativeSetupJNI();
SDLControllerManager.nativeSetupJNI();
}
@@ -22,7 +22,7 @@ public static void setupJNI() {
public static void initialize() {
setContext(null);
- SDLActivityComponent.initialize();
+ SDLActivity.initialize();
SDLAudioManager.initialize();
SDLControllerManager.initialize();
}
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index dd514a8b8e549..8a1aa690b497e 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -1,90 +1,732 @@
package org.libsdl.app;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.UiModeManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipboardManager;
+import android.content.ClipData;
+import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.hardware.Sensor;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.InputDevice;
import android.view.KeyEvent;
+import android.view.PointerIcon;
+import android.view.Surface;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.MimeTypeMap;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
-public abstract class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener, SDLComponentReceiver {
- private SDLActivityComponent component;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Locale;
+
+/**
+ SDL Activity
+*/
+public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
+ private static final String TAG = "SDL";
+ private static final int SDL_MAJOR_VERSION = 3;
+ private static final int SDL_MINOR_VERSION = 1;
+ private static final int SDL_MICRO_VERSION = 9;
+/*
+ // Display InputType.SOURCE/CLASS of events and devices
+ //
+ // SDLActivity.debugSource(device.getSources(), "device[" + device.getName() + "]");
+ // SDLActivity.debugSource(event.getSource(), "event");
+ public static void debugSource(int sources, String prefix) {
+ int s = sources;
+ int s_copy = sources;
+ String cls = "";
+ String src = "";
+ int tst = 0;
+ int FLAG_TAINTED = 0x80000000;
+
+ if ((s & InputDevice.SOURCE_CLASS_BUTTON) != 0) cls += " BUTTON";
+ if ((s & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) cls += " JOYSTICK";
+ if ((s & InputDevice.SOURCE_CLASS_POINTER) != 0) cls += " POINTER";
+ if ((s & InputDevice.SOURCE_CLASS_POSITION) != 0) cls += " POSITION";
+ if ((s & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) cls += " TRACKBALL";
+
+
+ int s2 = s_copy & ~InputDevice.SOURCE_ANY; // keep class bits
+ s2 &= ~( InputDevice.SOURCE_CLASS_BUTTON
+ | InputDevice.SOURCE_CLASS_JOYSTICK
+ | InputDevice.SOURCE_CLASS_POINTER
+ | InputDevice.SOURCE_CLASS_POSITION
+ | InputDevice.SOURCE_CLASS_TRACKBALL);
+
+ if (s2 != 0) cls += "Some_Unknown";
+
+ s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
+
+ if (Build.VERSION.SDK_INT >= 23) {
+ tst = InputDevice.SOURCE_BLUETOOTH_STYLUS;
+ if ((s & tst) == tst) src += " BLUETOOTH_STYLUS";
+ s2 &= ~tst;
+ }
+
+ tst = InputDevice.SOURCE_DPAD;
+ if ((s & tst) == tst) src += " DPAD";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_GAMEPAD;
+ if ((s & tst) == tst) src += " GAMEPAD";
+ s2 &= ~tst;
+
+ if (Build.VERSION.SDK_INT >= 21) {
+ tst = InputDevice.SOURCE_HDMI;
+ if ((s & tst) == tst) src += " HDMI";
+ s2 &= ~tst;
+ }
+
+ tst = InputDevice.SOURCE_JOYSTICK;
+ if ((s & tst) == tst) src += " JOYSTICK";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_KEYBOARD;
+ if ((s & tst) == tst) src += " KEYBOARD";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_MOUSE;
+ if ((s & tst) == tst) src += " MOUSE";
+ s2 &= ~tst;
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ tst = InputDevice.SOURCE_MOUSE_RELATIVE;
+ if ((s & tst) == tst) src += " MOUSE_RELATIVE";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_ROTARY_ENCODER;
+ if ((s & tst) == tst) src += " ROTARY_ENCODER";
+ s2 &= ~tst;
+ }
+ tst = InputDevice.SOURCE_STYLUS;
+ if ((s & tst) == tst) src += " STYLUS";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_TOUCHPAD;
+ if ((s & tst) == tst) src += " TOUCHPAD";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_TOUCHSCREEN;
+ if ((s & tst) == tst) src += " TOUCHSCREEN";
+ s2 &= ~tst;
+
+ if (Build.VERSION.SDK_INT >= 18) {
+ tst = InputDevice.SOURCE_TOUCH_NAVIGATION;
+ if ((s & tst) == tst) src += " TOUCH_NAVIGATION";
+ s2 &= ~tst;
+ }
+
+ tst = InputDevice.SOURCE_TRACKBALL;
+ if ((s & tst) == tst) src += " TRACKBALL";
+ s2 &= ~tst;
+
+ tst = InputDevice.SOURCE_ANY;
+ if ((s & tst) == tst) src += " ANY";
+ s2 &= ~tst;
+
+ if (s == FLAG_TAINTED) src += " FLAG_TAINTED";
+ s2 &= ~FLAG_TAINTED;
+
+ if (s2 != 0) src += " Some_Unknown";
+
+ Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src);
+ }
+*/
+
+ public static boolean mIsResumedCalled, mHasFocus;
+ public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */);
+
+ // Cursor types
+ // private static final int SDL_SYSTEM_CURSOR_NONE = -1;
+ private static final int SDL_SYSTEM_CURSOR_ARROW = 0;
+ private static final int SDL_SYSTEM_CURSOR_IBEAM = 1;
+ private static final int SDL_SYSTEM_CURSOR_WAIT = 2;
+ private static final int SDL_SYSTEM_CURSOR_CROSSHAIR = 3;
+ private static final int SDL_SYSTEM_CURSOR_WAITARROW = 4;
+ private static final int SDL_SYSTEM_CURSOR_SIZENWSE = 5;
+ private static final int SDL_SYSTEM_CURSOR_SIZENESW = 6;
+ private static final int SDL_SYSTEM_CURSOR_SIZEWE = 7;
+ private static final int SDL_SYSTEM_CURSOR_SIZENS = 8;
+ private static final int SDL_SYSTEM_CURSOR_SIZEALL = 9;
+ private static final int SDL_SYSTEM_CURSOR_NO = 10;
+ private static final int SDL_SYSTEM_CURSOR_HAND = 11;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT = 12;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_TOP = 13;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT = 14;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_RIGHT = 15;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT = 16;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOM = 17;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT = 18;
+ private static final int SDL_SYSTEM_CURSOR_WINDOW_LEFT = 19;
+
+ protected static final int SDL_ORIENTATION_UNKNOWN = 0;
+ protected static final int SDL_ORIENTATION_LANDSCAPE = 1;
+ protected static final int SDL_ORIENTATION_LANDSCAPE_FLIPPED = 2;
+ protected static final int SDL_ORIENTATION_PORTRAIT = 3;
+ protected static final int SDL_ORIENTATION_PORTRAIT_FLIPPED = 4;
+
+ protected static int mCurrentRotation;
+ 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 = true;
+
+ // Main components
+ protected static SDLActivity mSingleton;
+ protected static SDLSurface mSurface;
+ protected static SDLDummyEdit mTextEdit;
+ protected static boolean mScreenKeyboardShown;
+ protected static ViewGroup mLayout;
+ protected static SDLClipboardHandler mClipboardHandler;
+ protected static Hashtable<Integer, PointerIcon> mCursors;
+ protected static int mLastCursorID;
+ protected static SDLGenericMotionListener_API14 mMotionListener;
+ protected static HIDDeviceManager mHIDDeviceManager;
+
+ // This is what SDL runs in. It invokes SDL_main(), eventually
+ protected static Thread mSDLThread;
+ protected static boolean mSDLMainFinished = false;
+ protected static boolean mActivityCreated = false;
+ private static SDLFileDialogState mFileDialogState = null;
+
+ protected static SDLGenericMotionListener_API14 getMotionListener() {
+ if (mMotionListener == null) {
+ if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
+ mMotionListener = new SDLGenericMotionListener_API26();
+ } else if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
+ mMotionListener = new SDLGenericMotionListener_API24();
+ } else {
+ mMotionListener = new SDLGenericMotionListener_API14();
+ }
+ }
+
+ return mMotionListener;
+ }
+
+ /**
+ * The application entry point, called on a dedicated thread (SDLThread).
+ * The default implementation uses the getMainSharedObject() and getMainFunction() methods
+ * to invoke native code from the specified shared library.
+ * It can be overridden by derived classes.
+ */
+ protected void main() {
+ 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", "Finished main function");
+ }
+
+ /**
+ * 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 getContext().getApplicationInfo().nativeLibraryDir + "/" + 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.
+ * It can be overridden to provide names of shared libraries to be loaded.
+ * The default implementation returns the defaults. It never returns null.
+ * An array returned by a new implementation must at least contain "SDL3".
+ * Also keep in mind that the order the libraries are loaded may matter.
+ * @return names of shared libraries to be loaded (e.g. "SDL3", "main").
+ */
protected String[] getLibraries() {
- return null;
+ return new String[] {
+ "SDL3",
+ // "SDL3_image",
+ // "SDL3_mixer",
+ // "SDL3_net",
+ // "SDL3_ttf",
+ "main"
+ };
}
+
+ // Load the .so
+ public void loadLibraries() {
+ for (String lib : getLibraries()) {
+ SDL.loadLibrary(lib, this);
+ }
+ }
+
+ /**
+ * This method is called by SDL before starting the native application thread.
+ * It can be overridden to provide the arguments after the application name.
+ * The default implementation returns an empty array. It never returns null.
+ * @return arguments for the native application.
+ */
protected String[] getArguments() {
- return null;
+ return new String[0];
}
+ public static void initialize() {
+ // 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;
+ mCursors = new Hashtable<Integer, PointerIcon>();
+ mLastCursorID = 0;
+ mSDLThread = null;
+ mIsResumedCalled = false;
+ mHasFocus = true;
+ mNextNativeState = NativeState.INIT;
+ mCurrentNativeState = NativeState.INIT;
+ }
+
+ protected SDLSurface createSDLSurface(Context context) {
+ return new SDLSurface(context);
+ }
+
+ // Setup
@Override
protected void onCreate(Bundle savedInstanceState) {
+ Log.v(TAG, "Manufacturer: " + Build.MANUFACTURER);
+ Log.v(TAG, "Device: " + Build.DEVICE);
+ Log.v(TAG, "Model: " + Build.MODEL);
+ Log.v(TAG, "onCreate()");
super.onCreate(savedInstanceState);
- component = new SDLActivityComponent(this);
- String[] libraries = getLibraries();
- if (libraries != null) {
- component.setLibraries(libraries);
+
+ /* Control activity re-creation */
+ if (mSDLMainFinished || mActivityCreated) {
+ boolean allow_recreate = SDLActivity.nativeAllowRecreateActivity();
+ if (mSDLMainFinished) {
+ Log.v(TAG, "SDL main() finished");
+ }
+ if (allow_recreate) {
+ Log.v(TAG, "activity re-created");
+ } else {
+ Log.v(TAG, "activity finished");
+ System.exit(0);
+ return;
+ }
+ }
+
+ mActivityCreated = true;
+
+ try {
+ Thread.currentThread().setName("SDLActivity");
+ } catch (Exception e) {
+ Log.v(TAG, "modify thread properties failed " + e.toString());
+ }
+
+ // Load shared libraries
+ String errorMsgBrokenLib = "";
+ try {
+ loadLibraries();
+ mBrokenLibraries = false; /* success */
+ } catch(UnsatisfiedLinkError e) {
+ System.err.println(e.getMessage());
+ mBrokenLibraries = true;
+ errorMsgBrokenLib = e.getMessage();
+ } catch(Exception e) {
+ System.err.println(e.getMessage());
+ mBrokenLibraries = true;
+ errorMsgBrokenLib = e.getMessage();
+ }
+
+ if (!mBrokenLibraries) {
+ String expected_version = String.valueOf(SDL_MAJOR_VERSION) + "." +
+ String.valueOf(SDL_MINOR_VERSION) + "." +
+ String.valueOf(SDL_MICRO_VERSION);
+ String version = nativeGetVersion();
+ if (!version.equals(expected_version)) {
+ mBrokenLibraries = true;
+ errorMsgBrokenLib = "SDL C/Java version mismatch (expected " + expected_version + ", got " + version + ")";
+ }
+ }
+
+ if (mBrokenLibraries) {
+ mSingleton = this;
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
+ dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall."
+ + System.getProperty("line.separator")
+ + System.getProperty("line.separator")
+ + "Error: " + errorMsgBrokenLib);
+ dlgAlert.setTitle("SDL Error");
+ dlgAlert.setPositiveButton("Exit",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,int id) {
+ // if this button is clicked, close current activity
+ SDLActivity.mSingleton.finish();
+ }
+ });
+ dlgAlert.setCancelable(false);
+ dlgAlert.create().show();
+
+ return;
+ }
+
+
+ /* Control activity re-creation */
+ /* Robustness: check that the native code is run for the first time.
+ * (Maybe Activity was reset, but not the native code.) */
+ {
+ int run_count = SDLActivity.nativeCheckSDLThreadCounter(); /* get and increment a native counter */
+ if (run_count != 0) {
+ boolean allow_recreate = SDLActivity.nativeAllowRecreateActivity();
+ if (allow_recreate) {
+ Log.v(TAG, "activity re-created // run_count: " + run_count);
+ } else {
+ Log.v(TAG, "activity finished // run_count: " + run_count);
+ System.exit(0);
+ return;
+ }
+ }
+ }
+
+ // Set up JNI
+ SDL.setupJNI();
+
+ // Initialize state
+ SDL.initialize();
+
+ // So we can call stuff from static callbacks
+ mSingleton = this;
+ SDL.setContext(this);
+
+ mClipboardHandler = new SDLClipboardHandler();
+
+ mHIDDeviceManager = HIDDeviceManager.acquire(this);
+
+ // Set up the surface
+ mSurface = createSDLSurface(this);
+
+ mLayout = new RelativeLayout(this);
+ mLayout.addView(mSurface);
+
+ // Get our current screen orientation and pass it down.
+ SDLActivity.nativeSetNaturalOrientation(SDLActivity.getNaturalOrientation());
+ mCurrentRotation = SDLActivity.getCurrentRotation();
+ SDLActivity.onNativeRotationChanged(mCurrentRotation);
+
+ try {
+ if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
+ mCurrentLocale = getContext().getResources().getConfiguration().locale;
+ } else {
+ mCurrentLocale = getContext().getResources().getConfiguration().getLocales().get(0);
+ }
+ } catch(Exception ignored) {
}
- String[] args = getArguments();
- if (args != null) {
- component.setArguments(args);
+
+ switch (getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
+ case Configuration.UI_MODE_NIGHT_NO:
+ SDLActivity.onNativeDarkModeChanged(false);
+ break;
+ case Configuration.UI_MODE_NIGHT_YES:
+ SDLActivity.onNativeDarkModeChanged(true);
+ break;
+ }
+
+ 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) {
+ String filename = intent.getData().getPath();
+ if (filename != null) {
+ Log.v(TAG, "Got filename: " + filename);
+ SDLActivity.onNativeDropFile(filename);
+ }
+ }
+ }
+
+ 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;
}
- component.onCreate();
+ SDLActivity.handleNativeState();
}
+ // Events
@Override
protected void onPause() {
+ Log.v(TAG, "onPause()");
super.onPause();
- component.onPause();
+
+ if (mHIDDeviceManager != null) {
+ mHIDDeviceManager.setFrozen(true);
+ }
+ if (!mHasMultiWindow) {
+ pauseNativeThread();
+ }
}
@Override
protected void onResume() {
+ Log.v(TAG, "onResume()");
super.onResume();
- component.onResume();
+
+ if (mHIDDeviceManager != null) {
+ mHIDDeviceManager.setFrozen(false);
+ }
+ if (!mHasMultiWindow) {
+ resumeNativeThread();
+ }
}
@Override
protected void onStop() {
+ Log.v(TAG, "onStop()");
super.onStop();
- component.onStop();
+ if (mHasMultiWindow) {
+ pauseNativeThread();
+ }
}
@Override
protected void onStart() {
+ Log.v(TAG, "onStart()");
super.onStart();
- component.onStart();
+ if (mHasMultiWindow) {
+ resumeNativeThread();
+ }
+ }
+
+ public static int getNaturalOrientation() {
+ int result = SDL_ORIENTATION_UNKNOWN;
+
+ Activity activity = (Activity)getContext();
+ if (activity != null) {
+ Configuration config = activity.getResources().getConfiguration();
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ int rotation = display.getRotation();
+ if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
+ config.orientation == Configuration.ORIENTATION_LANDSCAPE) ||
+ ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
+ config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
+ result = SDL_ORIENTATION_LANDSCAPE;
+ } else {
+ result = SDL_ORIENTATION_PORTRAIT;
+ }
+ }
+ return result;
+ }
+
+ public static int getCurrentRotation() {
+ int result = 0;
+
+ Activity activity = (Activity)getContext();
+ if (activity != null) {
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ switch (display.getRotation()) {
+ case Surface.ROTATION_0:
+ result = 0;
+ break;
+ case Surface.ROTATION_90:
+ result = 90;
+ break;
+ case Surface.ROTATION_180:
+ result = 180;
+ break;
+ case Surface.ROTATION_270:
+ result = 270;
+ break;
+ }
+ }
+ return result;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
- component.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 onTrimMemory(int level) {
+ Log.v(TAG, "onTrimMemory()");
super.onTrimMemory(level);
- component.onTrimMemory(level);
+
+ if (SDLActivity.mBrokenLibraries) {
+ return;
+ }
+
+ SDLActivity.nativeLowMemory();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ Log.v(TAG, "onConfigurationChanged()");
super.onConfigurationChanged(newConfig);
- component.onConfigurationChanged(newConfig);
+
+ if (SDLActivity.mBrokenLibraries) {
+ return;
+ }
+
+ if (mCurrentLocale == null || !mCurrentLocale.equals(newConfig.locale)) {
+ mCurrentLocale = newConfig.locale;
+ SDLActivity.onNativeLocaleChanged();
+ }
+
+ switch (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
+ case Configuration.UI_MODE_NIGHT_NO:
+ SDLActivity.onNativeDarkModeChanged(false);
+ break;
+ case Configuration.UI_MODE_NIGHT_YES:
+ SDLActivity.onNativeDarkModeChanged(true);
+ break;
+ }
}
@Override
protected void onDestroy() {
+ Log.v(TAG, "onDestroy()");
+
+ if (mHIDDeviceManager != null) {
+ HIDDeviceManager.release(mHIDDeviceManager);
+ mHIDDeviceManager = null;
+ }
+
+ SDLAudioManager.release(this);
+
+ if (SDLActivity.mBrokenLibraries) {
+ super.onDestroy();
+ return;
+ }
+
+ if (SDLActivity.mSDLThread != null) {
+
+ // Send Quit event to "SDLThread" thread
+ SDLActivity.nativeSendQuit();
+
+ // Wait for "SDLThread" thread to end
+ try {
+ // Use a timeout because:
+ // C SDLmain() thread might have started (mSDLThread.start() called)
+ // while the SDL_Init() might not have been called yet,
+ // and so the previous QUIT event will be discarded by SDL_Init() and app is running, not exiting.
+ SDLActivity.mSDLThread.join(1000);
+ } catch(Exception e) {
+ Log.v(TAG, "Problem stopping SDLThread: " + e);
+ }
+ }
+
+ SDLActivity.nativeQuit();
+
super.onDestroy();
- component.onDestroy();
}
@Override
public void onBackPressed() {
- if (component.onBackPressed()) {
+ // Check if we want to block the back button in case of mouse right click.
+ //
+ // If we do, the normal hardware back button will no longer work and people have to use home,
+ // but the mouse right click will work.
+ //
+ boolean trapBack = SDLActivity.nativeGetHintBoolean("SDL_ANDROID_TRAP_BACK_BUTTON", false);
+ if (trapBack) {
+ // Exit and let the mouse handler handle this button (if appropriate)
+ return;
+ }
+
+ // Default system back button behavior.
+ if (!isFinishing()) {
super.onBackPresse
(Patch may be truncated, please check the link at the top of this post.)