Merge changes I7c303e66,Idc03b9d3 into main

* changes:
  Add floatingMaskView when animating to mimic bottom container.
  Add private_space_floating_mask_view flag.
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 31d8d34..b243922 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -42,3 +42,11 @@
     description: "This flag disables drag and drop for Private Space Items."
     bug: "289223923"
 }
+
+
+flag {
+    name: "private_space_floating_mask_view"
+    namespace: "launcher_search"
+    description: "This flag enables the floating mask view as part of the Private Space animation. "
+    bug: "339850589"
+}
diff --git a/res/drawable/bg_ps_mask_left_corner.xml b/res/drawable/bg_ps_mask_left_corner.xml
new file mode 100644
index 0000000..43eeedb
--- /dev/null
+++ b/res/drawable/bg_ps_mask_left_corner.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector
+            android:viewportWidth="28"
+            android:viewportHeight="28"
+            android:width="@dimen/ps_floating_mask_corner_radius"
+            android:height="@dimen/ps_floating_mask_corner_radius">
+            <path
+                android:pathData="M0 28H28C24.3228 28 20.6821 27.2759 17.2847 25.8687C13.8877 24.4614 10.8013 22.3989 8.20117 19.7988C5.60107 17.1987 3.53857 14.1123 2.13135 10.7153C0.724121 7.31787 0 3.67725 0 0V28Z"
+                android:fillType="evenOdd"
+                android:fillColor="?attr/allAppsScrimColor" />
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/bg_ps_mask_right_corner.xml b/res/drawable/bg_ps_mask_right_corner.xml
new file mode 100644
index 0000000..d63b866
--- /dev/null
+++ b/res/drawable/bg_ps_mask_right_corner.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector
+            android:viewportWidth="28"
+            android:viewportHeight="28"
+            android:width="@dimen/ps_floating_mask_corner_radius"
+            android:height="@dimen/ps_floating_mask_corner_radius">
+            <path
+                android:pathData="M28 28V0C28 3.67725 27.2759 7.31787 25.8687 10.7153C24.4614 14.1123 22.3989 17.1987 19.7988 19.7988C17.1987 22.3989 14.1123 24.4614 10.7153 25.8687C7.31787 27.2759 3.67725 28 0 28H28Z"
+                android:fillType="evenOdd"
+                android:fillColor="?attr/allAppsScrimColor" />
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/layout/private_space_mask_view.xml b/res/layout/private_space_mask_view.xml
new file mode 100644
index 0000000..44e2797
--- /dev/null
+++ b/res/layout/private_space_mask_view.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<com.android.launcher3.allapps.FloatingMaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_alignParentBottom="true"
+    android:layout_marginLeft="@dimen/ps_floating_mask_end_padding"
+    android:layout_marginRight="@dimen/ps_floating_mask_end_padding"
+    android:importantForAccessibility="noHideDescendants"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/left_corner"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="parent"
+        android:importantForAccessibility="no"
+        android:background="@drawable/bg_ps_mask_left_corner"/>
+
+    <ImageView
+        android:id="@+id/right_corner"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:scaleType="centerCrop"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:importantForAccessibility="no"
+        android:background="@drawable/bg_ps_mask_right_corner"/>
+
+    <ImageView
+        android:id="@+id/bottom_box"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="@id/left_corner"
+        app:layout_constraintEnd_toEndOf="@id/right_corner"
+        app:layout_constraintTop_toBottomOf="@id/left_corner"
+        android:importantForAccessibility="no"
+        android:background="?attr/allAppsScrimColor"/>
+
+</com.android.launcher3.allapps.FloatingMaskView>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 54edab4..74fadda 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -536,6 +536,8 @@
     <dimen name="ps_lock_icon_text_margin_start_expanded">8dp</dimen>
     <dimen name="ps_lock_icon_text_margin_end_expanded">6dp</dimen>
     <dimen name="ps_lock_button_background_padding">10dp</dimen>
