Foldables: Add IDisplayFoldListener
Include ag/5663399 to unregister display fold listener.
Bug: 123245311
Test: atest WmTests
Change-Id: I60776fddd4a671b7443cd33220271fed84503b27
diff --git a/Android.bp b/Android.bp
index 9584767..eafb605 100644
--- a/Android.bp
+++ b/Android.bp
@@ -376,6 +376,7 @@
"core/java/android/view/IApplicationToken.aidl",
"core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
"core/java/android/view/IDockedStackListener.aidl",
+ "core/java/android/view/IDisplayFoldListener.aidl",
"core/java/android/view/IGraphicsStats.aidl",
"core/java/android/view/IGraphicsStatsCallback.aidl",
"core/java/android/view/IInputFilter.aidl",
diff --git a/core/java/android/view/IDisplayFoldListener.aidl b/core/java/android/view/IDisplayFoldListener.aidl
new file mode 100644
index 0000000..2c91149
--- /dev/null
+++ b/core/java/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/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 42ac880..8ae4757 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -34,6 +34,7 @@
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayFoldListener;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
@@ -403,6 +404,16 @@
Region getCurrentImeTouchRegion();
/**
+ * Registers an IDisplayFoldListener.
+ */
+ void registerDisplayFoldListener(IDisplayFoldListener listener);
+
+ /**
+ * Unregisters an IDisplayFoldListener.
+ */
+ void unregisterDisplayFoldListener(IDisplayFoldListener listener);
+
+ /**
* Starts a window trace.
*/
void startWindowTrace();
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 71d6dfc..fdcafa7 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -23,8 +23,13 @@
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManagerInternal;
+import android.os.Handler;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
import android.view.DisplayInfo;
+import android.view.IDisplayFoldListener;
+import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerInternal;
@@ -40,16 +45,24 @@
/** The display area while device is folded. */
private final Rect mFoldedArea;
+ private final Handler mHandler;
private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo();
+ private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>();
private Boolean mFolded;
DisplayFoldController(WindowManagerInternal windowManagerInternal,
- DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea) {
+ DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea,
+ Handler handler) {
mWindowManagerInternal = windowManagerInternal;
mDisplayManagerInternal = displayManagerInternal;
mDisplayId = displayId;
mFoldedArea = new Rect(foldedArea);
+ mHandler = handler;
+ }
+
+ void requestDeviceFolded(boolean folded) {
+ mHandler.post(() -> setDeviceFolded(folded));
}
void setDeviceFolded(boolean folded) {
@@ -71,6 +84,34 @@
mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0);
}
mFolded = folded;
+
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mListeners.getBroadcastItem(i).onDisplayFoldChanged(mDisplayId, folded);
+ } catch (RemoteException e) {
+ // Listener died.
+ }
+ }
+ mListeners.finishBroadcast();
+ }
+
+ void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ mListeners.register(listener);
+ if (mFolded == null) {
+ return;
+ }
+ mHandler.post(() -> {
+ try {
+ listener.onDisplayFoldChanged(mDisplayId, mFolded);
+ } catch (RemoteException e) {
+ // Listener died.
+ }
+ });
+ }
+
+ void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ mListeners.unregister(listener);
}
/**
@@ -88,7 +129,7 @@
sensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
- result.setDeviceFolded(event.values[0] < 1f);
+ result.requestDeviceFolded(event.values[0] < 1f);
}
@Override
@@ -109,6 +150,6 @@
displayInfo.logicalWidth, displayInfo.logicalHeight);
return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class),
- displayService, displayId, foldedArea);
+ displayService, displayId, foldedArea, DisplayThread.getHandler());
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 25cfc72..0796a9c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -177,6 +177,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.HapticFeedbackConstants;
+import android.view.IDisplayFoldListener;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -3205,6 +3206,20 @@
}
@Override
+ public void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.registerDisplayFoldListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.unregisterDisplayFoldListener(listener);
+ }
+ }
+
+ @Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
throws RemoteException {
synchronized (mLock) {
@@ -4984,7 +4999,7 @@
private void applyLidSwitchState() {
final int lidState = mDefaultDisplayPolicy.getLidState();
if (mLidControlsDisplayFold && mDisplayFoldController != null) {
- mDisplayFoldController.setDeviceFolded(lidState == LID_CLOSED);
+ mDisplayFoldController.requestDeviceFolded(lidState == LID_CLOSED);
} else if (lidState == LID_CLOSED && mLidControlsSleep) {
goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 1d82970..e18cd17 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -78,6 +78,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.IApplicationToken;
+import android.view.IDisplayFoldListener;
import android.view.IWindowManager;
import android.view.InputEventReceiver;
import android.view.KeyEvent;
@@ -1457,6 +1458,16 @@
public void requestUserActivityNotification();
/**
+ * Registers an IDisplayFoldListener.
+ */
+ default void registerDisplayFoldListener(IDisplayFoldListener listener) {}
+
+ /**
+ * Unregisters an IDisplayFoldListener.
+ */
+ default void unregisterDisplayFoldListener(IDisplayFoldListener listener) {}
+
+ /**
* Updates the flag about whether AOD is showing.
*
* @return whether the value was changed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 12b858c..8373b44 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -192,6 +192,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.IDisplayFoldListener;
import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
@@ -3748,6 +3749,16 @@
}
@Override
+ public void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ mPolicy.registerDisplayFoldListener(listener);
+ }
+
+ @Override
+ public void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ mPolicy.unregisterDisplayFoldListener(listener);
+ }
+
+ @Override
public int getPreferredOptionsPanelGravity(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);