Get gravity of menu panel by display
Also:
- Reorganize import of DisplayContent and PhoneWindow.
- Fix DisplayContent leakage in wm test.
(SurfaceFlinger abort in createLayer -> addClientLayer with
"Suspected IGBP leak: 4097 IGBPs (4096 max)")
Bug: b/111362047
Test: atest FrameworksServicesTests:DisplayContentTests# \
testGetPreferredOptionsPanelGravityFromDifferentDisplays
Change-Id: I9c5a0f59a86fda08bd532cb2b66bab76b2dfa6c8
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 092702c..0398b8f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -223,10 +223,12 @@
/**
* Determine the preferred edge of the screen to pin the compact options menu against.
- * @return a Gravity value for the options menu panel
+ *
+ * @param displayId Id of the display where the menu window currently resides.
+ * @return a Gravity value for the options menu panel.
* @hide
*/
- int getPreferredOptionsPanelGravity();
+ int getPreferredOptionsPanelGravity(int displayId);
/**
* Lock the device orientation to the specified rotation, or to the
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ac7dc8e2..8751517 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -19,15 +19,54 @@
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.*;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.SearchManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
-import android.os.UserHandle;
-
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
import android.text.TextUtils;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.AndroidRuntimeException;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.IRotationWatcher.Stub;
@@ -52,6 +91,13 @@
import android.view.ViewRootImpl.ActivityConfigCallback;
import android.view.Window;
import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
import com.android.internal.R;
import com.android.internal.view.menu.ContextMenuBuilder;
import com.android.internal.view.menu.IconMenuPresenter;
@@ -64,43 +110,6 @@
import com.android.internal.widget.DecorContentParent;
import com.android.internal.widget.SwipeDismissLayout;
-import android.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.transition.Scene;
-import android.transition.Transition;
-import android.transition.TransitionInflater;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.util.AndroidRuntimeException;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -1377,7 +1386,8 @@
*/
private int getOptionsPanelGravity() {
try {
- return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
+ return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity(
+ getContext().getDisplay().getDisplayId());
} catch (RemoteException ex) {
Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
return Gravity.CENTER | Gravity.BOTTOM;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 65ee18a..49638a9 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -59,12 +58,25 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
+import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
+import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
+import static com.android.server.wm.DisplayContentProto.DPI;
+import static com.android.server.wm.DisplayContentProto.ID;
+import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER;
+import static com.android.server.wm.DisplayContentProto.ROTATION;
+import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
+import static com.android.server.wm.DisplayContentProto.STACKS;
+import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -101,19 +113,7 @@
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
-import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
-import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
-import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
-import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
-import static com.android.server.wm.DisplayContentProto.DPI;
-import static com.android.server.wm.DisplayContentProto.ID;
-import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
-import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER;
-import static com.android.server.wm.DisplayContentProto.ROTATION;
-import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
-import static com.android.server.wm.DisplayContentProto.STACKS;
-import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -140,6 +140,7 @@
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.Gravity;
import android.view.InputDevice;
import android.view.MagnificationSpec;
import android.view.Surface;
@@ -1616,6 +1617,54 @@
}
}
+ /**
+ * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
+ * theme attribute) on devices that feature a physical options menu key attempt to position
+ * their menu panel window along the edge of the screen nearest the physical menu key.
+ * This lowers the travel distance between invoking the menu panel and selecting
+ * a menu option.
+ *
+ * This method helps control where that menu is placed. Its current implementation makes
+ * assumptions about the menu key and its relationship to the screen based on whether
+ * the device's natural orientation is portrait (width < height) or landscape.
+ *
+ * The menu key is assumed to be located along the bottom edge of natural-portrait
+ * devices and along the right edge of natural-landscape devices. If these assumptions
+ * do not hold for the target device, this method should be changed to reflect that.
+ *
+ * @return A {@link Gravity} value for placing the options menu window.
+ */
+ int getPreferredOptionsPanelGravity() {
+ final int rotation = getRotation();
+ if (mInitialDisplayWidth < mInitialDisplayHeight) {
+ // On devices with a natural orientation of portrait.
+ switch (rotation) {
+ default:
+ case Surface.ROTATION_0:
+ return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ case Surface.ROTATION_90:
+ return Gravity.RIGHT | Gravity.BOTTOM;
+ case Surface.ROTATION_180:
+ return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ case Surface.ROTATION_270:
+ return Gravity.START | Gravity.BOTTOM;
+ }
+ }
+
+ // On devices with a natural orientation of landscape.
+ switch (rotation) {
+ default:
+ case Surface.ROTATION_0:
+ return Gravity.RIGHT | Gravity.BOTTOM;
+ case Surface.ROTATION_90:
+ return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ case Surface.ROTATION_180:
+ return Gravity.START | Gravity.BOTTOM;
+ case Surface.ROTATION_270:
+ return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ }
+ }
+
DockedStackDividerController getDockedDividerController() {
return mDividerControllerLocked;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7520bfa..42d6c8e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -226,7 +226,6 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.R;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -269,7 +268,6 @@
import java.util.Arrays;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -3954,56 +3952,14 @@
}
}
- /**
- * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
- * theme attribute) on devices that feature a physical options menu key attempt to position
- * their menu panel window along the edge of the screen nearest the physical menu key.
- * This lowers the travel distance between invoking the menu panel and selecting
- * a menu option.
- *
- * This method helps control where that menu is placed. Its current implementation makes
- * assumptions about the menu key and its relationship to the screen based on whether
- * the device's natural orientation is portrait (width < height) or landscape.
- *
- * The menu key is assumed to be located along the bottom edge of natural-portrait
- * devices and along the right edge of natural-landscape devices. If these assumptions
- * do not hold for the target device, this method should be changed to reflect that.
- *
- * @return A {@link Gravity} value for placing the options menu window
- */
@Override
- public int getPreferredOptionsPanelGravity() {
+ public int getPreferredOptionsPanelGravity(int displayId) {
synchronized (mWindowMap) {
- // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final int rotation = displayContent.getRotation();
- if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
- // On devices with a natural orientation of portrait
- switch (rotation) {
- default:
- case Surface.ROTATION_0:
- return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- case Surface.ROTATION_90:
- return Gravity.RIGHT | Gravity.BOTTOM;
- case Surface.ROTATION_180:
- return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- case Surface.ROTATION_270:
- return Gravity.START | Gravity.BOTTOM;
- }
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ return Gravity.CENTER | Gravity.BOTTOM;
}
-
- // On devices with a natural orientation of landscape
- switch (rotation) {
- default:
- case Surface.ROTATION_0:
- return Gravity.RIGHT | Gravity.BOTTOM;
- case Surface.ROTATION_90:
- return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- case Surface.ROTATION_180:
- return Gravity.START | Gravity.BOTTOM;
- case Surface.ROTATION_270:
- return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- }
+ return displayContent.getPreferredOptionsPanelGravity();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index cfef51c..0d40c5e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -51,6 +51,7 @@
import android.util.DisplayMetrics;
import android.util.SparseIntArray;
import android.view.DisplayCutout;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
@@ -575,6 +576,31 @@
.setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
}
+ @Test
+ public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
+ final DisplayContent portraitDisplay = createNewDisplay();
+ portraitDisplay.mInitialDisplayHeight = 2000;
+ portraitDisplay.mInitialDisplayWidth = 1000;
+
+ portraitDisplay.setRotation(Surface.ROTATION_0);
+ assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
+ portraitDisplay.setRotation(Surface.ROTATION_90);
+ assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
+
+ final DisplayContent landscapeDisplay = createNewDisplay();
+ landscapeDisplay.mInitialDisplayHeight = 1000;
+ landscapeDisplay.mInitialDisplayWidth = 2000;
+
+ landscapeDisplay.setRotation(Surface.ROTATION_0);
+ assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
+ landscapeDisplay.setRotation(Surface.ROTATION_90);
+ assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
+ }
+
+ private boolean isOptionsPanelAtRight(int displayId) {
+ return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
+ }
+
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
int expectedBaseHeight, int expectedBaseDensity) {
assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index d128363..5db0867 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -158,7 +158,11 @@
// If @After throws an exception, the error isn't logged. This will make sure any failures
// in the tear down are clear. This can be removed when b/37850063 is fixed.
try {
- final LinkedList<WindowState> nonCommonWindows = new LinkedList();
+ // Test may schedule to perform surface placement or other messages. Wait until a
+ // stable state to clean up for consistency.
+ waitUntilHandlersIdle();
+
+ final LinkedList<WindowState> nonCommonWindows = new LinkedList<>();
synchronized (sWm.mWindowMap) {
sWm.mRoot.forAllWindows(w -> {
@@ -171,7 +175,12 @@
nonCommonWindows.pollLast().removeImmediately();
}
- mDisplayContent.removeImmediately();
+ for (int i = sWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent displayContent = sWm.mRoot.mChildren.get(i);
+ if (!displayContent.isDefaultDisplay) {
+ displayContent.removeImmediately();
+ }
+ }
sWm.mInputMethodTarget = null;
sWm.mClosingApps.clear();
sWm.mOpeningApps.clear();