Snap for 9514198 from 7e1144ee994fb72481b9c9dbf174fd223430fab9 to tm-qpr3-release

Change-Id: Ide5d6d66a02379fc4b55a50b19b7d2b01457fd45
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index cbee58b..2b976df 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -51,7 +51,6 @@
 import android.annotation.LayoutRes;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -725,13 +724,6 @@
             mPropertyHolders.add(new StatePropertyHolder(
                     mBackButtonAlpha.get(ALPHA_INDEX_SUW),
                     flags -> (flags & FLAG_IME_VISIBLE) == 0));
-
-            // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
-            //  it based on dark theme for now.
-            int mode = res.getConfiguration().uiMode
-                    & Configuration.UI_MODE_NIGHT_MASK;
-            boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
-            mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1);
         } else if (isInKidsMode) {
             int iconSize = res.getDimensionPixelSize(
                     R.dimen.taskbar_icon_size_kids);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index bc41c2b..260876b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -73,6 +73,13 @@
     // Roundness property for round corner above taskbar .
     private final AnimatedFloat mCornerRoundness = new AnimatedFloat(this::updateCornerRoundness);
 
+    /**
+     * Want to add a new controller? Don't forget to:
+     *   * Call init
+     *   * Call onDestroy
+     *   * Add to mControllersToLog
+     *   * Add tests by adding this controller to TaskbarBaseTestCase.kt and extending that class
+     */
     public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
             TaskbarDragController taskbarDragController,
             TaskbarNavButtonController navButtonController,
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 5dc4613..a34888f 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -23,6 +23,7 @@
 import android.view.WindowManager;
 import android.view.WindowMetrics;
 
+import com.android.internal.policy.SystemBarUtils;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.CachedDisplayInfo;
 import com.android.launcher3.util.window.WindowManagerProxy;
@@ -45,6 +46,13 @@
     }
 
     @Override
