Merge "Add logging for actions view" into main
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index e4e2eb2..6f9cbfd 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -27,6 +27,8 @@
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_NONE;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.isPersistentSnapPosition;
@@ -186,6 +188,10 @@
         }
 
         @PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
+        if (snapPosition == SNAP_TO_NONE) {
+            // Free snap mode is enabled, just save it as 50/50 split.
+            snapPosition = SNAP_TO_50_50;
+        }
         if (!isPersistentSnapPosition(snapPosition)) {
             // If we received an illegal snap position, log an error and do not create the app pair
             Log.wtf(TAG, "Tried to save an app pair with illegal snapPosition "
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index a67a362..98ca420 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -300,7 +300,7 @@
             case VIEW_TYPE_PRIVATE_SPACE_HEADER:
                 RelativeLayout psHeaderLayout = holder.itemView.findViewById(
                         R.id.ps_header_layout);
-                mApps.getPrivateProfileManager().addPrivateSpaceHeaderViewElements(psHeaderLayout);
+                mApps.getPrivateProfileManager().bindPrivateSpaceHeaderViewElements(psHeaderLayout);
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
                 int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
                 if (mApps.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) {
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index a620490..2765c5c 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -104,6 +104,7 @@
     private static final int LOCK_TEXT_OPACITY_DELAY = 500;
     private static final int MASK_VIEW_DELAY = 400;
     private static final int NO_DELAY = 0;
+    private static final int CONTAINER_OPACITY_DURATION = 150;
     private final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
     private final int mPsHeaderHeight;
@@ -196,23 +197,6 @@
         mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
     }
 
-    /**
-     * Disables quiet mode for Private Space User Profile.
-     * When called from search, a runnable is set and executed in the {@link #reset()} method, when
-     * Launcher receives update about profile availability.
-     * The runnable is only executed once, and reset after execution.
-     * In case the method is called again, before the previously set runnable was executed,
-     * the runnable will be updated.
-     */
-    public void unlockPrivateProfile() {
-        setQuietMode(false);
-    }
-
-    /** Enables quiet mode for Private Space User Profile. */
-    void lockPrivateProfile() {
-        setQuietMode(true);
-    }
-
     /** Whether private profile should be hidden on Launcher. */
     public boolean isPrivateSpaceHidden() {
         return getCurrentState() == STATE_DISABLED && SettingsCache.INSTANCE
@@ -377,7 +361,7 @@
     }
 
     /** Add Private Space Header view elements based upon {@link UserProfileState} */
-    public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+    public void bindPrivateSpaceHeaderViewElements(RelativeLayout parent) {
         mPSHeader = parent;
         if (mOnPSHeaderAdded != null) {
             MAIN_EXECUTOR.execute(mOnPSHeaderAdded);
@@ -395,27 +379,27 @@
         //Add quietMode image and action for lock/unlock button
         ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
         assert lockButton != null;
-        addLockButton(lockButton);
+        updateLockButton(lockButton);
 
         //Trigger lock/unlock action from header.
-        addHeaderOnClickListener(mPSHeader);
+        updateHeaderOnClickListener(mPSHeader);
 
         //Add image and action for private space settings button
         ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
         assert settingsButton != null;
-        addPrivateSpaceSettingsButton(settingsButton);
+        updatePrivateSpaceSettingsButton(settingsButton);
 
         //Add image for private space transitioning view
         ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
         assert transitionView != null;
-        addTransitionImage(transitionView);
+        updateTransitionImage(transitionView);
     }
 
     /**
      *  Adds the quietModeButton and attach onClickListener for the header to animate different
      *  states when clicked.
      */
-    private void addLockButton(ViewGroup lockButton) {
+    private void updateLockButton(ViewGroup lockButton) {
         TextView lockText = lockButton.findViewById(R.id.lock_text);
         switch (getCurrentState()) {
             case STATE_ENABLED -> {
@@ -434,7 +418,7 @@
         }
     }
 
-    private void addHeaderOnClickListener(RelativeLayout header) {
+    private void updateHeaderOnClickListener(RelativeLayout header) {
         if (getCurrentState() == STATE_DISABLED) {
             header.setOnClickListener(view -> lockingAction(/* lock */ false));
             header.setClickable(true);
@@ -452,14 +436,10 @@
     /** Sets the enablement of the profile when header or button is clicked. */
     private void lockingAction(boolean lock) {
         logEvents(lock ? LAUNCHER_PRIVATE_SPACE_LOCK_TAP : LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
-        if (lock) {
-            lockPrivateProfile();
-        } else {
-            unlockPrivateProfile();
-        }
+        setQuietMode(lock);
     }
 
-    private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
+    private void updatePrivateSpaceSettingsButton(ImageButton settingsButton) {
         if (getCurrentState() == STATE_ENABLED
                 && isPrivateSpaceSettingsAvailable()) {
             settingsButton.setVisibility(VISIBLE);
@@ -473,7 +453,7 @@
         }
     }
 
-    private void addTransitionImage(ImageView transitionImage) {
+    private void updateTransitionImage(ImageView transitionImage) {
         if (getCurrentState() == STATE_TRANSITION) {
             transitionImage.setVisibility(VISIBLE);
         } else {
@@ -497,7 +477,10 @@
                                 return LinearSmoothScroller.SNAP_TO_END;
                             }
                         };
-                smoothScroller.setTargetPosition(i);
+                // If privateSpaceHidden() then the entire container decorator will be invisible and
+                // we can directly move to an element above the header. There should always be one
+                // element, as PS is present in the bottom of All Apps.
+                smoothScroller.setTargetPosition(isPrivateSpaceHidden() ? i - 1 : i);
                 RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
                 if (layoutManager != null) {
                     startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
@@ -619,8 +602,11 @@
                 float newAlpha = (float) valueAnimator.getAnimatedValue();
                 for (int i = 0; i < allAppsAdapterItems.size(); i++) {
                     BaseAllAppsAdapter.AdapterItem currentItem = allAppsAdapterItems.get(i);
+                    // When not hidden: Fade all PS items except header.
+                    // When hidden: Fade all items.
                     if (isPrivateSpaceItem(currentItem) &&
-                            currentItem.viewType != VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                            (currentItem.viewType != VIEW_TYPE_PRIVATE_SPACE_HEADER
+                                    || isPrivateSpaceHidden())) {
                         RecyclerView.ViewHolder viewHolder =
                                 allAppsRecyclerView.findViewHolderForAdapterPosition(i);
                         if (viewHolder != null) {
@@ -702,10 +688,9 @@
                     translateFloatingMaskView(false));
         } else {
             if (isPrivateSpaceHidden()) {
-                animatorSet.playSequentially(translateFloatingMaskView(false),
-                        animateAlphaOfIcons(false),
-                        animateCollapseAnimation(),
-                        fadeOutHeaderAlpha());
+                animatorSet.playSequentially(animateAlphaOfIcons(false),
+                        animateAlphaOfPrivateSpaceContainer(),
+                        animateCollapseAnimation());
             } else {
                 animatorSet.playSequentially(translateFloatingMaskView(true),
                         animateAlphaOfIcons(false),
@@ -715,22 +700,23 @@
         animatorSet.start();
     }
 
-    /** Fades out the private space container. */
-    private ValueAnimator fadeOutHeaderAlpha() {
-        if (mPSHeader == null) {
-            return new ValueAnimator();
-        }
-        float from = 1;
-        float to = 0;
-        ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
-        alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
-        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                if (mPSHeader != null) {
-                    mPSHeader.setAlpha((float) valueAnimator.getAnimatedValue());
+    /** Fades out the private space container (defined by its items' decorators). */
+    private ValueAnimator animateAlphaOfPrivateSpaceContainer() {
+        int from = 255; // 100% opacity.
+        int to = 0; // No opacity.
+        ValueAnimator alphaAnim = ObjectAnimator.ofInt(from, to);
+        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+        List<BaseAllAppsAdapter.AdapterItem> allAppsAdapterItems =
+                allAppsRecyclerView.getApps().getAdapterItems();
+        alphaAnim.setDuration(CONTAINER_OPACITY_DURATION);
+        alphaAnim.addUpdateListener(valueAnimator -> {
+            for (BaseAllAppsAdapter.AdapterItem currentItem : allAppsAdapterItems) {
+                if (isPrivateSpaceItem(currentItem)) {
+                    currentItem.setDecorationFillAlpha((int) valueAnimator.getAnimatedValue());
                 }
             }
+            // Invalidate the parent view, to redraw the decorations with changed alpha.
+            allAppsRecyclerView.invalidate();
         });
         return alphaAnim;
     }
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt
index ec8c9c2..63833e4 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt
@@ -32,7 +32,7 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito
-import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.whenever
 
 @SmallTest
@@ -51,20 +51,21 @@
         deviceProfile =
             Mockito.spy(LauncherAppState.getIDP(context).getDeviceProfile(context).copy(context))
 
-        doAnswer {
-                return@doAnswer 0.8f
-            }
-            .whenever(deviceProfile)
-            .getWorkspaceSpringLoadScale(any(Context::class.java))
-        whenever(deviceProfile.cellSize).thenReturn(Point(CELL_SIZE, CELL_SIZE))
+        doReturn(0.8f)
+                .whenever(deviceProfile).getWorkspaceSpringLoadScale(any(Context::class.java))
         deviceProfile.cellLayoutBorderSpacePx = Point(CELL_SPACING, CELL_SPACING)
         deviceProfile.widgetPadding.setEmpty()
     }
 
     @Test
     fun getWidgetDragScalePx_largeDraggedView_downScaled() {
+        val minSize = context.resources.getDimensionPixelSize(
+                R.dimen.widget_drag_view_min_scale_down_size)
+        whenever(deviceProfile.cellSize).thenReturn(Point(minSize * 2, minSize * 2))
+
         itemInfo.spanX = 2
         itemInfo.spanY = 2
+
         val widgetSize = WidgetSizes.getWidgetSizePx(deviceProfile, itemInfo.spanX, itemInfo.spanY)
         // Assume dragged view was a drawable which was larger than widget's size.
         val draggedViewWidthPx = widgetSize.width + 0.5f * widgetSize.width
@@ -84,6 +85,9 @@
 
     @Test
     fun getWidgetDragScalePx_draggedViewSameAsWidgetSize_downScaled() {
+        val minSize = context.resources.getDimensionPixelSize(
+                R.dimen.widget_drag_view_min_scale_down_size)
+        whenever(deviceProfile.cellSize).thenReturn(Point(minSize * 2, minSize * 2))
         itemInfo.spanX = 4
         itemInfo.spanY = 2
 
@@ -109,14 +113,13 @@
 
     @Test
     fun getWidgetDragScalePx_draggedViewSmallerThanMinSize_scaledSizeIsAtLeastMinSize() {
-        itemInfo.spanX = 1
-        itemInfo.spanY = 1
         val minSizePx =
             context.resources.getDimensionPixelSize(R.dimen.widget_drag_view_min_scale_down_size)
-
         // Assume min size is greater than cell size, so that, we know the upscale of dragged view
         // is due to min size enforcement.
-        assumeTrue(minSizePx > CELL_SIZE)
+        whenever(deviceProfile.cellSize).thenReturn(Point(minSizePx / 2, minSizePx / 2))
+        itemInfo.spanX = 1
+        itemInfo.spanY = 1
 
         val draggedViewWidthPx = minSizePx - 15f
         val draggedViewHeightPx = minSizePx - 15f
@@ -142,7 +145,6 @@
     }
 
     companion object {
-        const val CELL_SIZE = 60
         const val CELL_SPACING = 10
     }
 }
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 4cd2a07..5c50e97 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -130,7 +130,7 @@
     public void lockPrivateProfile_requestsQuietModeAsTrue() throws Exception {
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(false);
 
-        mPrivateProfileManager.lockPrivateProfile();
+        mPrivateProfileManager.setQuietMode(true /* lock */);
 
         awaitTasksCompleted();
         Mockito.verify(mUserManager).requestQuietModeEnabled(true, PRIVATE_HANDLE);
@@ -140,7 +140,7 @@
     public void unlockPrivateProfile_requestsQuietModeAsFalse() throws Exception {
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(true);
 
-        mPrivateProfileManager.unlockPrivateProfile();
+        mPrivateProfileManager.setQuietMode(false /* unlock */);
 
         awaitTasksCompleted();
         Mockito.verify(mUserManager).requestQuietModeEnabled(false, PRIVATE_HANDLE);
@@ -176,7 +176,7 @@
         doNothing().when(privateProfileManager).expandPrivateSpace();
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
 
-        privateProfileManager.unlockPrivateProfile();
+        privateProfileManager.setQuietMode(false /* unlock */);
         privateProfileManager.reset();
 
         awaitTasksCompleted();
@@ -194,7 +194,7 @@
         doNothing().when(privateProfileManager).expandPrivateSpace();
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
 
-        privateProfileManager.lockPrivateProfile();
+        privateProfileManager.setQuietMode(true /* lock */);
         privateProfileManager.reset();
 
         awaitTasksCompleted();
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 512b2ac..eac7f63 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -133,7 +133,7 @@
         Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
-        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -168,7 +168,7 @@
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
         when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
-        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -210,7 +210,7 @@
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
         when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
-        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -248,7 +248,7 @@
         Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
-        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;