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 diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 13272e9cf4..38a36e434b 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 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() { 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/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 01301f2b57..82e645a7a0 100644 --- a/src/com/android/launcher3/anim/AnimatedPropertySetter.java +++ b/src/com/android/launcher3/anim/AnimatedPropertySetter.java @@ -97,6 +97,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 */ 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; } }