From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Fri, 6 Mar 2026 13:30:59 -0800
Subject: Move contrib libraries to contrib repo
---
.../app/src/main/AndroidManifest.xml | 107 -
.../src/main/java/org/libsdl/app/HIDDevice.java | 21 -
.../libsdl/app/HIDDeviceBLESteamController.java | 645 ------
.../main/java/org/libsdl/app/HIDDeviceManager.java | 689 ------
.../src/main/java/org/libsdl/app/HIDDeviceUSB.java | 318 ---
.../app/src/main/java/org/libsdl/app/SDL.java | 90 -
.../src/main/java/org/libsdl/app/SDLActivity.java | 2189 --------------------
.../main/java/org/libsdl/app/SDLAudioManager.java | 126 --
.../java/org/libsdl/app/SDLControllerManager.java | 849 --------
.../src/main/java/org/libsdl/app/SDLDummyEdit.java | 66 -
.../java/org/libsdl/app/SDLInputConnection.java | 138 --
.../src/main/java/org/libsdl/app/SDLSurface.java | 408 ----
.../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2683 -> 0 bytes
.../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1698 -> 0 bytes
.../app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3872 -> 0 bytes
.../app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6874 -> 0 bytes
.../src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 14526 -> 0 bytes
.../app/src/main/res/values/colors.xml | 6 -
.../app/src/main/res/values/strings.xml | 3 -
.../app/src/main/res/values/styles.xml | 7 -
20 files changed, 5662 deletions(-)
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/AndroidManifest.xml
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDevice.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDL.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/mipmap-hdpi/ic_launcher.png
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/mipmap-mdpi/ic_launcher.png
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/mipmap-xhdpi/ic_launcher.png
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/values/colors.xml
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/values/strings.xml
delete mode 100644 contrib/SDL-3.2.8/android-project/app/src/main/res/values/styles.xml
(limited to 'contrib/SDL-3.2.8/android-project/app/src/main')
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/AndroidManifest.xml b/contrib/SDL-3.2.8/android-project/app/src/main/AndroidManifest.xml
deleted file mode 100644
index f3a7cd5..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDevice.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDevice.java
deleted file mode 100644
index f960953..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDevice.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.libsdl.app;
-
-import android.hardware.usb.UsbDevice;
-
-interface HIDDevice
-{
- public int getId();
- public int getVendorId();
- public int getProductId();
- public String getSerialNumber();
- public int getVersion();
- public String getManufacturerName();
- public String getProductName();
- public UsbDevice getDevice();
- public boolean open();
- public int writeReport(byte[] report, boolean feature);
- public boolean readReport(byte[] report, boolean feature);
- public void setFrozen(boolean frozen);
- public void close();
- public void shutdown();
-}
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
deleted file mode 100644
index d2dc0d2..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
+++ /dev/null
@@ -1,645 +0,0 @@
-package org.libsdl.app;
-
-import android.content.Context;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCallback;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattDescriptor;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothGattService;
-import android.hardware.usb.UsbDevice;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.os.*;
-
-//import com.android.internal.util.HexDump;
-
-import java.lang.Runnable;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.UUID;
-
-class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
-
- private static final String TAG = "hidapi";
- private HIDDeviceManager mManager;
- private BluetoothDevice mDevice;
- private int mDeviceId;
- private BluetoothGatt mGatt;
- private boolean mIsRegistered = false;
- private boolean mIsConnected = false;
- private boolean mIsChromebook = false;
- private boolean mIsReconnecting = false;
- private boolean mFrozen = false;
- private LinkedList mOperations;
- GattOperation mCurrentOperation = null;
- private Handler mHandler;
-
- private static final int TRANSPORT_AUTO = 0;
- private static final int TRANSPORT_BREDR = 1;
- private static final int TRANSPORT_LE = 2;
-
- private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
-
- static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
- static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
- static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
- static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
-
- static class GattOperation {
- private enum Operation {
- CHR_READ,
- CHR_WRITE,
- ENABLE_NOTIFICATION
- }
-
- Operation mOp;
- UUID mUuid;
- byte[] mValue;
- BluetoothGatt mGatt;
- boolean mResult = true;
-
- private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
- mGatt = gatt;
- mOp = operation;
- mUuid = uuid;
- }
-
- private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
- mGatt = gatt;
- mOp = operation;
- mUuid = uuid;
- mValue = value;
- }
-
- public void run() {
- // This is executed in main thread
- BluetoothGattCharacteristic chr;
-
- switch (mOp) {
- case CHR_READ:
- chr = getCharacteristic(mUuid);
- //Log.v(TAG, "Reading characteristic " + chr.getUuid());
- if (!mGatt.readCharacteristic(chr)) {
- Log.e(TAG, "Unable to read characteristic " + mUuid.toString());
- mResult = false;
- break;
- }
- mResult = true;
- break;
- case CHR_WRITE:
- chr = getCharacteristic(mUuid);
- //Log.v(TAG, "Writing characteristic " + chr.getUuid() + " value=" + HexDump.toHexString(value));
- chr.setValue(mValue);
- if (!mGatt.writeCharacteristic(chr)) {
- Log.e(TAG, "Unable to write characteristic " + mUuid.toString());
- mResult = false;
- break;
- }
- mResult = true;
- break;
- case ENABLE_NOTIFICATION:
- chr = getCharacteristic(mUuid);
- //Log.v(TAG, "Writing descriptor of " + chr.getUuid());
- if (chr != null) {
- BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
- if (cccd != null) {
- int properties = chr.getProperties();
- byte[] value;
- if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY) {
- value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
- } else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE) {
- value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
- } else {
- Log.e(TAG, "Unable to start notifications on input characteristic");
- mResult = false;
- return;
- }
-
- mGatt.setCharacteristicNotification(chr, true);
- cccd.setValue(value);
- if (!mGatt.writeDescriptor(cccd)) {
- Log.e(TAG, "Unable to write descriptor " + mUuid.toString());
- mResult = false;
- return;
- }
- mResult = true;
- }
- }
- }
- }
-
- public boolean finish() {
- return mResult;
- }
-
- private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
- BluetoothGattService valveService = mGatt.getService(steamControllerService);
- if (valveService == null)
- return null;
- return valveService.getCharacteristic(uuid);
- }
-
- static public GattOperation readCharacteristic(BluetoothGatt gatt, UUID uuid) {
- return new GattOperation(gatt, Operation.CHR_READ, uuid);
- }
-
- static public GattOperation writeCharacteristic(BluetoothGatt gatt, UUID uuid, byte[] value) {
- return new GattOperation(gatt, Operation.CHR_WRITE, uuid, value);
- }
-
- static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
- return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
- }
- }
-
- public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
- mManager = manager;
- mDevice = device;
- mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
- mIsRegistered = false;
- mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
- mOperations = new LinkedList();
- mHandler = new Handler(Looper.getMainLooper());
-
- mGatt = connectGatt();
- // final HIDDeviceBLESteamController finalThis = this;
- // mHandler.postDelayed(new Runnable() {
- // @Override
- // public void run() {
- // finalThis.checkConnectionForChromebookIssue();
- // }
- // }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
- }
-
- public String getIdentifier() {
- return String.format("SteamController.%s", mDevice.getAddress());
- }
-
- public BluetoothGatt getGatt() {
- return mGatt;
- }
-
- // Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
- // of TRANSPORT_LE. Let's force ourselves to connect low energy.
- private BluetoothGatt connectGatt(boolean managed) {
- if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 (M) */) {
- try {
- return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
- } catch (Exception e) {
- return mDevice.connectGatt(mManager.getContext(), managed, this);
- }
- } else {
- return mDevice.connectGatt(mManager.getContext(), managed, this);
- }
- }
-
- private BluetoothGatt connectGatt() {
- return connectGatt(false);
- }
-
- protected int getConnectionState() {
-
- Context context = mManager.getContext();
- if (context == null) {
- // We are lacking any context to get our Bluetooth information. We'll just assume disconnected.
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- BluetoothManager btManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
- if (btManager == null) {
- // This device doesn't support Bluetooth. We should never be here, because how did
- // we instantiate a device to start with?
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
- }
-
- public void reconnect() {
-
- if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
- mGatt.disconnect();
- mGatt = connectGatt();
- }
-
- }
-
- protected void checkConnectionForChromebookIssue() {
- if (!mIsChromebook) {
- // We only do this on Chromebooks, because otherwise it's really annoying to just attempt
- // over and over.
- return;
- }
-
- int connectionState = getConnectionState();
-
- switch (connectionState) {
- case BluetoothProfile.STATE_CONNECTED:
- if (!mIsConnected) {
- // We are in the Bad Chromebook Place. We can force a disconnect
- // to try to recover.
- Log.v(TAG, "Chromebook: We are in a very bad state; the controller shows as connected in the underlying Bluetooth layer, but we never received a callback. Forcing a reconnect.");
- mIsReconnecting = true;
- mGatt.disconnect();
- mGatt = connectGatt(false);
- break;
- }
- else if (!isRegistered()) {
- if (mGatt.getServices().size() > 0) {
- Log.v(TAG, "Chromebook: We are connected to a controller, but never got our registration. Trying to recover.");
- probeService(this);
- }
- else {
- Log.v(TAG, "Chromebook: We are connected to a controller, but never discovered services. Trying to recover.");
- mIsReconnecting = true;
- mGatt.disconnect();
- mGatt = connectGatt(false);
- break;
- }
- }
- else {
- Log.v(TAG, "Chromebook: We are connected, and registered. Everything's good!");
- return;
- }
- break;
-
- case BluetoothProfile.STATE_DISCONNECTED:
- Log.v(TAG, "Chromebook: We have either been disconnected, or the Chromebook BtGatt.ContextMap bug has bitten us. Attempting a disconnect/reconnect, but we may not be able to recover.");
-
- mIsReconnecting = true;
- mGatt.disconnect();
- mGatt = connectGatt(false);
- break;
-
- case BluetoothProfile.STATE_CONNECTING:
- Log.v(TAG, "Chromebook: We're still trying to connect. Waiting a bit longer.");
- break;
- }
-
- final HIDDeviceBLESteamController finalThis = this;
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- finalThis.checkConnectionForChromebookIssue();
- }
- }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
- }
-
- private boolean isRegistered() {
- return mIsRegistered;
- }
-
- private void setRegistered() {
- mIsRegistered = true;
- }
-
- private boolean probeService(HIDDeviceBLESteamController controller) {
-
- if (isRegistered()) {
- return true;
- }
-
- if (!mIsConnected) {
- return false;
- }
-
- Log.v(TAG, "probeService controller=" + controller);
-
- for (BluetoothGattService service : mGatt.getServices()) {
- if (service.getUuid().equals(steamControllerService)) {
- Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
-
- for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
- if (chr.getUuid().equals(inputCharacteristic)) {
- Log.v(TAG, "Found input characteristic");
- // Start notifications
- BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
- if (cccd != null) {
- enableNotification(chr.getUuid());
- }
- }
- }
- return true;
- }
- }
-
- if ((mGatt.getServices().size() == 0) && mIsChromebook && !mIsReconnecting) {
- Log.e(TAG, "Chromebook: Discovered services were empty; this almost certainly means the BtGatt.ContextMap bug has bitten us.");
- mIsConnected = false;
- mIsReconnecting = true;
- mGatt.disconnect();
- mGatt = connectGatt(false);
- }
-
- return false;
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- private void finishCurrentGattOperation() {
- GattOperation op = null;
- synchronized (mOperations) {
- if (mCurrentOperation != null) {
- op = mCurrentOperation;
- mCurrentOperation = null;
- }
- }
- if (op != null) {
- boolean result = op.finish(); // TODO: Maybe in main thread as well?
-
- // Our operation failed, let's add it back to the beginning of our queue.
- if (!result) {
- mOperations.addFirst(op);
- }
- }
- executeNextGattOperation();
- }
-
- private void executeNextGattOperation() {
- synchronized (mOperations) {
- if (mCurrentOperation != null)
- return;
-
- if (mOperations.isEmpty())
- return;
-
- mCurrentOperation = mOperations.removeFirst();
- }
-
- // Run in main thread
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (mOperations) {
- if (mCurrentOperation == null) {
- Log.e(TAG, "Current operation null in executor?");
- return;
- }
-
- mCurrentOperation.run();
- // now wait for the GATT callback and when it comes, finish this operation
- }
- }
- });
- }
-
- private void queueGattOperation(GattOperation op) {
- synchronized (mOperations) {
- mOperations.add(op);
- }
- executeNextGattOperation();
- }
-
- private void enableNotification(UUID chrUuid) {
- GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
- queueGattOperation(op);
- }
-
- public void writeCharacteristic(UUID uuid, byte[] value) {
- GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
- queueGattOperation(op);
- }
-
- public void readCharacteristic(UUID uuid) {
- GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
- queueGattOperation(op);
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////// BluetoothGattCallback overridden methods
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
- //Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
- mIsReconnecting = false;
- if (newState == 2) {
- mIsConnected = true;
- // Run directly, without GattOperation
- if (!isRegistered()) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mGatt.discoverServices();
- }
- });
- }
- }
- else if (newState == 0) {
- mIsConnected = false;
- }
-
- // Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
- }
-
- public void onServicesDiscovered(BluetoothGatt gatt, int status) {
- //Log.v(TAG, "onServicesDiscovered status=" + status);
- if (status == 0) {
- if (gatt.getServices().size() == 0) {
- Log.v(TAG, "onServicesDiscovered returned zero services; something has gone horribly wrong down in Android's Bluetooth stack.");
- mIsReconnecting = true;
- mIsConnected = false;
- gatt.disconnect();
- mGatt = connectGatt(false);
- }
- else {
- probeService(this);
- }
- }
- }
-
- public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
- //Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
-
- if (characteristic.getUuid().equals(reportCharacteristic) && !mFrozen) {
- mManager.HIDDeviceReportResponse(getId(), characteristic.getValue());
- }
-
- finishCurrentGattOperation();
- }
-
- public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
- //Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
-
- if (characteristic.getUuid().equals(reportCharacteristic)) {
- // Only register controller with the native side once it has been fully configured
- if (!isRegistered()) {
- Log.v(TAG, "Registering Steam Controller with ID: " + getId());
- mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true);
- setRegistered();
- }
- }
-
- finishCurrentGattOperation();
- }
-
- public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
- // Enable this for verbose logging of controller input reports
- //Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
-
- if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) {
- mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
- }
- }
-
- public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
- //Log.v(TAG, "onDescriptorRead status=" + status);
- }
-
- public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
- BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
- //Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
-
- if (chr.getUuid().equals(inputCharacteristic)) {
- boolean hasWrittenInputDescriptor = true;
- BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
- if (reportChr != null) {
- Log.v(TAG, "Writing report characteristic to enter valve mode");
- reportChr.setValue(enterValveMode);
- gatt.writeCharacteristic(reportChr);
- }
- }
-
- finishCurrentGattOperation();
- }
-
- public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
- //Log.v(TAG, "onReliableWriteCompleted status=" + status);
- }
-
- public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
- //Log.v(TAG, "onReadRemoteRssi status=" + status);
- }
-
- public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
- //Log.v(TAG, "onMtuChanged status=" + status);
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- //////// Public API
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- @Override
- public int getId() {
- return mDeviceId;
- }
-
- @Override
- public int getVendorId() {
- // Valve Corporation
- final int VALVE_USB_VID = 0x28DE;
- return VALVE_USB_VID;
- }
-
- @Override
- public int getProductId() {
- // We don't have an easy way to query from the Bluetooth device, but we know what it is
- final int D0G_BLE2_PID = 0x1106;
- return D0G_BLE2_PID;
- }
-
- @Override
- public String getSerialNumber() {
- // This will be read later via feature report by Steam
- return "12345";
- }
-
- @Override
- public int getVersion() {
- return 0;
- }
-
- @Override
- public String getManufacturerName() {
- return "Valve Corporation";
- }
-
- @Override
- public String getProductName() {
- return "Steam Controller";
- }
-
- @Override
- public UsbDevice getDevice() {
- return null;
- }
-
- @Override
- public boolean open() {
- return true;
- }
-
- @Override
- public int writeReport(byte[] report, boolean feature) {
- if (!isRegistered()) {
- Log.e(TAG, "Attempted writeReport before Steam Controller is registered!");
- if (mIsConnected) {
- probeService(this);
- }
- return -1;
- }
-
- if (feature) {
- // We need to skip the first byte, as that doesn't go over the air
- byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
- //Log.v(TAG, "writeFeatureReport " + HexDump.dumpHexString(actual_report));
- writeCharacteristic(reportCharacteristic, actual_report);
- return report.length;
- } else {
- //Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report));
- writeCharacteristic(reportCharacteristic, report);
- return report.length;
- }
- }
-
- @Override
- public boolean readReport(byte[] report, boolean feature) {
- if (!isRegistered()) {
- Log.e(TAG, "Attempted readReport before Steam Controller is registered!");
- if (mIsConnected) {
- probeService(this);
- }
- return false;
- }
-
- if (feature) {
- readCharacteristic(reportCharacteristic);
- return true;
- } else {
- // Not implemented
- return false;
- }
- }
-
- @Override
- public void close() {
- }
-
- @Override
- public void setFrozen(boolean frozen) {
- mFrozen = frozen;
- }
-
- @Override
- public void shutdown() {
- close();
-
- BluetoothGatt g = mGatt;
- if (g != null) {
- g.disconnect();
- g.close();
- mGatt = null;
- }
- mManager = null;
- mIsRegistered = false;
- mIsConnected = false;
- mOperations.clear();
- }
-
-}
-
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
deleted file mode 100644
index 37d80ca..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
+++ /dev/null
@@ -1,689 +0,0 @@
-package org.libsdl.app;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.os.Build;
-import android.util.Log;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.hardware.usb.*;
-import android.os.Handler;
-import android.os.Looper;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-public class HIDDeviceManager {
- private static final String TAG = "hidapi";
- private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
-
- private static HIDDeviceManager sManager;
- private static int sManagerRefCount = 0;
-
- public static HIDDeviceManager acquire(Context context) {
- if (sManagerRefCount == 0) {
- sManager = new HIDDeviceManager(context);
- }
- ++sManagerRefCount;
- return sManager;
- }
-
- public static void release(HIDDeviceManager manager) {
- if (manager == sManager) {
- --sManagerRefCount;
- if (sManagerRefCount == 0) {
- sManager.close();
- sManager = null;
- }
- }
- }
-
- private Context mContext;
- private HashMap mDevicesById = new HashMap();
- private HashMap mBluetoothDevices = new HashMap();
- private int mNextDeviceId = 0;
- private SharedPreferences mSharedPreferences = null;
- private boolean mIsChromebook = false;
- private UsbManager mUsbManager;
- private Handler mHandler;
- private BluetoothManager mBluetoothManager;
- private List mLastBluetoothDevices;
-
- private final BroadcastReceiver mUsbBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
- UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- handleUsbDeviceAttached(usbDevice);
- } else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
- UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- handleUsbDeviceDetached(usbDevice);
- } else if (action.equals(HIDDeviceManager.ACTION_USB_PERMISSION)) {
- UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- handleUsbDevicePermission(usbDevice, intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false));
- }
- }
- };
-
- private final BroadcastReceiver mBluetoothBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- // Bluetooth device was connected. If it was a Steam Controller, handle it
- if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- Log.d(TAG, "Bluetooth device connected: " + device);
-
- if (isSteamController(device)) {
- connectBluetoothDevice(device);
- }
- }
-
- // Bluetooth device was disconnected, remove from controller manager (if any)
- if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- Log.d(TAG, "Bluetooth device disconnected: " + device);
-
- disconnectBluetoothDevice(device);
- }
- }
- };
-
- private HIDDeviceManager(final Context context) {
- mContext = context;
-
- HIDDeviceRegisterCallback();
-
- mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
- mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
-
-// if (shouldClear) {
-// SharedPreferences.Editor spedit = mSharedPreferences.edit();
-// spedit.clear();
-// spedit.commit();
-// }
-// else
- {
- mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
- }
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public int getDeviceIDForIdentifier(String identifier) {
- SharedPreferences.Editor spedit = mSharedPreferences.edit();
-
- int result = mSharedPreferences.getInt(identifier, 0);
- if (result == 0) {
- result = mNextDeviceId++;
- spedit.putInt("next_device_id", mNextDeviceId);
- }
-
- spedit.putInt(identifier, result);
- spedit.commit();
- return result;
- }
-
- private void initializeUSB() {
- mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
- if (mUsbManager == null) {
- return;
- }
-
- /*
- // Logging
- for (UsbDevice device : mUsbManager.getDeviceList().values()) {
- Log.i(TAG,"Path: " + device.getDeviceName());
- Log.i(TAG,"Manufacturer: " + device.getManufacturerName());
- Log.i(TAG,"Product: " + device.getProductName());
- Log.i(TAG,"ID: " + device.getDeviceId());
- Log.i(TAG,"Class: " + device.getDeviceClass());
- Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
- Log.i(TAG,"Vendor ID " + device.getVendorId());
- Log.i(TAG,"Product ID: " + device.getProductId());
- Log.i(TAG,"Interface count: " + device.getInterfaceCount());
- Log.i(TAG,"---------------------------------------");
-
- // Get interface details
- for (int index = 0; index < device.getInterfaceCount(); index++) {
- UsbInterface mUsbInterface = device.getInterface(index);
- Log.i(TAG," ***** *****");
- Log.i(TAG," Interface index: " + index);
- Log.i(TAG," Interface ID: " + mUsbInterface.getId());
- Log.i(TAG," Interface class: " + mUsbInterface.getInterfaceClass());
- Log.i(TAG," Interface subclass: " + mUsbInterface.getInterfaceSubclass());
- Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
- Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
-
- // Get endpoint details
- for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
- {
- UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
- Log.i(TAG," ++++ ++++ ++++");
- Log.i(TAG," Endpoint index: " + epi);
- Log.i(TAG," Attributes: " + mEndpoint.getAttributes());
- Log.i(TAG," Direction: " + mEndpoint.getDirection());
- Log.i(TAG," Number: " + mEndpoint.getEndpointNumber());
- Log.i(TAG," Interval: " + mEndpoint.getInterval());
- Log.i(TAG," Packet size: " + mEndpoint.getMaxPacketSize());
- Log.i(TAG," Type: " + mEndpoint.getType());
- }
- }
- }
- Log.i(TAG," No more devices connected.");
- */
-
- // Register for USB broadcasts and permission completions
- IntentFilter filter = new IntentFilter();
- filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
- filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
- filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- mContext.registerReceiver(mUsbBroadcast, filter, Context.RECEIVER_EXPORTED);
- } else {
- mContext.registerReceiver(mUsbBroadcast, filter);
- }
-
- for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
- handleUsbDeviceAttached(usbDevice);
- }
- }
-
- UsbManager getUSBManager() {
- return mUsbManager;
- }
-
- private void shutdownUSB() {
- try {
- mContext.unregisterReceiver(mUsbBroadcast);
- } catch (Exception e) {
- // We may not have registered, that's okay
- }
- }
-
- private boolean isHIDDeviceInterface(UsbDevice usbDevice, UsbInterface usbInterface) {
- if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
- return true;
- }
- if (isXbox360Controller(usbDevice, usbInterface) || isXboxOneController(usbDevice, usbInterface)) {
- return true;
- }
- return false;
- }
-
- private boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
- final int XB360_IFACE_SUBCLASS = 93;
- final int XB360_IFACE_PROTOCOL = 1; // Wired
- final int XB360W_IFACE_PROTOCOL = 129; // Wireless
- final int[] SUPPORTED_VENDORS = {
- 0x0079, // GPD Win 2
- 0x044f, // Thrustmaster
- 0x045e, // Microsoft
- 0x046d, // Logitech
- 0x056e, // Elecom
- 0x06a3, // Saitek
- 0x0738, // Mad Catz
- 0x07ff, // Mad Catz
- 0x0e6f, // PDP
- 0x0f0d, // Hori
- 0x1038, // SteelSeries
- 0x11c9, // Nacon
- 0x12ab, // Unknown
- 0x1430, // RedOctane
- 0x146b, // BigBen
- 0x1532, // Razer Sabertooth
- 0x15e4, // Numark
- 0x162e, // Joytech
- 0x1689, // Razer Onza
- 0x1949, // Lab126, Inc.
- 0x1bad, // Harmonix
- 0x20d6, // PowerA
- 0x24c6, // PowerA
- 0x2c22, // Qanba
- 0x2dc8, // 8BitDo
- 0x9886, // ASTRO Gaming
- };
-
- if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
- usbInterface.getInterfaceSubclass() == XB360_IFACE_SUBCLASS &&
- (usbInterface.getInterfaceProtocol() == XB360_IFACE_PROTOCOL ||
- usbInterface.getInterfaceProtocol() == XB360W_IFACE_PROTOCOL)) {
- int vendor_id = usbDevice.getVendorId();
- for (int supportedVid : SUPPORTED_VENDORS) {
- if (vendor_id == supportedVid) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
- final int XB1_IFACE_SUBCLASS = 71;
- final int XB1_IFACE_PROTOCOL = 208;
- final int[] SUPPORTED_VENDORS = {
- 0x03f0, // HP
- 0x044f, // Thrustmaster
- 0x045e, // Microsoft
- 0x0738, // Mad Catz
- 0x0b05, // ASUS
- 0x0e6f, // PDP
- 0x0f0d, // Hori
- 0x10f5, // Turtle Beach
- 0x1532, // Razer Wildcat
- 0x20d6, // PowerA
- 0x24c6, // PowerA
- 0x2dc8, // 8BitDo
- 0x2e24, // Hyperkin
- 0x3537, // GameSir
- };
-
- if (usbInterface.getId() == 0 &&
- usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
- usbInterface.getInterfaceSubclass() == XB1_IFACE_SUBCLASS &&
- usbInterface.getInterfaceProtocol() == XB1_IFACE_PROTOCOL) {
- int vendor_id = usbDevice.getVendorId();
- for (int supportedVid : SUPPORTED_VENDORS) {
- if (vendor_id == supportedVid) {
- return true;
- }
- }
- }
- return false;
- }
-
- private void handleUsbDeviceAttached(UsbDevice usbDevice) {
- connectHIDDeviceUSB(usbDevice);
- }
-
- private void handleUsbDeviceDetached(UsbDevice usbDevice) {
- List devices = new ArrayList();
- for (HIDDevice device : mDevicesById.values()) {
- if (usbDevice.equals(device.getDevice())) {
- devices.add(device.getId());
- }
- }
- for (int id : devices) {
- HIDDevice device = mDevicesById.get(id);
- mDevicesById.remove(id);
- device.shutdown();
- HIDDeviceDisconnected(id);
- }
- }
-
- private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
- for (HIDDevice device : mDevicesById.values()) {
- if (usbDevice.equals(device.getDevice())) {
- boolean opened = false;
- if (permission_granted) {
- opened = device.open();
- }
- HIDDeviceOpenResult(device.getId(), opened);
- }
- }
- }
-
- private void connectHIDDeviceUSB(UsbDevice usbDevice) {
- synchronized (this) {
- int interface_mask = 0;
- for (int interface_index = 0; interface_index < usbDevice.getInterfaceCount(); interface_index++) {
- UsbInterface usbInterface = usbDevice.getInterface(interface_index);
- if (isHIDDeviceInterface(usbDevice, usbInterface)) {
- // Check to see if we've already added this interface
- // This happens with the Xbox Series X controller which has a duplicate interface 0, which is inactive
- int interface_id = usbInterface.getId();
- if ((interface_mask & (1 << interface_id)) != 0) {
- continue;
- }
- interface_mask |= (1 << interface_id);
-
- HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
- int id = device.getId();
- mDevicesById.put(id, device);
- HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false);
- }
- }
- }
- }
-
- private void initializeBluetooth() {
- Log.d(TAG, "Initializing Bluetooth");
-
- if (Build.VERSION.SDK_INT >= 31 /* Android 12 */ &&
- mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH_CONNECT, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
- Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH_CONNECT");
- return;
- }
-
- if (Build.VERSION.SDK_INT <= 30 /* Android 11.0 (R) */ &&
- mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
- Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
- return;
- }
-
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18 /* Android 4.3 (JELLY_BEAN_MR2) */)) {
- Log.d(TAG, "Couldn't initialize Bluetooth, this version of Android does not support Bluetooth LE");
- return;
- }
-
- // Find bonded bluetooth controllers and create SteamControllers for them
- mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (mBluetoothManager == null) {
- // This device doesn't support Bluetooth.
- return;
- }
-
- BluetoothAdapter btAdapter = mBluetoothManager.getAdapter();
- if (btAdapter == null) {
- // This device has Bluetooth support in the codebase, but has no available adapters.
- return;
- }
-
- // Get our bonded devices.
- for (BluetoothDevice device : btAdapter.getBondedDevices()) {
-
- Log.d(TAG, "Bluetooth device available: " + device);
- if (isSteamController(device)) {
- connectBluetoothDevice(device);
- }
-
- }
-
- // NOTE: These don't work on Chromebooks, to my undying dismay.
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
- filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- mContext.registerReceiver(mBluetoothBroadcast, filter, Context.RECEIVER_EXPORTED);
- } else {
- mContext.registerReceiver(mBluetoothBroadcast, filter);
- }
-
- if (mIsChromebook) {
- mHandler = new Handler(Looper.getMainLooper());
- mLastBluetoothDevices = new ArrayList();
-
- // final HIDDeviceManager finalThis = this;
- // mHandler.postDelayed(new Runnable() {
- // @Override
- // public void run() {
- // finalThis.chromebookConnectionHandler();
- // }
- // }, 5000);
- }
- }
-
- private void shutdownBluetooth() {
- try {
- mContext.unregisterReceiver(mBluetoothBroadcast);
- } catch (Exception e) {
- // We may not have registered, that's okay
- }
- }
-
- // Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
- // This function provides a sort of dummy version of that, watching for changes in the
- // connected devices and attempting to add controllers as things change.
- public void chromebookConnectionHandler() {
- if (!mIsChromebook) {
- return;
- }
-
- ArrayList disconnected = new ArrayList();
- ArrayList connected = new ArrayList();
-
- List currentConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
-
- for (BluetoothDevice bluetoothDevice : currentConnected) {
- if (!mLastBluetoothDevices.contains(bluetoothDevice)) {
- connected.add(bluetoothDevice);
- }
- }
- for (BluetoothDevice bluetoothDevice : mLastBluetoothDevices) {
- if (!currentConnected.contains(bluetoothDevice)) {
- disconnected.add(bluetoothDevice);
- }
- }
-
- mLastBluetoothDevices = currentConnected;
-
- for (BluetoothDevice bluetoothDevice : disconnected) {
- disconnectBluetoothDevice(bluetoothDevice);
- }
- for (BluetoothDevice bluetoothDevice : connected) {
- connectBluetoothDevice(bluetoothDevice);
- }
-
- final HIDDeviceManager finalThis = this;
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- finalThis.chromebookConnectionHandler();
- }
- }, 10000);
- }
-
- public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
- Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
- synchronized (this) {
- if (mBluetoothDevices.containsKey(bluetoothDevice)) {
- Log.v(TAG, "Steam controller with address " + bluetoothDevice + " already exists, attempting reconnect");
-
- HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
- device.reconnect();
-
- return false;
- }
- HIDDeviceBLESteamController device = new HIDDeviceBLESteamController(this, bluetoothDevice);
- int id = device.getId();
- mBluetoothDevices.put(bluetoothDevice, device);
- mDevicesById.put(id, device);
-
- // The Steam Controller will mark itself connected once initialization is complete
- }
- return true;
- }
-
- public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
- synchronized (this) {
- HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
- if (device == null)
- return;
-
- int id = device.getId();
- mBluetoothDevices.remove(bluetoothDevice);
- mDevicesById.remove(id);
- device.shutdown();
- HIDDeviceDisconnected(id);
- }
- }
-
- public boolean isSteamController(BluetoothDevice bluetoothDevice) {
- // Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
- if (bluetoothDevice == null) {
- return false;
- }
-
- // If the device has no local name, we really don't want to try an equality check against it.
- if (bluetoothDevice.getName() == null) {
- return false;
- }
-
- return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
- }
-
- private void close() {
- shutdownUSB();
- shutdownBluetooth();
- synchronized (this) {
- for (HIDDevice device : mDevicesById.values()) {
- device.shutdown();
- }
- mDevicesById.clear();
- mBluetoothDevices.clear();
- HIDDeviceReleaseCallback();
- }
- }
-
- public void setFrozen(boolean frozen) {
- synchronized (this) {
- for (HIDDevice device : mDevicesById.values()) {
- device.setFrozen(frozen);
- }
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- private HIDDevice getDevice(int id) {
- synchronized (this) {
- HIDDevice result = mDevicesById.get(id);
- if (result == null) {
- Log.v(TAG, "No device for id: " + id);
- Log.v(TAG, "Available devices: " + mDevicesById.keySet());
- }
- return result;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////// JNI interface functions
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public boolean initialize(boolean usb, boolean bluetooth) {
- Log.v(TAG, "initialize(" + usb + ", " + bluetooth + ")");
-
- if (usb) {
- initializeUSB();
- }
- if (bluetooth) {
- initializeBluetooth();
- }
- return true;
- }
-
- public boolean openDevice(int deviceID) {
- Log.v(TAG, "openDevice deviceID=" + deviceID);
- HIDDevice device = getDevice(deviceID);
- if (device == null) {
- HIDDeviceDisconnected(deviceID);
- return false;
- }
-
- // Look to see if this is a USB device and we have permission to access it
- UsbDevice usbDevice = device.getDevice();
- if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
- HIDDeviceOpenPending(deviceID);
- try {
- final int FLAG_MUTABLE = 0x02000000; // PendingIntent.FLAG_MUTABLE, but don't require SDK 31
- int flags;
- if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
- flags = FLAG_MUTABLE;
- } else {
- flags = 0;
- }
- if (Build.VERSION.SDK_INT >= 33 /* Android 14.0 (U) */) {
- Intent intent = new Intent(HIDDeviceManager.ACTION_USB_PERMISSION);
- intent.setPackage(mContext.getPackageName());
- mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, intent, flags));
- } else {
- mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
- }
- } catch (Exception e) {
- Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
- HIDDeviceOpenResult(deviceID, false);
- }
- return false;
- }
-
- try {
- return device.open();
- } catch (Exception e) {
- Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
- }
- return false;
- }
-
- public int writeReport(int deviceID, byte[] report, boolean feature) {
- try {
- //Log.v(TAG, "writeReport deviceID=" + deviceID + " length=" + report.length);
- HIDDevice device;
- device = getDevice(deviceID);
- if (device == null) {
- HIDDeviceDisconnected(deviceID);
- return -1;
- }
-
- return device.writeReport(report, feature);
- } catch (Exception e) {
- Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
- }
- return -1;
- }
-
- public boolean readReport(int deviceID, byte[] report, boolean feature) {
- try {
- //Log.v(TAG, "readReport deviceID=" + deviceID);
- HIDDevice device;
- device = getDevice(deviceID);
- if (device == null) {
- HIDDeviceDisconnected(deviceID);
- return false;
- }
-
- return device.readReport(report, feature);
- } catch (Exception e) {
- Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
- }
- return false;
- }
-
- public void closeDevice(int deviceID) {
- try {
- Log.v(TAG, "closeDevice deviceID=" + deviceID);
- HIDDevice device;
- device = getDevice(deviceID);
- if (device == null) {
- HIDDeviceDisconnected(deviceID);
- return;
- }
-
- device.close();
- } catch (Exception e) {
- Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
- }
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////// Native methods
- //////////////////////////////////////////////////////////////////////////////////////////////////////
-
- private native void HIDDeviceRegisterCallback();
- private native void HIDDeviceReleaseCallback();
-
- native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth);
- native void HIDDeviceOpenPending(int deviceID);
- native void HIDDeviceOpenResult(int deviceID, boolean opened);
- native void HIDDeviceDisconnected(int deviceID);
-
- native void HIDDeviceInputReport(int deviceID, byte[] report);
- native void HIDDeviceReportResponse(int deviceID, byte[] report);
-}
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
deleted file mode 100644
index 2741438..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
+++ /dev/null
@@ -1,318 +0,0 @@
-package org.libsdl.app;
-
-import android.hardware.usb.*;
-import android.os.Build;
-import android.util.Log;
-import java.util.Arrays;
-
-class HIDDeviceUSB implements HIDDevice {
-
- private static final String TAG = "hidapi";
-
- protected HIDDeviceManager mManager;
- protected UsbDevice mDevice;
- protected int mInterfaceIndex;
- protected int mInterface;
- protected int mDeviceId;
- protected UsbDeviceConnection mConnection;
- protected UsbEndpoint mInputEndpoint;
- protected UsbEndpoint mOutputEndpoint;
- protected InputThread mInputThread;
- protected boolean mRunning;
- protected boolean mFrozen;
-
- public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
- mManager = manager;
- mDevice = usbDevice;
- mInterfaceIndex = interface_index;
- mInterface = mDevice.getInterface(mInterfaceIndex).getId();
- mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
- mRunning = false;
- }
-
- public String getIdentifier() {
- return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
- }
-
- @Override
- public int getId() {
- return mDeviceId;
- }
-
- @Override
- public int getVendorId() {
- return mDevice.getVendorId();
- }
-
- @Override
- public int getProductId() {
- return mDevice.getProductId();
- }
-
- @Override
- public String getSerialNumber() {
- String result = null;
- if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
- try {
- result = mDevice.getSerialNumber();
- }
- catch (SecurityException exception) {
- //Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
- }
- }
- if (result == null) {
- result = "";
- }
- return result;
- }
-
- @Override
- public int getVersion() {
- return 0;
- }
-
- @Override
- public String getManufacturerName() {
- String result = null;
- if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
- result = mDevice.getManufacturerName();
- }
- if (result == null) {
- result = String.format("%x", getVendorId());
- }
- return result;
- }
-
- @Override
- public String getProductName() {
- String result = null;
- if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
- result = mDevice.getProductName();
- }
- if (result == null) {
- result = String.format("%x", getProductId());
- }
- return result;
- }
-
- @Override
- public UsbDevice getDevice() {
- return mDevice;
- }
-
- public String getDeviceName() {
- return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
- }
-
- @Override
- public boolean open() {
- mConnection = mManager.getUSBManager().openDevice(mDevice);
- if (mConnection == null) {
- Log.w(TAG, "Unable to open USB device " + getDeviceName());
- return false;
- }
-
- // Force claim our interface
- UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
- if (!mConnection.claimInterface(iface, true)) {
- Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
- close();
- return false;
- }
-
- // Find the endpoints
- for (int j = 0; j < iface.getEndpointCount(); j++) {
- UsbEndpoint endpt = iface.getEndpoint(j);
- switch (endpt.getDirection()) {
- case UsbConstants.USB_DIR_IN:
- if (mInputEndpoint == null) {
- mInputEndpoint = endpt;
- }
- break;
- case UsbConstants.USB_DIR_OUT:
- if (mOutputEndpoint == null) {
- mOutputEndpoint = endpt;
- }
- break;
- }
- }
-
- // Make sure the required endpoints were present
- if (mInputEndpoint == null || mOutputEndpoint == null) {
- Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
- close();
- return false;
- }
-
- // Start listening for input
- mRunning = true;
- mInputThread = new InputThread();
- mInputThread.start();
-
- return true;
- }
-
- @Override
- public int writeReport(byte[] report, boolean feature) {
- if (mConnection == null) {
- Log.w(TAG, "writeReport() called with no device connection");
- return -1;
- }
-
- if (feature) {
- int res = -1;
- int offset = 0;
- int length = report.length;
- boolean skipped_report_id = false;
- byte report_number = report[0];
-
- if (report_number == 0x0) {
- ++offset;
- --length;
- skipped_report_id = true;
- }
-
- res = mConnection.controlTransfer(
- UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
- 0x09/*HID set_report*/,
- (3/*HID feature*/ << 8) | report_number,
- mInterface,
- report, offset, length,
- 1000/*timeout millis*/);
-
- if (res < 0) {
- Log.w(TAG, "writeFeatureReport() returned " + res + " on device " + getDeviceName());
- return -1;
- }
-
- if (skipped_report_id) {
- ++length;
- }
- return length;
- } else {
- int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
- if (res != report.length) {
- Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName());
- }
- return res;
- }
- }
-
- @Override
- public boolean readReport(byte[] report, boolean feature) {
- int res = -1;
- int offset = 0;
- int length = report.length;
- boolean skipped_report_id = false;
- byte report_number = report[0];
-
- if (mConnection == null) {
- Log.w(TAG, "readReport() called with no device connection");
- return false;
- }
-
- if (report_number == 0x0) {
- /* Offset the return buffer by 1, so that the report ID
- will remain in byte 0. */
- ++offset;
- --length;
- skipped_report_id = true;
- }
-
- res = mConnection.controlTransfer(
- UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
- 0x01/*HID get_report*/,
- ((feature ? 3/*HID feature*/ : 1/*HID Input*/) << 8) | report_number,
- mInterface,
- report, offset, length,
- 1000/*timeout millis*/);
-
- if (res < 0) {
- Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
- return false;
- }
-
- if (skipped_report_id) {
- ++res;
- ++length;
- }
-
- byte[] data;
- if (res == length) {
- data = report;
- } else {
- data = Arrays.copyOfRange(report, 0, res);
- }
- mManager.HIDDeviceReportResponse(mDeviceId, data);
-
- return true;
- }
-
- @Override
- public void close() {
- mRunning = false;
- if (mInputThread != null) {
- while (mInputThread.isAlive()) {
- mInputThread.interrupt();
- try {
- mInputThread.join();
- } catch (InterruptedException e) {
- // Keep trying until we're done
- }
- }
- mInputThread = null;
- }
- if (mConnection != null) {
- UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
- mConnection.releaseInterface(iface);
- mConnection.close();
- mConnection = null;
- }
- }
-
- @Override
- public void shutdown() {
- close();
- mManager = null;
- }
-
- @Override
- public void setFrozen(boolean frozen) {
- mFrozen = frozen;
- }
-
- protected class InputThread extends Thread {
- @Override
- public void run() {
- int packetSize = mInputEndpoint.getMaxPacketSize();
- byte[] packet = new byte[packetSize];
- while (mRunning) {
- int r;
- try
- {
- r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
- }
- catch (Exception e)
- {
- Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
- break;
- }
- if (r < 0) {
- // Could be a timeout or an I/O error
- }
- if (r > 0) {
- byte[] data;
- if (r == packetSize) {
- data = packet;
- } else {
- data = Arrays.copyOfRange(packet, 0, r);
- }
-
- if (!mFrozen) {
- mManager.HIDDeviceInputReport(mDeviceId, data);
- }
- }
- }
- }
- }
-}
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDL.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDL.java
deleted file mode 100644
index b132fea..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDL.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.libsdl.app;
-
-import android.content.Context;
-
-import java.lang.Class;
-import java.lang.reflect.Method;
-
-/**
- SDL library initialization
-*/
-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() {
- SDLActivity.nativeSetupJNI();
- SDLAudioManager.nativeSetupJNI();
- SDLControllerManager.nativeSetupJNI();
- }
-
- // This function should be called each time the activity is started
- public static void initialize() {
- setContext(null);
-
- SDLActivity.initialize();
- SDLAudioManager.initialize();
- SDLControllerManager.initialize();
- }
-
- // This function stores the current activity (SDL or not)
- public static void setContext(Context context) {
- SDLAudioManager.setContext(context);
- mContext = context;
- }
-
- public static Context getContext() {
- return mContext;
- }
-
- public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
- loadLibrary(libraryName, mContext);
- }
-
- public static void loadLibrary(String libraryName, Context context) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
-
- if (libraryName == null) {
- throw new NullPointerException("No library name provided.");
- }
-
- try {
- // Let's see if we have ReLinker available in the project. This is necessary for
- // some projects that have huge numbers of local libraries bundled, and thus may
- // trip a bug in Android's native library loader which ReLinker works around. (If
- // loadLibrary works properly, ReLinker will simply use the normal Android method
- // internally.)
- //
- // To use ReLinker, just add it as a dependency. For more information, see
- // https://github.com/KeepSafe/ReLinker for ReLinker's repository.
- //
- Class> relinkClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
- Class> relinkListenerClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
- Class> contextClass = context.getClassLoader().loadClass("android.content.Context");
- Class> stringClass = context.getClassLoader().loadClass("java.lang.String");
-
- // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if
- // they've changed during updates.
- Method forceMethod = relinkClass.getDeclaredMethod("force");
- Object relinkInstance = forceMethod.invoke(null);
- Class> relinkInstanceClass = relinkInstance.getClass();
-
- // Actually load the library!
- Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
- loadMethod.invoke(relinkInstance, context, libraryName, null, null);
- }
- catch (final Throwable e) {
- // Fall back
- try {
- System.loadLibrary(libraryName);
- }
- catch (final UnsatisfiedLinkError ule) {
- throw ule;
- }
- catch (final SecurityException se) {
- throw se;
- }
- }
- }
-
- protected static Context mContext;
-}
diff --git a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
deleted file mode 100644
index 31aa9b6..0000000
--- a/contrib/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ /dev/null
@@ -1,2189 +0,0 @@
-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;
-
-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 = 2;
- private static final int SDL_MICRO_VERSION = 8;
-/*
- // 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 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 boolean mDispatchingKeyEvent = false;
-
- 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 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 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();
- 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);
-
-
- /* 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) {
- }
-
- 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;
- }
-
- SDLActivity.handleNativeState();
- }
-
- // Events
- @Override
- protected void onPause() {
- Log.v(TAG, "onPause()");
- super.onPause();
-
- if (mHIDDeviceManager != null) {
- mHIDDeviceManager.setFrozen(true);
- }
- if (!mHasMultiWindow) {
- pauseNativeThread();
- }
- }
-
- @Override
- protected void onResume() {
- Log.v(TAG, "onResume()");
- super.onResume();
-
- if (mHIDDeviceManager != null) {
- mHIDDeviceManager.setFrozen(false);
- }
- if (!mHasMultiWindow) {
- resumeNativeThread();
- }
- }
-
- @Override
- 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 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);
- 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);
-
- if (SDLActivity.mBrokenLibraries) {
- return;
- }
-
- SDLActivity.nativeLowMemory();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- Log.v(TAG, "onConfigurationChanged()");
- super.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();
- }
-
- @Override
- public void 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.onBackPressed();
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (mFileDialogState != null && mFileDialogState.requestCode == requestCode) {
- /* This is our file dialog */
- String[] filelist = null;
-
- if (data != null) {
- Uri singleFileUri = data.getData();
-
- if (singleFileUri == null) {
- /* Use Intent.getClipData to get multiple choices */
- ClipData clipData = data.getClipData();
- assert clipData != null;
-
- filelist = new String[clipData.getItemCount()];
-
- for (int i = 0; i < filelist.length; i++) {
- String uri = clipData.getItemAt(i).getUri().toString();
- filelist[i] = uri;
- }
- } else {
- /* Only one file is selected. */
- filelist = new String[]{singleFileUri.toString()};
- }
- } else {
- /* User cancelled the request. */
- filelist = new String[0];
- }
-
- // TODO: Detect the file MIME type and pass the filter value accordingly.
- SDLActivity.onNativeFileDialog(requestCode, filelist, -1);
- mFileDialogState = null;
- }
- }
-
- // Called by JNI from SDL.
- public static void manualBackButton() {
- mSingleton.pressBackButton();
- }
-
- // Used to get us onto the activity's main thread
- public void pressBackButton() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (!SDLActivity.this.isFinishing()) {
- SDLActivity.this.superOnBackPressed();
- }
- }
- });
- }
-
- // Used to access the system back behavior.
- public void superOnBackPressed() {
- super.onBackPressed();
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
-
- if (SDLActivity.mBrokenLibraries) {
- return false;
- }
-
- int keyCode = event.getKeyCode();
- // Ignore certain special keys so they're handled by Android
- if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
- keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
- keyCode == KeyEvent.KEYCODE_CAMERA ||
- keyCode == KeyEvent.KEYCODE_ZOOM_IN || /* API 11 */
- keyCode == KeyEvent.KEYCODE_ZOOM_OUT /* API 11 */
- ) {
- return false;
- }
- mDispatchingKeyEvent = true;
- boolean result = super.dispatchKeyEvent(event);
- mDispatchingKeyEvent = false;
- return result;
- }
-
- public static boolean dispatchingKeyEvent() {
- return mDispatchingKeyEvent;
- }
-
- /* 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 || mHasMultiWindow) && 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
- } else {
- nativeResume();
- }
- mSurface.handleResume();
-
- mCurrentNativeState = mNextNativeState;
- }
- }
- }
-
- // Messages from the SDLMain thread
- protected static final int COMMAND_CHANGE_TITLE = 1;
- protected static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
- protected static final int COMMAND_TEXTEDIT_HIDE = 3;
- protected static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
- 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.
- * Method can be overwritten to handle Messages in a different class.
- * @param command the command of the message.
- * @param param the parameter of the message. May be null.
- * @return if the message was handled in overridden method.
- */
- protected boolean onUnhandledMessage(int command, Object param) {
- 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 /* Android 4.4 (KITKAT) */) {
- if (context instanceof Activity) {
- Window window = ((Activity) context).getWindow();
- if (window != null) {
- if ((msg.obj instanceof Integer) && ((Integer) msg.obj != 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;
- }
- if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
- window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- }
- if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */ &&
- Build.VERSION.SDK_INT < 35 /* Android 15 */) {
- SDLActivity.onNativeInsetsChanged(0, 0, 0, 0);
- }
- }
- } 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 != 0)) {
- window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
- }
- }
- 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
- protected 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 /* Android 4.4 (KITKAT) */) {
- if (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();
- DisplayMetrics realMetrics = new DisplayMetrics();
- display.getRealMetrics(realMetrics);
-
- boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
- (realMetrics.heightPixels == mSurface.getHeight()));
-
- if ((Integer) data == 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 String nativeGetVersion();
- public static native int nativeSetupJNI();
- public static native void nativeInitMainThread();
- public static native void nativeCleanupMainThread();
- 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 onNativeDropFile(String filename);
- public static native void nativeSetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate);
- public static native void onNativeResize();
- 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,
- int action, float x,
- float y, float p);
- public static native void onNativePen(int penId, int button, 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 String nativeGetHint(String name);
- public static native boolean nativeGetHintBoolean(String name, boolean default_value);
- public static native void nativeSetenv(String name, String value);
- public static native void nativeSetNaturalOrientation(int orientation);
- public static native void onNativeRotationChanged(int rotation);
- public static native void onNativeInsetsChanged(int left, int right, int top, int bottom);
- public static native void nativeAddTouch(int touchId, String name);
- public static native void nativePermissionResult(int requestCode, boolean result);
- public static native void onNativeLocaleChanged();
- public static native void onNativeDarkModeChanged(boolean enabled);
- public static native boolean nativeAllowRecreateActivity();
- public static native int nativeCheckSDLThreadCounter();
- public static native void onNativeFileDialog(int requestCode, String[] filelist, int filter);
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * This method is called by SDL using JNI.
- * This is a static method for JNI convenience, it calls a non-static method
- * so that is can be overridden
- */
- public static void setOrientation(int w, int h, boolean resizable, String hint)
- {
- if (mSingleton != null) {
- mSingleton.setOrientationBis(w, h, resizable, hint);
- }
- }
-
- /**
- * This can be overridden
- */
- public void setOrientationBis(int w, int h, boolean resizable, String hint)
- {
- int orientation_landscape = -1;
- int orientation_portrait = -1;
-
- /* If set, hint "explicitly controls which UI orientations are allowed". */
- if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
- orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
- } else if (hint.contains("LandscapeLeft")) {
- orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- } else if (hint.contains("LandscapeRight")) {
- orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- }
-
- /* exact match to 'Portrait' to distinguish with PortraitUpsideDown */
- boolean contains_Portrait = hint.contains("Portrait ") || hint.endsWith("Portrait");
-
- if (contains_Portrait && hint.contains("PortraitUpsideDown")) {
- orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
- } else if (contains_Portrait) {
- orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- } else if (hint.contains("PortraitUpsideDown")) {
- orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- }
-
- boolean is_landscape_allowed = (orientation_landscape != -1);
- boolean is_portrait_allowed = (orientation_portrait != -1);
- int req; /* Requested orientation */
-
- /* No valid hint, nothing is explicitly allowed */
- if (!is_portrait_allowed && !is_landscape_allowed) {
- if (resizable) {
- /* All orientations are allowed, respecting user orientation lock setting */
- req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
- } else {
- /* Fixed window and nothing specified. Get orientation from w/h of created window */
- req = (w > h ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
- }
- } else {
- /* At least one orientation is allowed */
- if (resizable) {
- if (is_portrait_allowed && is_landscape_allowed) {
- /* hint allows both landscape and portrait, promote to full user */
- req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
- } else {
- /* Use the only one allowed "orientation" */
- req = (is_landscape_allowed ? orientation_landscape : orientation_portrait);
- }
- } else {
- /* Fixed window and both orientations are allowed. Choose one. */
- if (is_portrait_allowed && is_landscape_allowed) {
- req = (w > h ? orientation_landscape : orientation_portrait);
- } else {
- /* Use the only one allowed "orientation" */
- req = (is_landscape_allowed ? orientation_landscape : orientation_portrait);
- }
- }
- }
-
- Log.v(TAG, "setOrientation() requestedOrientation=" + req + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
- mSingleton.setRequestedOrientation(req);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void minimizeWindow() {
-
- if (mSingleton == null) {
- return;
- }
-
- Intent startMain = new Intent(Intent.ACTION_MAIN);
- startMain.addCategory(Intent.CATEGORY_HOME);
- startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mSingleton.startActivity(startMain);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean shouldMinimizeOnFocusLoss() {
- return false;
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean isScreenKeyboardShown()
- {
- if (mTextEdit == null) {
- return false;
- }
-
- if (!mScreenKeyboardShown) {
- return false;
- }
-
- InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- return imm.isAcceptingText();
-
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean supportsRelativeMouse()
- {
- // DeX mode in Samsung Experience 9.0 and earlier doesn't support relative mice properly under
- // Android 7 APIs, and simply returns no data under Android 8 APIs.
- //
- // This is fixed in Samsung Experience 9.5, which corresponds to Android 8.1.0, and
- // thus SDK version 27. If we are in DeX mode and not API 27 or higher, as a result,
- // we should stick to relative mode.
- //
- if (Build.VERSION.SDK_INT < 27 /* Android 8.1 (O_MR1) */ && isDeXMode()) {
- return false;
- }
-
- return SDLActivity.getMotionListener().supportsRelativeMouse();
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean setRelativeMouseEnabled(boolean enabled)
- {
- if (enabled && !supportsRelativeMouse()) {
- return false;
- }
-
- return SDLActivity.getMotionListener().setRelativeMouseEnabled(enabled);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean sendMessage(int command, int param) {
- if (mSingleton == null) {
- return false;
- }
- return mSingleton.sendCommand(command, param);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static Context getContext() {
- return SDL.getContext();
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean isAndroidTV() {
- UiModeManager uiModeManager = (UiModeManager) getContext().getSystemService(UI_MODE_SERVICE);
- if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
- return true;
- }
- if (Build.MANUFACTURER.equals("MINIX") && Build.MODEL.equals("NEO-U1")) {
- return true;
- }
- if (Build.MANUFACTURER.equals("Amlogic") && Build.MODEL.equals("X96-W")) {
- return true;
- }
- if (Build.MANUFACTURER.equals("Amlogic") && Build.MODEL.startsWith("TV")) {
- return true;
- }
- return false;
- }
-
- public static boolean isVRHeadset() {
- if (Build.MANUFACTURER.equals("Oculus") && Build.MODEL.startsWith("Quest")) {
- return true;
- }
- if (Build.MANUFACTURER.equals("Pico")) {
- return true;
- }
- return false;
- }
-
- public static double getDiagonal()
- {
- DisplayMetrics metrics = new DisplayMetrics();
- Activity activity = (Activity)getContext();
- if (activity == null) {
- return 0.0;
- }
- activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
- double dWidthInches = metrics.widthPixels / (double)metrics.xdpi;
- double dHeightInches = metrics.heightPixels / (double)metrics.ydpi;
-
- return Math.sqrt((dWidthInches * dWidthInches) + (dHeightInches * dHeightInches));
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean isTablet() {
- // If our diagonal size is seven inches or greater, we consider ourselves a tablet.
- return (getDiagonal() >= 7.0);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean isChromebook() {
- if (getContext() == null) {
- return false;
- }
- return getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean isDeXMode() {
- if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
- return false;
- }
- try {
- final Configuration config = getContext().getResources().getConfiguration();
- final Class> configClass = config.getClass();
- return configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass)
- == configClass.getField("semDesktopModeEnabled").getInt(config);
- } catch(Exception ignored) {
- return false;
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean getManifestEnvironmentVariables() {
- try {
- if (getContext() == null) {
- return false;
- }
-
- ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
- Bundle bundle = applicationInfo.metaData;
- if (bundle == null) {
- return false;
- }
- String prefix = "SDL_ENV.";
- final int trimLength = prefix.length();
- for (String key : bundle.keySet()) {
- if (key.startsWith(prefix)) {
- String name = key.substring(trimLength);
- String value = bundle.get(key).toString();
- nativeSetenv(name, value);
- }
- }
- /* environment variables set! */
- return true;
- } catch (Exception e) {
- Log.v(TAG, "exception " + e.toString());
- }
- return false;
- }
-
- // This method is called by SDLControllerManager's API 26 Generic Motion Handler.
- public static View getContentView() {
- return mLayout;
- }
-
- static class ShowTextInputTask implements Runnable {
- /*
- * This is used to regulate the pan&scan method to have some offset from
- * the bottom edge of the input region and the top edge of an input
- * method (soft keyboard)
- */
- static final int HEIGHT_PADDING = 15;
-
- public int input_type;
- public int x, y, w, h;
-
- public ShowTextInputTask(int input_type, int x, int y, int w, int h) {
- this.input_type = input_type;
- this.x = x;
- this.y = y;
- this.w = w;
- this.h = h;
-
- /* Minimum size of 1 pixel, so it takes focus. */
- if (this.w <= 0) {
- this.w = 1;
- }
- if (this.h + HEIGHT_PADDING <= 0) {
- this.h = 1 - HEIGHT_PADDING;
- }
- }
-
- @Override
- public void run() {
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
- params.leftMargin = x;
- params.topMargin = y;
-
- if (mTextEdit == null) {
- mTextEdit = new SDLDummyEdit(SDL.getContext());
-
- mLayout.addView(mTextEdit, params);
- } else {
- mTextEdit.setLayoutParams(params);
- }
- mTextEdit.setInputType(input_type);
-
- mTextEdit.setVisibility(View.VISIBLE);
- mTextEdit.requestFocus();
-
- InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mTextEdit, 0);
-
- mScreenKeyboardShown = true;
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static boolean showTextInput(int input_type, int x, int y, int w, int h) {
- // Transfer the task to the main thread as a Runnable
- return mSingleton.commandHandler.post(new ShowTextInputTask(input_type, x, y, w, h));
- }
-
- public static boolean isTextInputEvent(KeyEvent event) {
-
- // Key pressed with Ctrl should be sent as SDL_KEYDOWN/SDL_KEYUP and not SDL_TEXTINPUT
- if (event.isCtrlPressed()) {
- return false;
- }
-
- return event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
- }
-
- public static boolean handleKeyEvent(View v, int keyCode, KeyEvent event, InputConnection ic) {
- int deviceId = event.getDeviceId();
- int source = event.getSource();
-
- if (source == InputDevice.SOURCE_UNKNOWN) {
- InputDevice device = InputDevice.getDevice(deviceId);
- if (device != null) {
- source = device.getSources();
- }
- }
-
-// if (event.getAction() == KeyEvent.ACTION_DOWN) {
-// Log.v("SDL", "key down: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
-// } else if (event.getAction() == KeyEvent.ACTION_UP) {
-// Log.v("SDL", "key up: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
-// }
-
- // Dispatch the different events depending on where they come from
- // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
- // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
- //
- // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
- // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
- // So, retrieve the device itself and check all of its sources
- if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
- // Note that we process events with specific key codes here
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- if (SDLControllerManager.onNativePadDown(deviceId, keyCode)) {
- return true;
- }
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- if (SDLControllerManager.onNativePadUp(deviceId, keyCode)) {
- return true;
- }
- }
- }
-
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
- if (SDLActivity.isVRHeadset()) {
- // The Oculus Quest controller back button comes in as source mouse, so accept that
- } else {
- // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
- // they are ignored here because sending them as mouse input to SDL is messy
- if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
- switch (event.getAction()) {
- case KeyEvent.ACTION_DOWN:
- case KeyEvent.ACTION_UP:
- // mark the event as handled or it will be handled by system
- // handling KEYCODE_BACK by system will call onBackPressed()
- return true;
- }
- }
- }
- }
-
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- onNativeKeyDown(keyCode);
-
- if (isTextInputEvent(event)) {
- if (ic != null) {
- ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
- } else {
- SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
- }
- }
- return true;
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- onNativeKeyUp(keyCode);
- return true;
- }
-
- return false;
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static Surface getNativeSurface() {
- if (SDLActivity.mSurface == null) {
- return null;
- }
- return SDLActivity.mSurface.getNativeSurface();
- }
-
- // Input
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void initTouch() {
- int[] ids = InputDevice.getDeviceIds();
-
- for (int id : ids) {
- InputDevice device = InputDevice.getDevice(id);
- /* Allow SOURCE_TOUCHSCREEN and also Virtual InputDevices because they can send TOUCHSCREEN events */
- if (device != null && ((device.getSources() & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN
- || device.isVirtual())) {
-
- nativeAddTouch(device.getId(), device.getName());
- }
- }
- }
-
- // Messagebox
-
- /** Result of current messagebox. Also used for blocking the calling thread. */
- protected final int[] messageboxSelection = new int[1];
-
- /**
- * This method is called by SDL using JNI.
- * Shows the messagebox from UI thread and block calling thread.
- * buttonFlags, buttonIds and buttonTexts must have same length.
- * @param buttonFlags array containing flags for every button.
- * @param buttonIds array containing id for every button.
- * @param buttonTexts array containing text for every button.
- * @param colors null for default or array of length 5 containing colors.
- * @return button id or -1.
- */
- public int messageboxShowMessageBox(
- final int flags,
- final String title,
- final String message,
- final int[] buttonFlags,
- final int[] buttonIds,
- final String[] buttonTexts,
- final int[] colors) {
-
- messageboxSelection[0] = -1;
-
- // sanity checks
-
- if ((buttonFlags.length != buttonIds.length) && (buttonIds.length != buttonTexts.length)) {
- return -1; // implementation broken
- }
-
- // collect arguments for Dialog
-
- final Bundle args = new Bundle();
- args.putInt("flags", flags);
- args.putString("title", title);
- args.putString("message", message);
- args.putIntArray("buttonFlags", buttonFlags);
- args.putIntArray("buttonIds", buttonIds);
- args.putStringArray("buttonTexts", buttonTexts);
- args.putIntArray("colors", colors);
-
- // trigger Dialog creation on UI thread
-
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- messageboxCreateAndShow(args);
- }
- });
-
- // block the calling thread
-
- synchronized (messageboxSelection) {
- try {
- messageboxSelection.wait();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- return -1;
- }
- }
-
- // return selected value
-
- return messageboxSelection[0];
- }
-
- protected void messageboxCreateAndShow(Bundle args) {
-
- // TODO set values from "flags" to messagebox dialog
-
- // get colors
-
- int[] colors = args.getIntArray("colors");
- int backgroundColor;
- int textColor;
- int buttonBorderColor;
- int buttonBackgroundColor;
- int buttonSelectedColor;
- if (colors != null) {
- int i = -1;
- backgroundColor = colors[++i];
- textColor = colors[++i];
- buttonBorderColor = colors[++i];
- buttonBackgroundColor = colors[++i];
- buttonSelectedColor = colors[++i];
- } else {
- backgroundColor = Color.TRANSPARENT;
- textColor = Color.TRANSPARENT;
- buttonBorderColor = Color.TRANSPARENT;
- buttonBackgroundColor = Color.TRANSPARENT;
- buttonSelectedColor = Color.TRANSPARENT;
- }
-
- // create dialog with title and a listener to wake up calling thread
-
- final AlertDialog dialog = new AlertDialog.Builder(this).create();
- dialog.setTitle(args.getString("title"));
- dialog.setCancelable(false);
- dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface unused) {
- synchronized (messageboxSelection) {
- messageboxSelection.notify();
- }
- }
- });
-
- // create text
-
- TextView message = new TextView(this);
- message.setGravity(Gravity.CENTER);
- message.setText(args.getString("message"));
- if (textColor != Color.TRANSPARENT) {
- message.setTextColor(textColor);
- }
-
- // create buttons
-
- int[] buttonFlags = args.getIntArray("buttonFlags");
- int[] buttonIds = args.getIntArray("buttonIds");
- String[] buttonTexts = args.getStringArray("buttonTexts");
-
- final SparseArray