From 8009c1d4462bdca5a37c8b11825e4a154c4e88c5 Mon Sep 17 00:00:00 2001 From: Luca Zuccarini Date: Tue, 24 May 2022 16:17:19 +0000 Subject: [PATCH 1/6] Add support for text color animations in PropertySetter. Bug: 233223446 Test: manual Change-Id: Id321ad7f21e804b1d1063fbe207fb783bb45f759 --- .../android/launcher3/LauncherAnimUtils.java | 27 +++++++++++++++++++ .../anim/AnimatedPropertySetter.java | 12 +++++++++ .../launcher3/anim/PropertySetter.java | 10 +++++++ 3 files changed, 49 insertions(+) diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java index 808bf96f9f..0c7c3110c4 100644 --- a/src/com/android/launcher3/LauncherAnimUtils.java +++ b/src/com/android/launcher3/LauncherAnimUtils.java @@ -26,6 +26,7 @@ import android.util.FloatProperty; import android.util.IntProperty; import android.view.View; import android.view.ViewGroup.LayoutParams; +import android.widget.TextView; import com.android.launcher3.util.MultiScalePropertyFactory; @@ -115,6 +116,32 @@ public class LauncherAnimUtils { } }; + public static final IntProperty TEXT_COLOR = + new IntProperty("textColor") { + @Override + public Integer get(TextView view) { + return view.getTextColors().getDefaultColor(); + } + + @Override + public void setValue(TextView view, int color) { + view.setTextColor(color); + } + }; + + public static final IntProperty HINT_TEXT_COLOR = + new IntProperty("hintTextColor") { + @Override + public Integer get(TextView view) { + return view.getHintTextColors().getDefaultColor(); + } + + @Override + public void setValue(TextView view, int color) { + view.setHintTextColor(color); + } + }; + public static final FloatProperty VIEW_TRANSLATE_X = View.TRANSLATION_X instanceof FloatProperty ? (FloatProperty) View.TRANSLATION_X : new FloatProperty("translateX") { diff --git a/src/com/android/launcher3/anim/AnimatedPropertySetter.java b/src/com/android/launcher3/anim/AnimatedPropertySetter.java index e5f5e7c44b..373eb7e9a8 100644 --- a/src/com/android/launcher3/anim/AnimatedPropertySetter.java +++ b/src/com/android/launcher3/anim/AnimatedPropertySetter.java @@ -89,6 +89,18 @@ public class AnimatedPropertySetter extends PropertySetter { return anim; } + @NonNull + @Override + public Animator setColor(T target, IntProperty property, int value, + TimeInterpolator interpolator) { + if (property.get(target) == value) { + return NO_OP; + } + Animator anim = ObjectAnimator.ofArgb(target, property, value); + anim.setInterpolator(interpolator); + add(anim); + return anim; + } /** * Adds a callback to be run on every frame of the animation diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java index d2207f6351..b0ed2d2277 100644 --- a/src/com/android/launcher3/anim/PropertySetter.java +++ b/src/com/android/launcher3/anim/PropertySetter.java @@ -88,6 +88,16 @@ public abstract class PropertySetter { return NO_OP; } + /** + * Updates a color property of the target using the provided interpolator + */ + @NonNull + public Animator setColor(T target, IntProperty property, int value, + TimeInterpolator interpolator) { + property.setValue(target, value); + return NO_OP; + } + /** * Runs the animation as part of setting the property */ From c04af333f52aa50be3920f8a8bc3df2709341b45 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Wed, 8 Jun 2022 04:43:21 +0000 Subject: [PATCH 2/6] Prevent wallpaper flicker while entering split screen from overview When launching a pair of apps from overview panel, it will perform cross-fade animations to transit from overview to the split pair. But wallpaper might be visible for a while when both overveiw and split pair is transparent during the transition. This updates to not fade-out overview until the split pair is finishing showing in foregorund to prevent the flicker of wallpaper. Bug: 235137249 Test: swipe to home and enter overview panel, select and swipe down to enter a split pair, verified there's no flicker. Change-Id: Iec1dc49e260f6e46640d47295d7f65dad5c24ab5 --- quickstep/src/com/android/quickstep/TaskViewUtils.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 6179b81b7c..db402aff85 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -514,9 +514,6 @@ public final class TaskViewUtils { for (SurfaceControl leash: openingTargets) { t.setAlpha(leash, progress); } - for (SurfaceControl leash: closingTargets) { - t.setAlpha(leash, 1 - progress); - } t.apply(); }); animator.addListener(new AnimatorListenerAdapter() { From 9a54d2aa43b4ab8dd27d3e1d9b0a068689d3e4bb Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 4 Apr 2022 14:58:30 -0700 Subject: [PATCH 3/6] Hide taskbar while VoiceInteractionWindow is visible - Fade out icons (or stashed handle if stashed) - Move background to APPLICATION_OVERLAY layer (behind VIW) - Only for gesture nav - On home screen in 3 button mode, translate buttons down when assistant is invoked Test: Invoke assistant, ensure it draws above taskbar background and taskbar stops drawing icons or stashed handle Bug: 225200928 Change-Id: I7807d30df8f358295b8231d89217c7413f32c6f9 Merged-In: I7807d30df8f358295b8231d89217c7413f32c6f9 --- .../taskbar/NavbarButtonsViewController.java | 16 ++- .../taskbar/StashedHandleViewController.java | 3 +- .../taskbar/TaskbarActivityContext.java | 22 +++- .../launcher3/taskbar/TaskbarControllers.java | 10 +- .../taskbar/TaskbarViewController.java | 3 +- .../VoiceInteractionWindowController.kt | 109 ++++++++++++++++++ 6 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 5d576f7bf5..01cf23bffd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -35,6 +35,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING; import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION; import android.animation.ArgbEvaluator; @@ -105,6 +106,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private static final int FLAG_DISABLE_BACK = 1 << 9; private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10; private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 11; + private static final int FLAG_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 12; private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE; @@ -207,9 +209,12 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT boolean isInKidsMode = mContext.isNavBarKidsModeActive(); boolean alwaysShowButtons = isThreeButtonNav || isInSetup; - // Make sure to remove nav bar buttons translation when notification shade is expanded or - // IME is showing (add separate translation for IME). - int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE; + // Make sure to remove nav bar buttons translation when any of the following occur: + // - Notification shade is expanded + // - IME is showing (add separate translation for IME) + // - VoiceInteractionWindow (assistant) is showing + int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE + | FLAG_VOICE_INTERACTION_WINDOW_SHOWING; mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui, flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE, 1, 0)); @@ -443,6 +448,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0; boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; + boolean isVoiceInteractionWindowShowing = + (sysUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0; // TODO(b/202218289) we're getting IME as not visible on lockscreen from system updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible); @@ -453,6 +460,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled); updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded); updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive); + updateStateForFlag(FLAG_VOICE_INTERACTION_WINDOW_SHOWING, isVoiceInteractionWindowShowing); if (mA11yButton != null) { // Only used in 3 button @@ -750,6 +758,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT appendFlag(str, flags, FLAG_NOTIFICATION_SHADE_EXPANDED, "FLAG_NOTIFICATION_SHADE_EXPANDED"); appendFlag(str, flags, FLAG_SCREEN_PINNING_ACTIVE, "FLAG_SCREEN_PINNING_ACTIVE"); + appendFlag(str, flags, FLAG_VOICE_INTERACTION_WINDOW_SHOWING, + "FLAG_VOICE_INTERACTION_WINDOW_SHOWING"); return str.toString(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index b7978076c1..f472427520 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -43,7 +43,8 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT public static final int ALPHA_INDEX_STASHED = 0; public static final int ALPHA_INDEX_HOME_DISABLED = 1; - private static final int NUM_ALPHA_CHANNELS = 2; + public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2; + private static final int NUM_ALPHA_CHANNELS = 3; /** * The SharedPreferences key for whether the stashed handle region is dark. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 95da118948..61fad50499 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -27,6 +27,7 @@ import static com.android.launcher3.ResourceUtils.getBoolByName; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING; import android.animation.AnimatorSet; import android.animation.ValueAnimator; @@ -200,7 +201,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new TaskbarPopupController(this), new TaskbarForceVisibleImmersiveController(this), new TaskbarAllAppsController(this, dp), - new TaskbarInsetsController(this)); + new TaskbarInsetsController(this), + new VoiceInteractionWindowController(this)); } public void init(@NonNull TaskbarSharedState sharedState) { @@ -246,12 +248,20 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return super.getStatsLogManager(); } - /** Creates LayoutParams for adding a view directly to WindowManager as a new window */ + /** @see #createDefaultWindowLayoutParams(int) */ public WindowManager.LayoutParams createDefaultWindowLayoutParams() { + return createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL); + } + + /** + * Creates LayoutParams for adding a view directly to WindowManager as a new window. + * @param type The window type to pass to the created WindowManager.LayoutParams. + */ + public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) { WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams( MATCH_PARENT, mLastRequestedNonFullscreenHeight, - TYPE_NAVIGATION_BAR_PANEL, + type, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); @@ -468,6 +478,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { fromInit); mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags); mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags); + mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible( + (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit); } /** @@ -612,7 +624,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { /** Removes the given view from WindowManager. See {@link #addWindowView}. */ public void removeWindowView(View view) { - mWindowManager.removeViewImmediate(view); + if (view.isAttachedToWindow()) { + mWindowManager.removeViewImmediate(view); + } } protected void onTaskbarIconClicked(View view) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 449e0a7311..d7b50b0994 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -52,6 +52,7 @@ public class TaskbarControllers { public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController; public final TaskbarAllAppsController taskbarAllAppsController; public final TaskbarInsetsController taskbarInsetsController; + public final VoiceInteractionWindowController voiceInteractionWindowController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @@ -80,7 +81,8 @@ public class TaskbarControllers { TaskbarPopupController taskbarPopupController, TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, TaskbarAllAppsController taskbarAllAppsController, - TaskbarInsetsController taskbarInsetsController) { + TaskbarInsetsController taskbarInsetsController, + VoiceInteractionWindowController voiceInteractionWindowController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -99,6 +101,7 @@ public class TaskbarControllers { this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; this.taskbarAllAppsController = taskbarAllAppsController; this.taskbarInsetsController = taskbarInsetsController; + this.voiceInteractionWindowController = voiceInteractionWindowController; } /** @@ -126,13 +129,15 @@ public class TaskbarControllers { taskbarAllAppsController.init(this, sharedState.allAppsVisible); navButtonController.init(this); taskbarInsetsController.init(this); + voiceInteractionWindowController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, taskbarDragLayerController, taskbarScrimViewController, taskbarViewController, taskbarUnfoldAnimationController, taskbarKeyguardController, stashedHandleViewController, taskbarStashController, taskbarEduController, - taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController + taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController, + voiceInteractionWindowController }; mAreAllControllersInitialized = true; @@ -172,6 +177,7 @@ public class TaskbarControllers { taskbarAllAppsController.onDestroy(); navButtonController.onDestroy(); taskbarInsetsController.onDestroy(); + voiceInteractionWindowController.onDestroy(); mControllersToLog = null; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 3562f5bc3c..fdd9de5db3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -63,7 +63,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public static final int ALPHA_INDEX_STASH = 2; public static final int ALPHA_INDEX_RECENTS_DISABLED = 3; public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4; - private static final int NUM_ALPHA_CHANNELS = 5; + public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5; + private static final int NUM_ALPHA_CHANNELS = 6; private final TaskbarActivityContext mActivity; private final TaskbarView mTaskbarView; diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt new file mode 100644 index 0000000000..946873e7ab --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt @@ -0,0 +1,109 @@ +package com.android.launcher3.taskbar + +import android.graphics.Canvas +import android.view.WindowManager +import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY +import com.android.launcher3.views.BaseDragLayer +import com.android.systemui.animation.ViewRootSync +import java.io.PrintWriter + +private const val TASKBAR_ICONS_FADE_DURATION = 300L +private const val STASHED_HANDLE_FADE_DURATION = 180L + +/** + * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. + */ +class VoiceInteractionWindowController(val context: TaskbarActivityContext) + : TaskbarControllers.LoggableTaskbarController { + + private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context) + + // Initialized in init. + private lateinit var controllers: TaskbarControllers + private lateinit var separateWindowForTaskbarBackground: BaseDragLayer + private lateinit var separateWindowLayoutParams: WindowManager.LayoutParams + + private var isVoiceInteractionWindowVisible: Boolean = false + + fun init(controllers: TaskbarControllers) { + this.controllers = controllers + + separateWindowForTaskbarBackground = + object : BaseDragLayer(context, null, 0) { + override fun recreateControllers() { + mControllers = emptyArray() + } + + override fun draw(canvas: Canvas) { + super.draw(canvas) + taskbarBackgroundRenderer.draw(canvas) + } + } + separateWindowForTaskbarBackground.recreateControllers() + separateWindowForTaskbarBackground.setWillNotDraw(false) + + separateWindowLayoutParams = context.createDefaultWindowLayoutParams( + TYPE_APPLICATION_OVERLAY) + separateWindowLayoutParams.isSystemApplicationOverlay = true + } + + fun onDestroy() { + setIsVoiceInteractionWindowVisible(visible = false, skipAnim = true) + } + + fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) { + if (isVoiceInteractionWindowVisible == visible) { + return + } + isVoiceInteractionWindowVisible = visible + + // Fade out taskbar icons and stashed handle. + val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f + val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha + .getProperty(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .animateToValue(taskbarIconAlpha) + .setDuration(TASKBAR_ICONS_FADE_DURATION) + val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha + .getProperty(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .animateToValue(taskbarIconAlpha) + .setDuration(STASHED_HANDLE_FADE_DURATION) + fadeTaskbarIcons.start() + fadeStashedHandle.start() + if (skipAnim) { + fadeTaskbarIcons.end() + fadeStashedHandle.end() + } + + if (context.isGestureNav && controllers.taskbarStashController.isInAppAndNotStashed) { + moveTaskbarBackgroundToLowerLayer() + } + } + + /** + * Hides the TaskbarDragLayer background and creates a new window to draw just that background. + */ + private fun moveTaskbarBackgroundToLowerLayer() { + val taskbarBackgroundOverride = controllers.taskbarDragLayerController + .overrideBackgroundAlpha + if (isVoiceInteractionWindowVisible) { + // First add the temporary window, then hide the overlapping taskbar background. + context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams) + ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer + ) { + taskbarBackgroundOverride.updateValue(0f) + } + } else { + // First reapply the original taskbar background, then remove the temporary window. + taskbarBackgroundOverride.updateValue(1f) + ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer + ) { + context.removeWindowView(separateWindowForTaskbarBackground) + } + } + } + + override fun dumpLogs(prefix: String, pw: PrintWriter) { + pw.println(prefix + "VoiceInteractionWindowController:") + pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible") + } +} \ No newline at end of file From 661f02de18d49ae53fdbdeb1912e081f26d7cc94 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Tue, 7 Jun 2022 14:03:43 +0100 Subject: [PATCH 4/6] Use normalized CachedDisplayInfo as key - For system Launcher, migrate to use getPossibleMaximumWindowMetrics instead of getDisplays - Removed usage of displayId - In estimateInternalDisplayBounds, use CachedDisplayInfo directly as a key - When cache retunrs null for the current display (e.g. the 3P launcher case), invalidate the cache and estimate again, and only add to supportedBounds if current display is not found in the new cache Bug: 227459045 Bug: 198965093 Test: manual Change-Id: Ibcc05ba483ed31a40d16e3cf49c3f3d43af68cf6 --- .../util/SystemWindowManagerProxy.java | 37 ++++-- .../OrientationTouchTransformerTest.java | 13 +- .../quickstep/util/TaskViewSimulatorTest.java | 14 +-- .../launcher3/InvariantDeviceProfile.java | 5 +- .../launcher3/util/DisplayController.java | 102 ++++++++-------- .../util/window/CachedDisplayInfo.java | 21 ++-- .../util/window/WindowManagerProxy.java | 114 ++++++++---------- .../deviceemulator/DisplayEmulator.java | 6 +- .../TestWindowManagerProxy.java | 24 ++-- 9 files changed, 159 insertions(+), 177 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java index 19a48dbf20..5dc461363b 100644 --- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java +++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java @@ -15,11 +15,20 @@ */ package com.android.quickstep.util; -import android.content.Context; -import android.view.Display; +import static android.view.Display.DEFAULT_DISPLAY; +import android.content.Context; +import android.util.ArrayMap; +import android.view.Surface; +import android.view.WindowManager; +import android.view.WindowMetrics; + +import com.android.launcher3.util.WindowBounds; +import com.android.launcher3.util.window.CachedDisplayInfo; import com.android.launcher3.util.window.WindowManagerProxy; +import java.util.Set; + /** * Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher */ @@ -30,17 +39,23 @@ public class SystemWindowManagerProxy extends WindowManagerProxy { } @Override - protected String getDisplayId(Display display) { - return display.getUniqueId(); + public int getRotation(Context displayInfoContext) { + return displayInfoContext.getResources().getConfiguration().windowConfiguration + .getRotation(); } @Override - public boolean isInternalDisplay(Display display) { - return display.getType() == Display.TYPE_INTERNAL; - } - - @Override - public int getRotation(Context context) { - return context.getResources().getConfiguration().windowConfiguration.getRotation(); + public ArrayMap estimateInternalDisplayBounds( + Context displayInfoContext) { + ArrayMap result = new ArrayMap<>(); + WindowManager windowManager = displayInfoContext.getSystemService(WindowManager.class); + Set possibleMaximumWindowMetrics = + windowManager.getPossibleMaximumWindowMetrics(DEFAULT_DISPLAY); + for (WindowMetrics windowMetrics : possibleMaximumWindowMetrics) { + CachedDisplayInfo info = getDisplayInfo(windowMetrics, Surface.ROTATION_0); + WindowBounds[] bounds = estimateWindowBounds(displayInfoContext, info); + result.put(info, bounds); + } + return result; } } diff --git a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java index 9e5d9585af..1c15e1eb3e 100644 --- a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java +++ b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java @@ -35,7 +35,6 @@ import android.graphics.Rect; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Size; -import android.view.Display; import android.view.MotionEvent; import android.view.Surface; @@ -290,15 +289,17 @@ public class OrientationTouchTransformerTest { private DisplayController.Info createDisplayInfo(Size screenSize, int rotation) { Point displaySize = new Point(screenSize.getWidth(), screenSize.getHeight()); RotationUtils.rotateSize(displaySize, rotation); - CachedDisplayInfo cdi = new CachedDisplayInfo(displaySize, rotation); - WindowBounds wm = new WindowBounds( + CachedDisplayInfo cachedDisplayInfo = new CachedDisplayInfo(displaySize, rotation); + WindowBounds windowBounds = new WindowBounds( new Rect(0, 0, displaySize.x, displaySize.y), new Rect()); WindowManagerProxy wmProxy = mock(WindowManagerProxy.class); - doReturn(cdi).when(wmProxy).getDisplayInfo(any(), any()); - doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any()); + doReturn(cachedDisplayInfo).when(wmProxy).getDisplayInfo(any()); + doReturn(windowBounds).when(wmProxy).getRealBounds(any(), any()); + ArrayMap internalDisplayBounds = new ArrayMap<>(); + doReturn(internalDisplayBounds).when(wmProxy).estimateInternalDisplayBounds(any()); return new DisplayController.Info( - getApplicationContext(), mock(Display.class), wmProxy, new ArrayMap<>()); + getApplicationContext(), wmProxy, new ArrayMap<>()); } private float generateTouchRegionHeight(Size screenSize, int rotation) { diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java index 7d414f4910..d43aafa162 100644 --- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java +++ b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java @@ -23,8 +23,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.util.ArrayMap; -import android.util.Pair; -import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; @@ -148,7 +146,7 @@ public class TaskViewSimulatorTest { int rotation = mDisplaySize.x > mDisplaySize.y ? Surface.ROTATION_90 : Surface.ROTATION_0; CachedDisplayInfo cdi = - new CachedDisplayInfo("test-display", mDisplaySize, rotation , new Rect()); + new CachedDisplayInfo(mDisplaySize, rotation, new Rect()); WindowBounds wm = new WindowBounds( new Rect(0, 0, mDisplaySize.x, mDisplaySize.y), mDisplayInsets); @@ -164,15 +162,15 @@ public class TaskViewSimulatorTest { } WindowManagerProxy wmProxy = mock(WindowManagerProxy.class); - doReturn(cdi).when(wmProxy).getDisplayInfo(any(), any()); - doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any()); + doReturn(cdi).when(wmProxy).getDisplayInfo(any()); + doReturn(wm).when(wmProxy).getRealBounds(any(), any()); - ArrayMap> perDisplayBoundsCache = + ArrayMap perDisplayBoundsCache = new ArrayMap<>(); - perDisplayBoundsCache.put(cdi.id, Pair.create(cdi.normalize(), allBounds)); + perDisplayBoundsCache.put(cdi.normalize(), allBounds); DisplayController.Info mockInfo = new Info( - helper.sandboxContext, mock(Display.class), wmProxy, perDisplayBoundsCache); + helper.sandboxContext, wmProxy, perDisplayBoundsCache); DisplayController controller = DisplayController.INSTANCE.get(helper.sandboxContext); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index db43b44f72..73ca4a34c4 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -234,7 +234,8 @@ public class InvariantDeviceProfile { /*allowDisabledGrid=*/false), defaultDeviceType); - Info myInfo = new Info(context, display); + Context displayContext = context.createDisplayContext(display); + Info myInfo = new Info(displayContext); @DeviceType int deviceType = getDeviceType(myInfo); DisplayOption myDisplayOption = invDistWeightedInterpolate( myInfo, @@ -642,7 +643,7 @@ public class InvariantDeviceProfile { + "\nconfig: " + config + "\ndisplayMetrics: " + res.getDisplayMetrics() + "\nrotation: " + rotation - + "\n" + stringWriter.toString(), + + "\n" + stringWriter, new Exception()); } return getBestMatch(screenWidth, screenHeight, rotation); diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index 9ed6beef6f..1a77674ddd 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -41,7 +41,6 @@ import android.os.Build; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; -import android.util.Pair; import android.view.Display; import androidx.annotation.AnyThread; @@ -117,8 +116,9 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED)); WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context); - mInfo = new Info(getDisplayInfoContext(display), display, - wmProxy, wmProxy.estimateInternalDisplayBounds(context)); + Context displayInfoContext = getDisplayInfoContext(display); + mInfo = new Info(displayInfoContext, wmProxy, + wmProxy.estimateInternalDisplayBounds(displayInfoContext)); } /** @@ -216,18 +216,18 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext); Info oldInfo = mInfo; - Context displayContext = getDisplayInfoContext(display); - Info newInfo = new Info(displayContext, display, wmProxy, oldInfo.mPerDisplayBounds); + Context displayInfoContext = getDisplayInfoContext(display); + Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds); if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale || newInfo.navigationMode != oldInfo.navigationMode) { // Cache may not be valid anymore, recreate without cache - newInfo = new Info(displayContext, display, wmProxy, - wmProxy.estimateInternalDisplayBounds(displayContext)); + newInfo = new Info(displayInfoContext, wmProxy, + wmProxy.estimateInternalDisplayBounds(displayInfoContext)); } int change = 0; - if (!newInfo.displayId.equals(oldInfo.displayId)) { + if (!newInfo.normalizedDisplayInfo.equals(oldInfo.normalizedDisplayInfo)) { change |= CHANGE_ACTIVE_SCREEN; } if (newInfo.rotation != oldInfo.rotation) { @@ -242,35 +242,16 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds) || !newInfo.mPerDisplayBounds.equals(oldInfo.mPerDisplayBounds)) { change |= CHANGE_SUPPORTED_BOUNDS; - - Point currentS = newInfo.currentSize; - Pair cachedBounds = - oldInfo.mPerDisplayBounds.get(newInfo.displayId); - Point expectedS = cachedBounds == null ? null : cachedBounds.first.size; - if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) { - Log.e("b/198965093", - "Inconsistent number of displays" - + "\ndisplay state: " + display.getState() - + "\noldInfo.supportedBounds: " + oldInfo.supportedBounds - + "\nnewInfo.supportedBounds: " + newInfo.supportedBounds); - } - if (expectedS != null - && (Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y) - || Math.max(currentS.x, currentS.y) != Math.max(expectedS.x, expectedS.y)) - && display.getState() == Display.STATE_OFF) { - Log.e("b/198965093", - "Display size changed while display is off, ignoring change"); - return; - } } Log.d("b/198965093", "handleInfoChange" - + "\n\tchange: " + change - + "\n\tConfiguration diff: " + newInfo.mConfiguration.diff(oldInfo.mConfiguration)); + + "\n\tchange: 0b" + Integer.toBinaryString(change) + + "\n\tConfiguration diff: 0x" + Integer.toHexString( + newInfo.mConfiguration.diff(oldInfo.mConfiguration))); if (change != 0) { mInfo = newInfo; final int flags = change; - MAIN_EXECUTOR.execute(() -> notifyChange(displayContext, flags)); + MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags)); } } @@ -288,8 +269,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public static class Info { // Cached property + public final CachedDisplayInfo normalizedDisplayInfo; public final int rotation; - public final String displayId; public final Point currentSize; public final Rect cutout; @@ -302,60 +283,71 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public final Set supportedBounds = new ArraySet<>(); - private final ArrayMap> mPerDisplayBounds = + private final ArrayMap mPerDisplayBounds = new ArrayMap<>(); // TODO(b/198965093): Remove after investigation private Configuration mConfiguration; - public Info(Context context, Display display) { + public Info(Context displayInfoContext) { /* don't need system overrides for external displays */ - this(context, display, new WindowManagerProxy(), new ArrayMap<>()); + this(displayInfoContext, new WindowManagerProxy(), new ArrayMap<>()); } // Used for testing - public Info(Context context, Display display, + public Info(Context displayInfoContext, WindowManagerProxy wmProxy, - ArrayMap> perDisplayBoundsCache) { - CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(context, display); + ArrayMap perDisplayBoundsCache) { + CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(displayInfoContext); + normalizedDisplayInfo = displayInfo.normalize(); rotation = displayInfo.rotation; currentSize = displayInfo.size; - displayId = displayInfo.id; cutout = displayInfo.cutout; - Configuration config = context.getResources().getConfiguration(); + Configuration config = displayInfoContext.getResources().getConfiguration(); fontScale = config.fontScale; densityDpi = config.densityDpi; mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp); - navigationMode = parseNavigationMode(context); + navigationMode = parseNavigationMode(displayInfoContext); // TODO(b/198965093): Remove after investigation mConfiguration = config; mPerDisplayBounds.putAll(perDisplayBoundsCache); - Pair cachedValue = mPerDisplayBounds.get(displayId); + WindowBounds[] cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo); - WindowBounds realBounds = wmProxy.getRealBounds(context, display, displayInfo); + WindowBounds realBounds = wmProxy.getRealBounds(displayInfoContext, displayInfo); if (cachedValue == null) { - supportedBounds.add(realBounds); - } else { + // Unexpected normalizedDisplayInfo is found, recreate the cache + Log.e("b/198965093", "Unexpected normalizedDisplayInfo found, invalidating cache"); + mPerDisplayBounds.clear(); + mPerDisplayBounds.putAll(wmProxy.estimateInternalDisplayBounds(displayInfoContext)); + cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo); + if (cachedValue == null) { + Log.e("b/198965093", "normalizedDisplayInfo not found in estimation: " + + normalizedDisplayInfo); + supportedBounds.add(realBounds); + } + } + + if (cachedValue != null) { // Verify that the real bounds are a match - WindowBounds expectedBounds = cachedValue.second[displayInfo.rotation]; + WindowBounds expectedBounds = cachedValue[displayInfo.rotation]; if (!realBounds.equals(expectedBounds)) { WindowBounds[] clone = new WindowBounds[4]; - System.arraycopy(cachedValue.second, 0, clone, 0, 4); + System.arraycopy(cachedValue, 0, clone, 0, 4); clone[displayInfo.rotation] = realBounds; - cachedValue = Pair.create(displayInfo.normalize(), clone); - mPerDisplayBounds.put(displayId, cachedValue); + mPerDisplayBounds.put(normalizedDisplayInfo, clone); } } mPerDisplayBounds.values().forEach( - pair -> Collections.addAll(supportedBounds, pair.second)); + windowBounds -> Collections.addAll(supportedBounds, windowBounds)); Log.e("b/198965093", "mConfiguration: " + mConfiguration); Log.d("b/198965093", "displayInfo: " + displayInfo); Log.d("b/198965093", "realBounds: " + realBounds); - mPerDisplayBounds.values().forEach(pair -> Log.d("b/198965093", - "perDisplayBounds - " + pair.first + ": " + Arrays.deepToString(pair.second))); + Log.d("b/198965093", "normalizedDisplayInfo: " + normalizedDisplayInfo); + mPerDisplayBounds.forEach((key, value) -> Log.d("b/198965093", + "perDisplayBounds - " + key + ": " + Arrays.deepToString(value))); } /** @@ -383,14 +375,14 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public void dump(PrintWriter pw) { Info info = mInfo; pw.println("DisplayController.Info:"); - pw.println(" id=" + info.displayId); + pw.println(" normalizedDisplayInfo=" + info.normalizedDisplayInfo); pw.println(" rotation=" + info.rotation); pw.println(" fontScale=" + info.fontScale); pw.println(" densityDpi=" + info.densityDpi); pw.println(" navigationMode=" + info.navigationMode.name()); pw.println(" currentSize=" + info.currentSize); - info.mPerDisplayBounds.values().forEach(pair -> pw.println( - " perDisplayBounds - " + pair.first + ": " + Arrays.deepToString(pair.second))); + info.mPerDisplayBounds.forEach((key, value) -> pw.println( + " perDisplayBounds - " + key + ": " + Arrays.deepToString(value))); } /** diff --git a/src/com/android/launcher3/util/window/CachedDisplayInfo.java b/src/com/android/launcher3/util/window/CachedDisplayInfo.java index 06b9829270..23f37aa2b2 100644 --- a/src/com/android/launcher3/util/window/CachedDisplayInfo.java +++ b/src/com/android/launcher3/util/window/CachedDisplayInfo.java @@ -30,7 +30,6 @@ import java.util.Objects; */ public class CachedDisplayInfo { - public final String id; public final Point size; public final int rotation; public final Rect cutout; @@ -40,11 +39,10 @@ public class CachedDisplayInfo { } public CachedDisplayInfo(Point size, int rotation) { - this("", size, rotation, new Rect()); + this(size, rotation, new Rect()); } - public CachedDisplayInfo(String id, Point size, int rotation, Rect cutout) { - this.id = id; + public CachedDisplayInfo(Point size, int rotation, Rect cutout) { this.size = size; this.rotation = rotation; this.cutout = cutout; @@ -62,16 +60,15 @@ public class CachedDisplayInfo { Rect newCutout = new Rect(cutout); rotateRect(newCutout, deltaRotation(rotation, Surface.ROTATION_0)); - return new CachedDisplayInfo(id, newSize, Surface.ROTATION_0, newCutout); + return new CachedDisplayInfo(newSize, Surface.ROTATION_0, newCutout); } @Override public String toString() { return "CachedDisplayInfo{" - + "id='" + id + '\'' - + ", size=" + size - + ", rotation=" + rotation + + "size=" + size + ", cutout=" + cutout + + ", rotation=" + rotation + '}'; } @@ -80,13 +77,13 @@ public class CachedDisplayInfo { if (this == o) return true; if (!(o instanceof CachedDisplayInfo)) return false; CachedDisplayInfo that = (CachedDisplayInfo) o; - return rotation == that.rotation && Objects.equals(id, that.id) - && Objects.equals(size, that.size) && Objects.equals(cutout, - that.cutout); + return rotation == that.rotation + && Objects.equals(size, that.size) + && Objects.equals(cutout, that.cutout); } @Override public int hashCode() { - return Objects.hash(id, size, rotation, cutout); + return Objects.hash(size, rotation, cutout); } } diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java index 92f718ef45..d5a065a2ea 100644 --- a/src/com/android/launcher3/util/window/WindowManagerProxy.java +++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java @@ -16,7 +16,6 @@ package com.android.launcher3.util.window; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE; import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT; @@ -41,7 +40,6 @@ import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Build; import android.util.ArrayMap; -import android.util.Pair; import android.view.Display; import android.view.DisplayCutout; import android.view.Surface; @@ -88,20 +86,12 @@ public class WindowManagerProxy implements ResourceBasedOverride { * Returns a map of normalized info of internal displays to estimated window bounds * for that display */ - public ArrayMap> estimateInternalDisplayBounds( - Context context) { - Display[] displays = context.getSystemService(DisplayManager.class).getDisplays(); - ArrayMap> result = new ArrayMap<>(); - for (Display display : displays) { - if (isInternalDisplay(display)) { - Context displayContext = Utilities.ATLEAST_S - ? context.createWindowContext(display, TYPE_APPLICATION, null) - : context.createDisplayContext(display); - CachedDisplayInfo info = getDisplayInfo(displayContext, display).normalize(); - WindowBounds[] bounds = estimateWindowBounds(context, info); - result.put(info.id, Pair.create(info, bounds)); - } - } + public ArrayMap estimateInternalDisplayBounds( + Context displayInfoContext) { + CachedDisplayInfo info = getDisplayInfo(displayInfoContext).normalize(); + WindowBounds[] bounds = estimateWindowBounds(displayInfoContext, info); + ArrayMap result = new ArrayMap<>(); + result.put(info, bounds); return result; } @@ -109,12 +99,11 @@ public class WindowManagerProxy implements ResourceBasedOverride { * Returns the real bounds for the provided display after applying any insets normalization */ @TargetApi(Build.VERSION_CODES.R) - public WindowBounds getRealBounds(Context windowContext, - Display display, CachedDisplayInfo info) { + public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) { if (!Utilities.ATLEAST_R) { Point smallestSize = new Point(); Point largestSize = new Point(); - display.getCurrentSizeRange(smallestSize, largestSize); + getDisplay(displayInfoContext).getCurrentSizeRange(smallestSize, largestSize); if (info.size.y > info.size.x) { // Portrait @@ -122,17 +111,16 @@ public class WindowManagerProxy implements ResourceBasedOverride { info.rotation); } else { // Landscape - new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y, + return new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y, info.rotation); } } - WindowMetrics wm = windowContext.getSystemService(WindowManager.class) + WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics(); - Rect insets = new Rect(); - normalizeWindowInsets(windowContext, wm.getWindowInsets(), insets); - return new WindowBounds(wm.getBounds(), insets, info.rotation); + normalizeWindowInsets(displayInfoContext, windowMetrics.getWindowInsets(), insets); + return new WindowBounds(windowMetrics.getBounds(), insets, info.rotation); } /** @@ -169,12 +157,9 @@ public class WindowManagerProxy implements ResourceBasedOverride { insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets); Insets statusBarInsets = oldInsets.getInsets(WindowInsets.Type.statusBars()); - - int statusBarHeight = getDimenByName(systemRes, (isPortrait) ? STATUS_BAR_HEIGHT_PORTRAIT : STATUS_BAR_HEIGHT_LANDSCAPE, STATUS_BAR_HEIGHT); - Insets newStatusBarInsets = Insets.of( statusBarInsets.left, Math.max(statusBarInsets.top, statusBarHeight), @@ -201,22 +186,15 @@ public class WindowManagerProxy implements ResourceBasedOverride { return result; } - /** - * Returns true if the display is an internal displays - */ - protected boolean isInternalDisplay(Display display) { - return display.getDisplayId() == Display.DEFAULT_DISPLAY; - } - /** * Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations */ - public WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo display) { + protected WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo displayInfo) { int densityDpi = context.getResources().getConfiguration().densityDpi; - int rotation = display.rotation; - Rect safeCutout = display.cutout; + int rotation = displayInfo.rotation; + Rect safeCutout = displayInfo.cutout; - int minSize = Math.min(display.size.x, display.size.y); + int minSize = Math.min(displayInfo.size.x, displayInfo.size.y); int swDp = (int) dpiFromPx(minSize, densityDpi); Resources systemRes; @@ -255,7 +233,7 @@ public class WindowManagerProxy implements ResourceBasedOverride { Point tempSize = new Point(); for (int i = 0; i < 4; i++) { int rotationChange = deltaRotation(rotation, i); - tempSize.set(display.size.x, display.size.y); + tempSize.set(displayInfo.size.x, displayInfo.size.y); rotateSize(tempSize, rotationChange); Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y); @@ -311,48 +289,58 @@ public class WindowManagerProxy implements ResourceBasedOverride { * Returns a CachedDisplayInfo initialized for the current display */ @TargetApi(Build.VERSION_CODES.S) - public CachedDisplayInfo getDisplayInfo(Context displayContext, Display display) { - int rotation = getRotation(displayContext); - Rect cutoutRect = new Rect(); - Point size = new Point(); + public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) { + int rotation = getRotation(displayInfoContext); if (Utilities.ATLEAST_S) { - WindowMetrics wm = displayContext.getSystemService(WindowManager.class) + WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics(); - DisplayCutout cutout = wm.getWindowInsets().getDisplayCutout(); - if (cutout != null) { - cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(), - cutout.getSafeInsetRight(), cutout.getSafeInsetBottom()); - } - - size.set(wm.getBounds().right, wm.getBounds().bottom); + return getDisplayInfo(windowMetrics, rotation); } else { + Point size = new Point(); + Display display = getDisplay(displayInfoContext); display.getRealSize(size); + Rect cutoutRect = new Rect(); + return new CachedDisplayInfo(size, rotation, cutoutRect); } - return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutoutRect); } /** - * Returns a unique ID representing the display + * Returns a CachedDisplayInfo initialized for the current display */ - protected String getDisplayId(Display display) { - return Integer.toString(display.getDisplayId()); + @TargetApi(Build.VERSION_CODES.S) + protected CachedDisplayInfo getDisplayInfo(WindowMetrics windowMetrics, int rotation) { + Point size = new Point(windowMetrics.getBounds().right, windowMetrics.getBounds().bottom); + Rect cutoutRect = new Rect(); + DisplayCutout cutout = windowMetrics.getWindowInsets().getDisplayCutout(); + if (cutout != null) { + cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(), + cutout.getSafeInsetRight(), cutout.getSafeInsetBottom()); + } + return new CachedDisplayInfo(size, rotation, cutoutRect); } /** - * Returns rotation of the display associated with the context. + * Returns rotation of the display associated with the context, or rotation of DEFAULT_DISPLAY + * if the context isn't associated with a display. */ - public int getRotation(Context context) { - Display d = null; + public int getRotation(Context displayInfoContext) { + return getDisplay(displayInfoContext).getRotation(); + } + + /** + * + * Returns the display associated with the context, or DEFAULT_DISPLAY if the context isn't + * associated with a display. + */ + protected Display getDisplay(Context displayInfoContext) { if (Utilities.ATLEAST_R) { try { - d = context.getDisplay(); + return displayInfoContext.getDisplay(); } catch (UnsupportedOperationException e) { // Ignore } } - if (d == null) { - d = context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); - } - return d.getRotation(); + return displayInfoContext.getSystemService(DisplayManager.class).getDisplay( + DEFAULT_DISPLAY); } } diff --git a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java index 31468c5336..e2ed65fa5b 100644 --- a/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java +++ b/tests/src/com/android/launcher3/deviceemulator/DisplayEmulator.java @@ -47,8 +47,7 @@ public class DisplayEmulator { * By changing the WindowManagerProxy we can override the window insets information **/ private IWindowManager changeWindowManagerInstance(DeviceEmulationData deviceData) { - WindowManagerProxy.INSTANCE.initializeForTesting( - new TestWindowManagerProxy(mContext, deviceData)); + WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(deviceData)); return WindowManagerGlobal.getWindowManagerService(); } @@ -57,8 +56,7 @@ public class DisplayEmulator { WindowManagerProxy original = WindowManagerProxy.INSTANCE.get(mContext); // Set up emulation final int userId = UserHandle.myUserId(); - WindowManagerProxy.INSTANCE.initializeForTesting( - new TestWindowManagerProxy(mContext, device)); + WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(device)); IWindowManager wm = changeWindowManagerInstance(device); // Change density twice to force display controller to reset its state wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density / 2, userId); diff --git a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java index cbea688a9a..2d6bbccb68 100644 --- a/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java +++ b/tests/src/com/android/launcher3/deviceemulator/TestWindowManagerProxy.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; -import android.view.Display; import android.view.WindowInsets; import com.android.launcher3.deviceemulator.models.DeviceEmulationData; @@ -32,16 +31,11 @@ public class TestWindowManagerProxy extends WindowManagerProxy { private final DeviceEmulationData mDevice; - public TestWindowManagerProxy(Context context, DeviceEmulationData device) { + public TestWindowManagerProxy(DeviceEmulationData device) { super(true); mDevice = device; } - @Override - public boolean isInternalDisplay(Display display) { - return display.getDisplayId() == Display.DEFAULT_DISPLAY; - } - @Override protected int getDimenByName(Resources res, String resName) { Integer mock = mDevice.resourceOverrides.get(resName); @@ -54,27 +48,25 @@ public class TestWindowManagerProxy extends WindowManagerProxy { } @Override - public CachedDisplayInfo getDisplayInfo(Context context, Display display) { - int rotation = display.getRotation(); + public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) { + int rotation = getRotation(displayInfoContext); Point size = new Point(mDevice.width, mDevice.height); RotationUtils.rotateSize(size, rotation); Rect cutout = new Rect(mDevice.cutout); RotationUtils.rotateRect(cutout, rotation); - return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutout); + return new CachedDisplayInfo(size, rotation, cutout); } @Override - public WindowBounds getRealBounds(Context windowContext, Display display, - CachedDisplayInfo info) { - return estimateInternalDisplayBounds(windowContext) - .get(getDisplayId(display)).second[display.getRotation()]; + public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) { + return estimateInternalDisplayBounds(displayInfoContext).get( + getDisplayInfo(displayInfoContext))[getDisplay(displayInfoContext).getRotation()]; } @Override public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets, Rect outInsets) { - outInsets.set(getRealBounds(context, context.getDisplay(), - getDisplayInfo(context, context.getDisplay())).insets); + outInsets.set(getRealBounds(context, getDisplayInfo(context)).insets); return oldInsets; } } From 5e2fb4e08f956b13c9c6b2edb28f35f9568fa8d5 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Mon, 6 Jun 2022 14:03:17 +0100 Subject: [PATCH 5/6] Use DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED for getDisplays - getDisplays is removed in tm-qpr-dev so it's an empty commit Bug: 227459045 Bug: 221071695 Test: manual Change-Id: I8c1587e05a30abf75a01a84ebda6522606abb99b From 1cd4162b82ca33702e943e6a6d402d80013250db Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Thu, 9 Jun 2022 10:19:37 -0700 Subject: [PATCH 6/6] Do not attempt auto-enter-pip if there is no valid leash No reproduce path for the bug being reported, this fix is to ensure we do not start the auto-enter-pip animation with invalid leash at the first place. Bug: 234796719 Test: N/A for the bug, verify the normal auto-enter-pip still works Change-Id: I6f2164a322877f1b0213a1ee09eb476090300c7f --- .../src/com/android/quickstep/AbsSwipeUpHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index d676f7d195..5bb2a05417 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1284,8 +1284,11 @@ public abstract class AbsSwipeUpHandler, ? runningTaskTarget.taskInfo.launchCookies : new ArrayList<>(); boolean isTranslucent = runningTaskTarget != null && runningTaskTarget.isTranslucent; + boolean hasValidLeash = runningTaskTarget != null + && runningTaskTarget.leash != null + && runningTaskTarget.leash.isValid(); boolean appCanEnterPip = !mDeviceState.isPipActive() - && runningTaskTarget != null + && hasValidLeash && runningTaskTarget.allowEnterPip && runningTaskTarget.taskInfo.pictureInPictureParams != null && runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled(); @@ -1394,9 +1397,6 @@ public abstract class AbsSwipeUpHandler, } } - /** - * TODO(b/195473090) handle multiple task simulators (if needed) for PIP - */ private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory, RemoteAnimationTargetCompat runningTaskTarget, float startProgress) { // Directly animate the app to PiP (picture-in-picture) mode