Adapt "turn screen off" for Android 15

Android 15 introduced an easy way to set the display power:
<fd8b5efc7f%5E!/#F17>

Refs #3927 <https://github.com/Genymobile/scrcpy/issues/3927>
Refs <https://issuetracker.google.com/issues/303565669>
PR #5418 <https://github.com/Genymobile/scrcpy/pull/5418>
This commit is contained in:
Romain Vimont 2024-10-29 00:45:26 +01:00
parent 569c37cec1
commit 58ba00fa06
4 changed files with 34 additions and 7 deletions

View File

@ -143,7 +143,7 @@ public final class CleanUp {
Device.powerOffScreen(displayId);
} else if (restoreDisplayPower) {
Ln.i("Restoring display power");
Device.setDisplayPower(true);
Device.setDisplayPower(displayId, true);
}
}

View File

@ -273,7 +273,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
case ControlMessage.TYPE_SET_DISPLAY_POWER:
if (supportsInputEvents && displayId != Device.DISPLAY_ID_NONE) {
boolean on = msg.getOn();
boolean setDisplayPowerOk = Device.setDisplayPower(on);
boolean setDisplayPowerOk = Device.setDisplayPower(displayId, on);
if (setDisplayPowerOk) {
keepDisplayPowerOff = !on;
Ln.i("Device display turned " + (on ? "on" : "off"));
@ -312,7 +312,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
private boolean injectKeycode(int action, int keycode, int repeat, int metaState) {
if (keepDisplayPowerOff && action == KeyEvent.ACTION_UP && (keycode == KeyEvent.KEYCODE_POWER || keycode == KeyEvent.KEYCODE_WAKEUP)) {
assert displayId != Device.DISPLAY_ID_NONE;
scheduleDisplayPowerOff();
scheduleDisplayPowerOff(displayId);
}
return injectKeyEvent(action, keycode, repeat, metaState, Device.INJECT_MODE_ASYNC);
}
@ -491,10 +491,10 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
/**
* Schedule a call to set display power to off after a small delay.
*/
private static void scheduleDisplayPowerOff() {
private static void scheduleDisplayPowerOff(int displayId) {
EXECUTOR.schedule(() -> {
Ln.i("Forcing display off");
Device.setDisplayPower(false);
Device.setDisplayPower(displayId, false);
}, 200, TimeUnit.MILLISECONDS);
}
@ -512,7 +512,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
if (keepDisplayPowerOff) {
assert displayId != Device.DISPLAY_ID_NONE;
scheduleDisplayPowerOff();
scheduleDisplayPowerOff(displayId);
}
return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC);
}

View File

@ -126,7 +126,13 @@ public final class Device {
return clipboardManager.setText(text);
}
public static boolean setDisplayPower(boolean on) {
public static boolean setDisplayPower(int displayId, boolean on) {
assert displayId != Device.DISPLAY_ID_NONE;
if (Build.VERSION.SDK_INT >= AndroidVersions.API_35_ANDROID_15) {
return ServiceManager.getDisplayManager().requestDisplayPower(displayId, on);
}
boolean applyToMultiPhysicalDisplays = Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10;
if (applyToMultiPhysicalDisplays

View File

@ -1,5 +1,6 @@
package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.AndroidVersions;
import com.genymobile.scrcpy.FakeContext;
import com.genymobile.scrcpy.device.DisplayInfo;
import com.genymobile.scrcpy.device.Size;
@ -7,6 +8,7 @@ import com.genymobile.scrcpy.util.Command;
import com.genymobile.scrcpy.util.Ln;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.display.VirtualDisplay;
import android.view.Display;
@ -22,6 +24,7 @@ import java.util.regex.Pattern;
public final class DisplayManager {
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
private Method createVirtualDisplayMethod;
private Method requestDisplayPowerMethod;
static DisplayManager create() {
try {
@ -137,4 +140,22 @@ public final class DisplayManager {
android.hardware.display.DisplayManager dm = ctor.newInstance(FakeContext.get());
return dm.createVirtualDisplay(name, width, height, dpi, surface, flags);
}
private Method getRequestDisplayPowerMethod() throws NoSuchMethodException {
if (requestDisplayPowerMethod == null) {
requestDisplayPowerMethod = manager.getClass().getMethod("requestDisplayPower", int.class, boolean.class);
}
return requestDisplayPowerMethod;
}
@TargetApi(AndroidVersions.API_35_ANDROID_15)
public boolean requestDisplayPower(int displayId, boolean on) {
try {
Method method = getRequestDisplayPowerMethod();
return (boolean) method.invoke(manager, displayId, on);
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
return false;
}
}
}