+    <dimen name="ps_floating_mask_corner_radius">28dp</dimen>
+    <dimen name="ps_floating_mask_end_padding">16dp</dimen>
 
     <!-- WindowManagerProxy -->
     <dimen name="max_width_and_height_of_small_display_cutout">136px</dimen>
diff --git a/src/com/android/launcher3/allapps/FloatingMaskView.java b/src/com/android/launcher3/allapps/FloatingMaskView.java
new file mode 100644
index 0000000..606eb03
--- /dev/null
+++ b/src/com/android/launcher3/allapps/FloatingMaskView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.views.ActivityContext;
+
+public class FloatingMaskView extends ConstraintLayout {
+
+    private final ActivityContext mActivityContext;
+    private ImageView mBottomBox;
+
+    public FloatingMaskView(Context context) {
+        this(context, null, 0);
+    }
+
+    public FloatingMaskView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FloatingMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mActivityContext = ActivityContext.lookupContext(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBottomBox = findViewById(R.id.bottom_box);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
+        AllAppsRecyclerView allAppsContainerView =
+                mActivityContext.getAppsView().getActiveRecyclerView();
+        if (lp != null) {
+            lp.rightMargin = allAppsContainerView.getPaddingRight();
+            lp.leftMargin = allAppsContainerView.getPaddingLeft();
+            mBottomBox.setMinimumHeight(allAppsContainerView.getPaddingBottom());
+        }
+    }
+}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 53f9cfc..27340a3 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -60,6 +60,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.recyclerview.widget.LinearSmoothScroller;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -96,14 +97,17 @@
     private static final int TEXT_UNLOCK_OPACITY_DURATION = 300;
     private static final int TEXT_LOCK_OPACITY_DURATION = 50;
     private static final int APP_OPACITY_DURATION = 400;
+    private static final int MASK_VIEW_DURATION = 200;
     private static final int APP_OPACITY_DELAY = 400;
     private static final int SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY = 400;
     private static final int SETTINGS_OPACITY_DELAY = 400;
     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 final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
     private final int mPsHeaderHeight;
+    private final int mFloatingMaskViewCornerRadius;
     private final RecyclerView.OnScrollListener mOnIdleScrollListener =
             new RecyclerView.OnScrollListener() {
         @Override
@@ -123,6 +127,7 @@
     private Runnable mOnPSHeaderAdded;
     @Nullable
     private RelativeLayout mPSHeader;
+    private ConstraintLayout mFloatingMaskView;
     private final String mLockedStateContentDesc;
     private final String mUnLockedStateContentDesc;
 
@@ -142,6 +147,8 @@
                 .getString(R.string.ps_container_lock_button_content_description);
         mUnLockedStateContentDesc = mAllApps.getContext()
                 .getString(R.string.ps_container_unlock_button_content_description);
+        mFloatingMaskViewCornerRadius = mAllApps.getContext().getResources().getDimensionPixelSize(
+                R.dimen.ps_floating_mask_corner_radius);
     }
 
     /** Adds Private Space Header to the layout. */
@@ -219,6 +226,7 @@
                 .hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
         int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
         setCurrentState(updatedState);
+        mFloatingMaskView = null;
         if (mPSHeader != null) {
             mPSHeader.setAlpha(1);
         }
@@ -494,12 +502,15 @@
                 RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
                 if (layoutManager != null) {
                     startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
-                    currentItem.decorationInfo = null;
+                    // Preserve decorator if floating mask view exists.
+                    if (mFloatingMaskView == null) {
+                        currentItem.decorationInfo = null;
+                    }
                 }
                 break;
             }
             // Make the private space apps gone to "collapse".
