diff --git a/server/src/main/aidl/android/view/IDisplayFoldListener.aidl b/server/src/main/aidl/android/view/IDisplayFoldListener.aidl new file mode 100644 index 00000000..2c91149d --- /dev/null +++ b/server/src/main/aidl/android/view/IDisplayFoldListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** + * {@hide} + */ +oneway interface IDisplayFoldListener +{ + /** Called when the foldedness of a display changes */ + void onDisplayFoldChanged(int displayId, boolean folded); +} diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index 3d83f73e..a3b6a270 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -12,6 +12,7 @@ import android.os.Build; import android.os.IBinder; import android.os.SystemClock; import android.view.IRotationWatcher; +import android.view.IDisplayFoldListener; import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyCharacterMap; @@ -35,6 +36,10 @@ public final class Device { void onRotationChanged(int rotation); } + public interface FoldListener { + void onFoldChanged(int displayId, boolean folded); + } + public interface ClipboardListener { void onClipboardTextChanged(String text); } @@ -46,6 +51,7 @@ public final class Device { private ScreenInfo screenInfo; private RotationListener rotationListener; + private FoldListener foldListener; private ClipboardListener clipboardListener; private final AtomicBoolean isSettingClipboard = new AtomicBoolean(); @@ -93,6 +99,26 @@ public final class Device { } }, displayId); + ServiceManager.getWindowManager().registerDisplayFoldListener(new IDisplayFoldListener.Stub() { + @Override + public void onDisplayFoldChanged(int displayId, boolean folded) { + synchronized (Device.this) { + DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId); + if (displayInfo == null) { + Ln.e("Display " + displayId + " not found\n" + LogUtils.buildDisplayListMessage()); + return; + } + + screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), displayInfo.getSize(), options.getCrop(), + options.getMaxSize(), options.getLockVideoOrientation()); + // notify + if (foldListener != null) { + foldListener.onFoldChanged(displayId, folded); + } + } + } + }); + if (options.getControl() && options.getClipboardAutosync()) { // If control and autosync are enabled, synchronize Android clipboard to the computer automatically ClipboardManager clipboardManager = ServiceManager.getClipboardManager(); @@ -224,6 +250,10 @@ public final class Device { this.rotationListener = rotationListener; } + public synchronized void setFoldListener(FoldListener foldlistener) { + this.foldListener = foldlistener; + } + public synchronized void setClipboardListener(ClipboardListener clipboardListener) { this.clipboardListener = clipboardListener; } diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index d45ca853..d56e5d27 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -16,7 +16,7 @@ import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -public class ScreenEncoder implements Device.RotationListener, AsyncProcessor { +public class ScreenEncoder implements Device.RotationListener, Device.FoldListener, AsyncProcessor { private static final int DEFAULT_I_FRAME_INTERVAL = 10; // seconds private static final int REPEAT_FRAME_DELAY_US = 100_000; // repeat after 100ms @@ -53,6 +53,11 @@ public class ScreenEncoder implements Device.RotationListener, AsyncProcessor { this.downsizeOnError = downsizeOnError; } + @Override + public void onFoldChanged(int displayId, boolean folded) { + resetCapture.set(true); + } + @Override public void onRotationChanged(int rotation) { resetCapture.set(true); @@ -68,6 +73,7 @@ public class ScreenEncoder implements Device.RotationListener, AsyncProcessor { MediaFormat format = createFormat(codec.getMimeType(), videoBitRate, maxFps, codecOptions); IBinder display = createDisplay(); device.setRotationListener(this); + device.setFoldListener(this); streamer.writeVideoHeader(device.getScreenInfo().getVideoSize()); @@ -115,6 +121,7 @@ public class ScreenEncoder implements Device.RotationListener, AsyncProcessor { } finally { mediaCodec.release(); device.setRotationListener(null); + device.setFoldListener(null); SurfaceControl.destroyDisplay(display); } } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java index faa366a5..d9fd9825 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java @@ -4,6 +4,7 @@ import com.genymobile.scrcpy.Ln; import android.os.IInterface; import android.view.IRotationWatcher; +import android.view.IDisplayFoldListener; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -108,4 +109,13 @@ public final class WindowManager { throw new AssertionError(e); } } + + public void registerDisplayFoldListener(IDisplayFoldListener foldListener) { + try { + Class cls = manager.getClass(); + cls.getMethod("registerDisplayFoldListener", IDisplayFoldListener.class).invoke(manager, foldListener); + } catch (Exception e) { + throw new AssertionError(e); + } + } }