mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-19 23:14:23 +00:00
Fix crashes and ANRs in controller LED handling
This commit is contained in:
@@ -786,6 +786,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Light.hasRgbControl() was totally broken prior to Android 14.
|
||||
// It always returned true because LIGHT_CAPABILITY_RGB was defined as 0,
|
||||
// so we will just guess RGB is supported if it's a PlayStation controller.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE && context.vendorId != 0x054c) {
|
||||
context.hasRgbLed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect if the gamepad has Mode and Select buttons according to the Android key layouts.
|
||||
@@ -2305,25 +2312,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
|
||||
// Ignore input devices without an RGB LED
|
||||
if (deviceContext.controllerNumber == controllerNumber && deviceContext.hasRgbLed) {
|
||||
// Create a new light session if one doesn't already exist
|
||||
if (deviceContext.lightsSession == null) {
|
||||
deviceContext.lightsSession = deviceContext.inputDevice.getLightsManager().openSession();
|
||||
}
|
||||
|
||||
// Convert the RGB components into the integer value that LightState uses
|
||||
int argbValue = 0xFF000000 | ((r << 16) & 0xFF0000) | ((g << 8) & 0xFF00) | (b & 0xFF);
|
||||
LightState lightState = new LightState.Builder().setColor(argbValue).build();
|
||||
deviceContext.ledArgbValue = 0xFF000000 | ((r << 16) & 0xFF0000) | ((g << 8) & 0xFF00) | (b & 0xFF);
|
||||
|
||||
// Set the RGB value for each RGB-controllable LED on the device
|
||||
LightsRequest.Builder lightsRequestBuilder = new LightsRequest.Builder();
|
||||
for (Light light : deviceContext.inputDevice.getLightsManager().getLights()) {
|
||||
if (light.hasRgbControl()) {
|
||||
lightsRequestBuilder.addLight(light, lightState);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the LED changes
|
||||
deviceContext.lightsSession.requestLights(lightsRequestBuilder.build());
|
||||
backgroundThreadHandler.removeCallbacks(deviceContext.setLedStateRunnable);
|
||||
backgroundThreadHandler.post(deviceContext.setLedStateRunnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2958,6 +2951,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
|
||||
public boolean hasRgbLed;
|
||||
public LightsManager.LightsSession lightsSession;
|
||||
public int ledArgbValue;
|
||||
|
||||
// These are BatteryState values, not Moonlight values
|
||||
public int lastReportedBatteryStatus;
|
||||
@@ -3034,6 +3028,34 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
}
|
||||
};
|
||||
|
||||
public final Runnable setLedStateRunnable = new Runnable() {
|
||||
@TargetApi(Build.VERSION_CODES.S)
|
||||
@Override
|
||||
public void run() {
|
||||
LightState lightState = new LightState.Builder().setColor(ledArgbValue).build();
|
||||
|
||||
// Set the RGB value for each RGB-controllable LED on the device
|
||||
boolean hasRgbLight = false;
|
||||
LightsRequest.Builder lightsRequestBuilder = new LightsRequest.Builder();
|
||||
for (Light light : inputDevice.getLightsManager().getLights()) {
|
||||
if (light.hasRgbControl()) {
|
||||
lightsRequestBuilder.addLight(light, lightState);
|
||||
hasRgbLight = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRgbLight) {
|
||||
// Create a new light session if one doesn't already exist
|
||||
if (lightsSession == null) {
|
||||
lightsSession = inputDevice.getLightsManager().openSession();
|
||||
}
|
||||
|
||||
// Apply the LED changes
|
||||
lightsSession.requestLights(lightsRequestBuilder.build());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
@@ -3046,6 +3068,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
}
|
||||
|
||||
backgroundThreadHandler.removeCallbacks(enableSensorRunnable);
|
||||
backgroundThreadHandler.removeCallbacks(setLedStateRunnable);
|
||||
|
||||
if (gyroListener != null) {
|
||||
sensorManager.unregisterListener(gyroListener);
|
||||
@@ -3056,7 +3079,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (lightsSession != null) {
|
||||
lightsSession.close();
|
||||
try {
|
||||
lightsSession.close();
|
||||
} catch (RuntimeException e) {
|
||||
LimeLog.warning("Error closing LightsSession: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3128,10 +3155,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
capabilities |= MoonBridge.LI_CCAP_BATTERY_STATE;
|
||||
}
|
||||
|
||||
// Light.hasRgbControl() was totally broken prior to Android 14.
|
||||
// It always returned true because LIGHT_CAPABILITY_RGB was defined as 0,
|
||||
// so we will just guess RGB is supported if it's a PlayStation controller.
|
||||
if (hasRgbLed && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE || type == MoonBridge.LI_CTYPE_PS)) {
|
||||
if (hasRgbLed) {
|
||||
capabilities |= MoonBridge.LI_CCAP_RGB_LED;
|
||||
}
|
||||
}
|
||||
@@ -3195,6 +3219,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
this.lightsSession = oldContext.lightsSession;
|
||||
oldContext.lightsSession = null;
|
||||
}
|
||||
this.ledArgbValue = oldContext.ledArgbValue;
|
||||
this.gyroReportRateHz = oldContext.gyroReportRateHz;
|
||||
this.accelReportRateHz = oldContext.accelReportRateHz;
|
||||
|
||||
@@ -3219,6 +3244,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
// Re-enable sensors on the new context
|
||||
enableSensors();
|
||||
|
||||
// Refresh the LED state if it's set. We don't know if there was a pending LED state
|
||||
// callback when the context was migrated, so we'll reset it just to be safe.
|
||||
if (this.lightsSession != null) {
|
||||
backgroundThreadHandler.post(setLedStateRunnable);
|
||||
}
|
||||
|
||||
// Refresh battery state and start the battery state polling again
|
||||
backgroundThreadHandler.post(batteryStateUpdateRunnable);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user