+    protected int getStatusBarHeight(Context context, boolean isPortrait, int statusBarInset) {
+        // See b/264656380, calculate the status bar height manually as the inset in the system
+        // server might not be updated by this point yet causing extra DeviceProfile updates
+        return SystemBarUtils.getStatusBarHeight(context);
+    }
+
+    @Override
     public ArrayMap<CachedDisplayInfo, WindowBounds[]> estimateInternalDisplayBounds(
             Context displayInfoContext) {
         ArrayMap<CachedDisplayInfo, WindowBounds[]> result = new ArrayMap<>();
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index f6e172a..c71a74e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -377,6 +377,8 @@
 
     private void updateSplashView(Drawable icon) {
         if (icon == null || icon.getConstantState() == null) {
+            mSplashViewDrawable = null;
+            mSplashView = null;
             return;
         }
         mSplashViewDrawable = icon.getConstantState().newDrawable().mutate();
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
new file mode 100644
index 0000000..e8a575e
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar
+
+import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
+import com.android.systemui.shared.rotation.RotationButtonController
+import org.junit.Before
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+/**
+ * Helper class to extend to get access to all controllers.
+ * Gotta be careful of your relationship with this class though, it can be quite... controlling.
+ */
+abstract class TaskbarBaseTestCase {
+
+    @Mock
+    lateinit var taskbarActivityContext: TaskbarActivityContext
+    @Mock
+    lateinit var taskbarDragController: TaskbarDragController
+    @Mock
+    lateinit var navButtonController: TaskbarNavButtonController
+    @Mock
+    lateinit var navbarButtonsViewController: NavbarButtonsViewController
+    @Mock
+    lateinit var rotationButtonController: RotationButtonController
+    @Mock
+    lateinit var taskbarDragLayerController: TaskbarDragLayerController
+    @Mock
+    lateinit var taskbarScrimViewController: TaskbarScrimViewController
+    @Mock
+    lateinit var taskbarViewController: TaskbarViewController
+    @Mock
+    lateinit var taskbarUnfoldAnimationController: TaskbarUnfoldAnimationController
+    @Mock
+    lateinit var taskbarKeyguardController: TaskbarKeyguardController
+    @Mock
+    lateinit var stashedHandleViewController: StashedHandleViewController
+    @Mock
+    lateinit var taskbarStashController: TaskbarStashController
+    @Mock
+    lateinit var taskbarEduController: TaskbarEduController
+    @Mock
+    lateinit var taskbarAutohideSuspendController: TaskbarAutohideSuspendController
+    @Mock
+    lateinit var taskbarPopupController: TaskbarPopupController
+    @Mock
+    lateinit var taskbarForceVisibleImmersiveController: TaskbarForceVisibleImmersiveController
+    @Mock
+    lateinit var taskbarAllAppsController: TaskbarAllAppsController
+    @Mock
+    lateinit var taskbarInsetsController: TaskbarInsetsController
+    @Mock
+    lateinit var voiceInteractionWindowController: VoiceInteractionWindowController
+    @Mock
+    lateinit var taskbarRecentAppsController: TaskbarRecentAppsController
+    @Mock
+    lateinit var taskbarTranslationController: TaskbarTranslationController
+    @Mock
+    lateinit var taskbarOverlayController: TaskbarOverlayController
+
+    lateinit var mTaskbarControllers: TaskbarControllers
+
+    @Before
+    open fun setup() {
+        /*
+         * NOTE: Mocking of controllers that are written in Kotlin won't work since their methods
+         * are final by default (and should not be changed only for tests), meaning unmockable.
+         * Womp, womp woooommmmppp.
+         * If you want to mock one of those methods, you need to make a parent interface that
+         * includes that method to allow mocking it.
+         */
+        MockitoAnnotations.initMocks(this)
+        mTaskbarControllers = TaskbarControllers(
+                taskbarActivityContext, taskbarDragController, navButtonController,
+                navbarButtonsViewController, rotationButtonController, taskbarDragLayerController,
+                taskbarViewController, taskbarScrimViewController, taskbarUnfoldAnimationController,
+                taskbarKeyguardController, stashedHandleViewController, taskbarStashController,
+                taskbarEduController, taskbarAutohideSuspendController, taskbarPopupController,
+                taskbarForceVisibleImmersiveController, taskbarOverlayController,
+                taskbarAllAppsController, taskbarInsetsController,
+                voiceInteractionWindowController, taskbarTranslationController,
+                taskbarRecentAppsController
+        )
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt
new file mode 100644
index 0000000..59db8c8
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar
+
+import android.app.KeyguardManager
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+class TaskbarKeyguardControllerTest : TaskbarBaseTestCase() {
+
+    @Mock
+    lateinit var baseDragLayer: TaskbarDragLayer
+    @Mock
+    lateinit var keyguardManager: KeyguardManager
+
+    @Before
+    override fun setup() {
+        super.setup()
+        whenever(taskbarActivityContext.getSystemService(KeyguardManager::class.java))
+                .thenReturn(keyguardManager)
+        whenever(baseDragLayer.childCount).thenReturn(0)
+        whenever(taskbarActivityContext.dragLayer).thenReturn(baseDragLayer)
+
+        taskbarKeyguardController = TaskbarKeyguardController(taskbarActivityContext)
+        taskbarKeyguardController.init(navbarButtonsViewController)
+    }
+
+    @Test
+    fun uninterestingFlags_noActions() {
+        setFlags(0)
+        verify(navbarButtonsViewController, never()).setKeyguardVisible(anyBoolean(), anyBoolean())
+    }
+
+    @Test
+    fun keyguardShowing() {
+        setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING)
+        verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
+                true /*isKeyguardVisible*/,
+                false /*isKeyguardOccluded*/)
+    }
+
+    @Test
+    fun dozingShowing() {
+        setFlags(SYSUI_STATE_DEVICE_DOZING)
+        verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
+                true /*isKeyguardVisible*/,
+                false /*isKeyguardOccluded*/)
+    }
+
+    @Test
+    fun keyguardOccluded() {
+        setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED)
+        verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
+                false /*isKeyguardVisible*/,
+                true /*isKeyguardOccluded*/)
+    }
+
+    @Test
+    fun keyguardOccludedAndDozing() {
+        setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED.or(SYSUI_STATE_DEVICE_DOZING))
+        verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
+                true /*isKeyguardVisible*/,
+                true /*isKeyguardOccluded*/)
+    }
+
+    @Test
+    fun deviceInsecure_hideBackForBouncer() {
+        whenever(keyguardManager.isDeviceSecure).thenReturn(false)
+        setFlags(SYSUI_STATE_OVERVIEW_DISABLED
+                .or(SYSUI_STATE_HOME_DISABLED)
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
+    }
+
+    @Test
+    fun deviceSecure_showBackForBouncer() {
+        whenever(keyguardManager.isDeviceSecure).thenReturn(true)
+        setFlags(SYSUI_STATE_OVERVIEW_DISABLED
+                .or(SYSUI_STATE_HOME_DISABLED)
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(1)).setBackForBouncer(true)
+    }
+
+    @Test
+    fun homeShowing_hideBackForBouncer() {
+        whenever(keyguardManager.isDeviceSecure).thenReturn(true)
+        setFlags(SYSUI_STATE_OVERVIEW_DISABLED
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
+    }
+
+    @Test
+    fun overviewShowing_hideBackForBouncer() {
+        whenever(keyguardManager.isDeviceSecure).thenReturn(true)
+        setFlags(SYSUI_STATE_HOME_DISABLED
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
+    }
+
+    @Test
+    fun backDisabled_hideBackForBouncer() {
+        whenever(keyguardManager.isDeviceSecure).thenReturn(true)
+        setFlags(SYSUI_STATE_BACK_DISABLED
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
+
+        // back disabled along with home and overview
+        setFlags(SYSUI_STATE_BACK_DISABLED
+                .or(SYSUI_STATE_HOME_DISABLED)
+                .or(SYSUI_STATE_OVERVIEW_DISABLED)
+                .or(SYSUI_STATE_BOUNCER_SHOWING))
+
+        verify(navbarButtonsViewController, times(2)).setBackForBouncer(false)
+    }
+
+    private fun setFlags(flags: Int) {
+        taskbarKeyguardController.updateStateForSysuiFlags(flags)
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 4f5cc4a..c3d8a53 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1404,15 +1404,17 @@
                             (isFling && !isVelocityLeft)) && mCurrentPage > 0) {
                         finalPage = returnToOriginalPage
                                 ? mCurrentPage : mCurrentPage - getPanelCount();
-                        snapToPageWithVelocity(finalPage, velocity);
+                        runOnPageScrollsInitialized(
+                                () -> snapToPageWithVelocity(finalPage, velocity));
                     } else if (((isSignificantMove && isDeltaLeft && !isFling) ||
                             (isFling && isVelocityLeft)) &&
                             mCurrentPage < getChildCount() - 1) {
                         finalPage = returnToOriginalPage
                                 ? mCurrentPage : mCurrentPage + getPanelCount();
-                        snapToPageWithVelocity(finalPage, velocity);
+                        runOnPageScrollsInitialized(
+                                () -> snapToPageWithVelocity(finalPage, velocity));
                     } else {
-                        snapToDestination();
+                        runOnPageScrollsInitialized(this::snapToDestination);
                     }
                 } else {
                     if (!mScroller.isFinished()) {
@@ -1435,7 +1437,7 @@
 
                         int finalPos = mScroller.getFinalX();
                         mNextPage = getDestinationPage(finalPos);
-                        onNotSnappingToPageInFreeScroll();
+                        runOnPageScrollsInitialized(this::onNotSnappingToPageInFreeScroll);
                     }
                     invalidate();
                 }
@@ -1449,7 +1451,7 @@
 
         case MotionEvent.ACTION_CANCEL:
             if (mIsBeingDragged) {
-                snapToDestination();
+                runOnPageScrollsInitialized(this::snapToDestination);
             }
             mEdgeGlowLeft.onRelease();
             mEdgeGlowRight.onRelease();
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index fb2ae73..4093bc9 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -161,12 +161,10 @@
         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),
+                getStatusBarHeight(context, isPortrait, statusBarInsets.top),
                 statusBarInsets.right,
                 statusBarInsets.bottom);
         insetsBuilder.setInsets(WindowInsets.Type.statusBars(), newStatusBarInsets);
@@ -190,6 +188,15 @@
         return result;
     }
 
+    protected int getStatusBarHeight(Context context, boolean isPortrait, int statusBarInset) {
+        Resources systemRes = context.getResources();
+        int statusBarHeight = getDimenByName(systemRes,
+                isPortrait ? STATUS_BAR_HEIGHT_PORTRAIT : STATUS_BAR_HEIGHT_LANDSCAPE,
+                STATUS_BAR_HEIGHT);
+
+        return Math.max(statusBarInset, statusBarHeight);
+    }
+
     /**
      * Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations
      */
@@ -212,6 +219,9 @@
         boolean isTabletOrGesture = isTablet
                 || (Utilities.ATLEAST_R && isGestureNav(context));
 
+        // Use the status bar height resources because current system API to get the status bar
+        // height doesn't allow to do this for an arbitrary display, it returns value only
+        // for the current active display (see com.android.internal.policy.StatusBarUtils)
         int statusBarHeightPortrait = getDimenByName(systemRes,
                 STATUS_BAR_HEIGHT_PORTRAIT, STATUS_BAR_HEIGHT);
         int statusBarHeightLandscape = getDimenByName(systemRes,