Restart capture when screen resolution changes
This commit is contained in:
parent
762ed2755a
commit
391f2de3fa
@ -2,6 +2,7 @@ package com.genymobile.scrcpy;
|
|||||||
|
|
||||||
import com.genymobile.scrcpy.wrappers.ClipboardManager;
|
import com.genymobile.scrcpy.wrappers.ClipboardManager;
|
||||||
import com.genymobile.scrcpy.wrappers.DisplayControl;
|
import com.genymobile.scrcpy.wrappers.DisplayControl;
|
||||||
|
import com.genymobile.scrcpy.wrappers.DisplayManager;
|
||||||
import com.genymobile.scrcpy.wrappers.InputManager;
|
import com.genymobile.scrcpy.wrappers.InputManager;
|
||||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
||||||
@ -10,6 +11,8 @@ import com.genymobile.scrcpy.wrappers.WindowManager;
|
|||||||
import android.content.IOnPrimaryClipChangedListener;
|
import android.content.IOnPrimaryClipChangedListener;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.IDisplayFoldListener;
|
import android.view.IDisplayFoldListener;
|
||||||
@ -33,6 +36,10 @@ public final class Device {
|
|||||||
public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1;
|
public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1;
|
||||||
public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2;
|
public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2;
|
||||||
|
|
||||||
|
public interface DisplayChangeListener {
|
||||||
|
void onDisplayChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public interface RotationListener {
|
public interface RotationListener {
|
||||||
void onRotationChanged(int rotation);
|
void onRotationChanged(int rotation);
|
||||||
}
|
}
|
||||||
@ -51,6 +58,7 @@ public final class Device {
|
|||||||
|
|
||||||
private Size deviceSize;
|
private Size deviceSize;
|
||||||
private ScreenInfo screenInfo;
|
private ScreenInfo screenInfo;
|
||||||
|
private DisplayChangeListener displayChangeListener;
|
||||||
private RotationListener rotationListener;
|
private RotationListener rotationListener;
|
||||||
private FoldListener foldListener;
|
private FoldListener foldListener;
|
||||||
private ClipboardListener clipboardListener;
|
private ClipboardListener clipboardListener;
|
||||||
@ -86,6 +94,27 @@ public final class Device {
|
|||||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
||||||
layerStack = displayInfo.getLayerStack();
|
layerStack = displayInfo.getLayerStack();
|
||||||
|
|
||||||
|
HandlerThread displayListenerThread = new HandlerThread("DisplayListenerThread");
|
||||||
|
displayListenerThread.start();
|
||||||
|
|
||||||
|
Handler displayListenerHandler = new Handler(displayListenerThread.getLooper());
|
||||||
|
ServiceManager.getDisplayManager().registerDisplayListener(new DisplayManager.DisplayListener() {
|
||||||
|
@Override
|
||||||
|
public void onDisplayChanged(int displayId) {
|
||||||
|
if (Device.this.displayId != displayId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
|
||||||
|
deviceSize = displayInfo.getSize();
|
||||||
|
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
||||||
|
|
||||||
|
if (displayChangeListener != null) {
|
||||||
|
displayChangeListener.onDisplayChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, displayListenerHandler);
|
||||||
|
|
||||||
ServiceManager.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() {
|
ServiceManager.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onRotationChanged(int rotation) {
|
public void onRotationChanged(int rotation) {
|
||||||
@ -253,6 +282,10 @@ public final class Device {
|
|||||||
return ServiceManager.getPowerManager().isScreenOn();
|
return ServiceManager.getPowerManager().isScreenOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void setDisplayChangeListener(DisplayChangeListener displayChangeListener) {
|
||||||
|
this.displayChangeListener = displayChangeListener;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void setRotationListener(RotationListener rotationListener) {
|
public synchronized void setRotationListener(RotationListener rotationListener) {
|
||||||
this.rotationListener = rotationListener;
|
this.rotationListener = rotationListener;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import android.os.Build;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
public class ScreenCapture extends SurfaceCapture implements Device.RotationListener, Device.FoldListener {
|
public class ScreenCapture extends SurfaceCapture implements Device.DisplayChangeListener, Device.RotationListener, Device.FoldListener {
|
||||||
|
|
||||||
private final Device device;
|
private final Device device;
|
||||||
private IBinder display;
|
private IBinder display;
|
||||||
@ -18,6 +18,7 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
device.setDisplayChangeListener(this);
|
||||||
device.setRotationListener(this);
|
device.setRotationListener(this);
|
||||||
device.setFoldListener(this);
|
device.setFoldListener(this);
|
||||||
}
|
}
|
||||||
@ -41,6 +42,7 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
|
device.setDisplayChangeListener(null);
|
||||||
device.setRotationListener(null);
|
device.setRotationListener(null);
|
||||||
device.setFoldListener(null);
|
device.setFoldListener(null);
|
||||||
if (display != null) {
|
if (display != null) {
|
||||||
@ -69,6 +71,11 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
|
|||||||
requestReset();
|
requestReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisplayChanged() {
|
||||||
|
requestReset();
|
||||||
|
}
|
||||||
|
|
||||||
private static IBinder createDisplay() {
|
private static IBinder createDisplay() {
|
||||||
// Since Android 12 (preview), secure displays could not be created with shell permissions anymore.
|
// Since Android 12 (preview), secure displays could not be created with shell permissions anymore.
|
||||||
// On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S".
|
// On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S".
|
||||||
|
@ -5,13 +5,20 @@ import com.genymobile.scrcpy.DisplayInfo;
|
|||||||
import com.genymobile.scrcpy.Ln;
|
import com.genymobile.scrcpy.Ln;
|
||||||
import com.genymobile.scrcpy.Size;
|
import com.genymobile.scrcpy.Size;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public final class DisplayManager {
|
public final class DisplayManager {
|
||||||
|
|
||||||
|
// Constant copied from AOSP framework_base: core/java/android/hardware/display/DisplayManager.java
|
||||||
|
private static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
|
||||||
|
|
||||||
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
||||||
|
|
||||||
public DisplayManager(Object manager) {
|
public DisplayManager(Object manager) {
|
||||||
@ -94,4 +101,47 @@ public final class DisplayManager {
|
|||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerDisplayListener(DisplayListener listener, Handler handler) {
|
||||||
|
try {
|
||||||
|
Class<?> displayListenerClass = Class.forName("android.hardware.display.DisplayManager$DisplayListener");
|
||||||
|
Object displayListenerProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
|
||||||
|
new Class[]{displayListenerClass},
|
||||||
|
(proxy, method, args) -> {
|
||||||
|
if ("onDisplayChanged".equals(method.getName())) {
|
||||||
|
listener.onDisplayChanged((int) args[0]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
try {
|
||||||
|
manager.getClass()
|
||||||
|
.getMethod("registerDisplayListener", displayListenerClass, Handler.class, long.class)
|
||||||
|
.invoke(manager, displayListenerProxy, handler, EVENT_FLAG_DISPLAY_CHANGED);
|
||||||
|
return;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// fall-through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.getClass()
|
||||||
|
.getMethod("registerDisplayListener", displayListenerClass, Handler.class)
|
||||||
|
.invoke(manager, displayListenerProxy, handler);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Screen size won't be updated, not a fatal error
|
||||||
|
Ln.e("Could not register display listener", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partially copied from AOSP framework_base: core/java/android/hardware/display/DisplayManager.java
|
||||||
|
public interface DisplayListener {
|
||||||
|
/**
|
||||||
|
* Called whenever the properties of a logical {@link android.view.Display},
|
||||||
|
* such as size and density, have changed.
|
||||||
|
*
|
||||||
|
* @param displayId The id of the logical display that changed.
|
||||||
|
*/
|
||||||
|
void onDisplayChanged(int displayId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user