-            if (isPrivateSpaceItem(currentItem)) {
+            if (mFloatingMaskView == null && isPrivateSpaceItem(currentItem)) {
                 RecyclerView.ViewHolder viewHolder =
                         allAppsRecyclerView.findViewHolderForAdapterPosition(i);
                 if (viewHolder != null) {
@@ -637,6 +648,7 @@
             setAnimationRunning(false);
             return;
         }
+        attachFloatingMaskView(expand);
         ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
         if (settingsAndLockGroup.getLayoutTransition() == null) {
             // Set a new transition if the current ViewGroup does not already contain one as each
@@ -662,6 +674,11 @@
                 mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
                 setAnimationRunning(true);
             }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                detachFloatingMaskView();
+            }
         });
         animatorSet.addListener(forEndCallback(() -> {
             setAnimationRunning(false);
@@ -681,13 +698,17 @@
             }
         }));
         if (expand) {
-            animatorSet.playTogether(animateAlphaOfIcons(true));
+            animatorSet.playTogether(animateAlphaOfIcons(true),
+                    translateFloatingMaskView(false));
         } else {
             if (isPrivateSpaceHidden()) {
-                animatorSet.playSequentially(animateAlphaOfIcons(false),
-                        animateCollapseAnimation(), fadeOutHeaderAlpha());
+                animatorSet.playSequentially(translateFloatingMaskView(false),
+                        animateAlphaOfIcons(false),
+                        animateCollapseAnimation(),
+                        fadeOutHeaderAlpha());
             } else {
-                animatorSet.playSequentially(animateAlphaOfIcons(false),
+                animatorSet.playSequentially(translateFloatingMaskView(true),
+                        animateAlphaOfIcons(false),
                         animateCollapseAnimation());
             }
         }
@@ -715,6 +736,27 @@
         return alphaAnim;
     }
 
+    /** Fades out the private space container. */
+    private ValueAnimator translateFloatingMaskView(boolean animateIn) {
+        if (!Flags.privateSpaceFloatingMaskView() || mFloatingMaskView == null) {
+            return new ValueAnimator();
+        }
+        // Translate base on the height amount. Translates out on expand and in on collapse.
+        float floatingMaskViewHeight = getFloatingMaskViewHeight();
+        float from = animateIn ? floatingMaskViewHeight : 0;
+        float to = animateIn ? 0 : floatingMaskViewHeight;
+        ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+        alphaAnim.setDuration(MASK_VIEW_DURATION);
+        alphaAnim.setStartDelay(MASK_VIEW_DELAY);
+        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                mFloatingMaskView.setTranslationY((float) valueAnimator.getAnimatedValue());
+            }
+        });
+        return alphaAnim;
+    }
+
     /** Animates the layout changes when the text of the button becomes visible/gone. */
     private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
         LayoutTransition settingsAndLockTransition = new LayoutTransition();
@@ -806,6 +848,28 @@
         });
     }
 
+    private void attachFloatingMaskView(boolean expand) {
+        if (!Flags.privateSpaceFloatingMaskView()) {
+            return;
+        }
+        mFloatingMaskView = (FloatingMaskView) mAllApps.getLayoutInflater().inflate(
+                R.layout.private_space_mask_view, mAllApps, false);
+        mAllApps.addView(mFloatingMaskView);
+        // Translate off the screen first if its collapsing so this header view isn't visible to
+        // user when animation starts.
+        if (!expand) {
+            mFloatingMaskView.setTranslationY(getFloatingMaskViewHeight());
+        }
+        mFloatingMaskView.setVisibility(VISIBLE);
+    }
+
+    private void detachFloatingMaskView() {
+        if (mFloatingMaskView != null) {
+            mAllApps.removeView(mFloatingMaskView);
+        }
+        mFloatingMaskView = null;
+    }
+
     /** Starts the smooth scroll with the provided smoothScroller and add idle listener. */
     private void startAnimationScroll(AllAppsRecyclerView allAppsRecyclerView,
             RecyclerView.LayoutManager layoutManager, RecyclerView.SmoothScroller smoothScroller) {
@@ -815,6 +879,10 @@
         allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
     }
 
+    private float getFloatingMaskViewHeight() {
+        return mFloatingMaskViewCornerRadius + getMainRecyclerView().getPaddingBottom();
+    }
+
     AllAppsRecyclerView getMainRecyclerView() {
         return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
     }