Enabling Private Space Container in Launcher.

This CL adds the following:
1. Adds filtering and addition of Private Profile apps in main user
all apps recycler view
2. Enables decoration of Private Profile apps
3. Enables hiding Private Space container based upon a settings entry.

Flag: ACONFIG com.android.launcher3.Flags.enable_private_space DEVELOPMENT
Bug: 289223923
Test: Ran Launcher3 tests
Change-Id: I33dc55a3a39e75d3fc336ca6a488b282e2dd322c
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 34bfdb7..9a19526 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -25,6 +25,7 @@
 import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
+import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -166,6 +167,8 @@
         onNotificationSettingsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI));
         mOnTerminateCallback.add(() ->
                 settingsCache.unregister(NOTIFICATION_BADGING_URI, notificationLister));
+        // Register an observer to notify Launcher about Private Space settings toggle.
+        registerPrivateSpaceHideWhenLockListener(settingsCache);
     }
 
     public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
@@ -188,6 +191,18 @@
         }
     }
 
+    private void registerPrivateSpaceHideWhenLockListener(SettingsCache settingsCache) {
+        SettingsCache.OnChangeListener psHideWhenLockChangedListener =
+                this::onPrivateSpaceHideWhenLockChanged;
+        settingsCache.register(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, psHideWhenLockChangedListener);
+        mOnTerminateCallback.add(() -> settingsCache.unregister(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI,
+                psHideWhenLockChangedListener));
+    }
+
+    private void onPrivateSpaceHideWhenLockChanged(boolean isPrivateSpaceHideOnLockEnabled) {
+        mModel.forceReload();
+    }
+
     private void refreshAndReloadLauncher() {
         LauncherIcons.clearPool();
         mIconCache.updateIconParams(
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 7d52cbb..bd3740c 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.allapps;
 
 import static com.android.launcher3.Flags.enableExpandingPauseWorkButton;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
@@ -69,6 +70,7 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
@@ -95,6 +97,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 /**
  * All apps container view with search support for use in a dragging activity.
@@ -133,6 +136,7 @@
     protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
             Process.myUserHandle());
     protected WorkProfileManager mWorkManager;
+    protected final PrivateProfileManager mPrivateProfileManager;
     protected final Point mFastScrollerOffset = new Point();
     protected final int mScrimColor;
     protected final float mHeaderThreshold;
@@ -175,6 +179,7 @@
     protected SearchAdapterProvider<?> mMainAdapterProvider;
     private View mBottomSheetHandleArea;
     private boolean mHasWorkApps;
+    private boolean mHasPrivateApps;
     private float[] mBottomSheetCornerRadii;
     private ScrimView mScrimView;
     private int mHeaderColor;
@@ -184,6 +189,8 @@
     private int mTabsProtectionAlpha;
     @Nullable private AllAppsTransitionController mAllAppsTransitionController;
 
+    private PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
+
     public ActivityAllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -207,6 +214,11 @@
                 this,
                 mActivityContext.getStatsLogManager(),
                 UserCache.INSTANCE.get(mActivityContext));
+        mPrivateProfileManager = new PrivateProfileManager(
+                mActivityContext.getSystemService(UserManager.class),
+                this,
+                mActivityContext.getStatsLogManager(),
+                UserCache.INSTANCE.get(mActivityContext));
         mAH = Arrays.asList(null, null, null);
         mNavBarScrimPaint = new Paint();
         mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
@@ -246,13 +258,20 @@
      */
     protected void initContent() {
         mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
+        if (Flags.enablePrivateSpace()) {
+            mPrivateSpaceHeaderViewController =
+                    new PrivateSpaceHeaderViewController(mPrivateProfileManager);
+        }
 
         mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
-                new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore, null)));
+                new AlphabeticalAppsList<>(mActivityContext,
+                        mAllAppsStore,
+                        null,
+                        mPrivateProfileManager)));
         mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK,
-                new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore, mWorkManager)));
+                new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore, mWorkManager, null)));
         mAH.set(SEARCH, new AdapterHolder(SEARCH,
-                new AlphabeticalAppsList<>(mActivityContext, null, null)));
+                new AlphabeticalAppsList<>(mActivityContext, null, null, null)));
 
         getLayoutInflater().inflate(R.layout.all_apps_content, this);
         mHeader = findViewById(R.id.all_apps_header);
@@ -592,7 +611,7 @@
         } else {
             mainRecyclerView = findViewById(R.id.apps_list_view);
             workRecyclerView = null;
-            mAH.get(AdapterHolder.MAIN).setup(mainRecyclerView, null);
+            mAH.get(AdapterHolder.MAIN).setup(mainRecyclerView, mPersonalMatcher);
             mAH.get(AdapterHolder.WORK).mRecyclerView = null;
         }
         setUpCustomRecyclerViewPool(
@@ -860,7 +879,7 @@
 
     protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList) {
         return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
-                mMainAdapterProvider);
+                mMainAdapterProvider, mPrivateSpaceHeaderViewController);
     }
 
     // TODO(b/216683257): Remove when Taskbar All Apps supports search.
@@ -973,13 +992,19 @@
 
     @VisibleForTesting
     public void onAppsUpdated() {
-        mHasWorkApps = mWorkManager.hasWorkApps();
+        mHasWorkApps = Stream.of(mAllAppsStore.getApps())
+                .anyMatch(mWorkManager.getItemInfoMatcher());
+        mHasPrivateApps = Stream.of(mAllAppsStore.getApps())
+                .anyMatch(mPrivateProfileManager.getItemInfoMatcher());
         if (!isSearching()) {
             rebindAdapters();
         }
         if (mHasWorkApps) {
             mWorkManager.reset();
         }
+        if (mHasPrivateApps) {
+            mPrivateProfileManager.reset();
+        }
 
         mActivityContext.getStatsLogManager().logger()
                 .withCardinality(mAllAppsStore.getApps().length)
@@ -1245,6 +1270,10 @@
         return mAH.get(SEARCH).mAppsList;
     }
 
+    public AlphabeticalAppsList<T> getPersonalAppList() {
+        return mAH.get(MAIN).mAppsList;
+    }
+
     public FloatingHeaderView getFloatingHeaderView() {
         return mHeader;
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index df383bf..5f002b5 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -73,8 +73,9 @@
 
 
     public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
-            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider) {
-        super(activityContext, inflater, apps, adapterProvider);
+            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider,
+            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
+        super(activityContext, inflater, apps, adapterProvider, privateSpaceHeaderViewController);
         mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
         mGridLayoutMgr.setSpanSizeLookup(new GridSpanSizer());
         setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index ee4b5bc..328516e 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -20,6 +20,7 @@
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.DiffUtil;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -47,6 +48,8 @@
 
     private final WorkProfileManager mWorkProviderManager;
 
+    private final PrivateProfileManager mPrivateProviderManager;
+
     /**
      * Info about a fast scroller section, depending if sections are merged, the fast scroller
      * sections will not be the same set as the section headers.
@@ -68,6 +71,7 @@
 
     // The set of apps from the system
     private final List<AppInfo> mApps = new ArrayList<>();
+    private final List<AppInfo> mPrivateApps = new ArrayList<>();
     @Nullable
     private final AllAppsStore<T> mAllAppsStore;
 
@@ -87,11 +91,12 @@
     private Predicate<ItemInfo> mItemFilter;
 
     public AlphabeticalAppsList(Context context, @Nullable AllAppsStore<T> appsStore,
-            WorkProfileManager workProfileManager) {
+            WorkProfileManager workProfileManager, PrivateProfileManager privateProfileManager) {
         mAllAppsStore = appsStore;
         mActivityContext = ActivityContext.lookupContext(context);
         mAppNameComparator = new AppInfoComparator(context);
         mWorkProviderManager = workProfileManager;
+        mPrivateProviderManager = privateProfileManager;
         mNumAppsPerRowAllApps = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
         if (mAllAppsStore != null) {
             mAllAppsStore.addUpdateListener(this);
@@ -197,12 +202,20 @@
         }
         // Sort the list of apps
         mApps.clear();
+        mPrivateApps.clear();
 
         Stream<AppInfo> appSteam = Stream.of(mAllAppsStore.getApps());
+        Stream<AppInfo> privateAppStream = Stream.of(mAllAppsStore.getApps());
+
         if (!hasSearchResults() && mItemFilter != null) {
             appSteam = appSteam.filter(mItemFilter);
+            if (mPrivateProviderManager != null) {
+                privateAppStream = privateAppStream
+                        .filter(mPrivateProviderManager.getItemInfoMatcher());
+            }
         }
         appSteam = appSteam.sorted(mAppNameComparator);
+        privateAppStream = privateAppStream.sorted(mAppNameComparator);
 
         // As a special case for some languages (currently only Simplified Chinese), we may need to
         // coalesce sections
@@ -221,6 +234,7 @@
         }
 
         appSteam.forEachOrdered(mApps::add);
+        privateAppStream.forEachOrdered(mPrivateApps::add);
         // Recompose the set of adapter items from the current set of apps
         if (mSearchResults.isEmpty()) {
             updateAdapterItems();
@@ -250,18 +264,10 @@
                 addApps = mWorkProviderManager.shouldShowWorkApps();
             }
             if (addApps) {
-                String lastSectionName = null;
-                for (AppInfo info : mApps) {
-                    mAdapterItems.add(AdapterItem.asApp(info));
-
-                    String sectionName = info.sectionName;
-                    // Create a new section if the section names do not match
-                    if (!sectionName.equals(lastSectionName)) {
-                        lastSectionName = sectionName;
-                        mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
-                    }
-                    position++;
-                }
+                addAppsWithSections(mApps, position);
+            }
+            if (Flags.enablePrivateSpace()) {
+                addPrivateSpaceItems(position);
             }
         }
         mAccessibilityResultsCount = (int) mAdapterItems.stream()
@@ -275,7 +281,8 @@
             int rowIndex = -1;
             for (AdapterItem item : mAdapterItems) {
                 item.rowIndex = 0;
-                if (BaseAllAppsAdapter.isDividerViewType(item.viewType)) {
+                if (BaseAllAppsAdapter.isDividerViewType(item.viewType)
+                        || BaseAllAppsAdapter.isPrivateSpaceHeaderView(item.viewType)) {
                     numAppsInSection = 0;
                 } else if (BaseAllAppsAdapter.isIconViewType(item.viewType)) {
                     if (numAppsInSection % mNumAppsPerRowAllApps == 0) {
@@ -297,6 +304,40 @@
         }
     }
 
+    void addPrivateSpaceItems(int position) {
+        if (mPrivateProviderManager != null
+                && !mPrivateProviderManager.isPrivateSpaceHidden()
+                && !mPrivateApps.isEmpty()) {
+            // Always add PS Header if Space is present and visible.
+            position += mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+            int privateSpaceState = mPrivateProviderManager.getCurrentState();
+            switch (privateSpaceState) {
+                case PrivateProfileManager.STATE_DISABLED:
+                case PrivateProfileManager.STATE_TRANSITION:
+                    break;
+                case PrivateProfileManager.STATE_ENABLED:
+                    // Add PS Apps only in Enabled State.
+                    addAppsWithSections(mPrivateApps, position);
+                    break;
+            }
+        }
+    }
+
+    private void addAppsWithSections(List<AppInfo> appList, int startPosition) {
+        String lastSectionName = null;
+        for (AppInfo info : appList) {
+            mAdapterItems.add(AdapterItem.asApp(info));
+
+            String sectionName = info.sectionName;
+            // Create a new section if the section names do not match
+            if (!sectionName.equals(lastSectionName)) {
+                lastSectionName = sectionName;
+                mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, startPosition));
+            }
+            startPosition++;
+        }
+    }
+
     private static class MyDiffCallback extends DiffUtil.Callback {
 
         private final List<AdapterItem> mOldList;
@@ -328,4 +369,4 @@
         }
     }
 
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index bce38a3..5e26ea5 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -22,6 +22,7 @@
 import android.view.View.OnFocusChangeListener;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import androidx.recyclerview.widget.RecyclerView;
@@ -139,9 +140,16 @@
     protected final OnClickListener mOnIconClickListener;
     protected final OnLongClickListener mOnIconLongClickListener;
     protected OnFocusChangeListener mIconFocusListener;
+    private final PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
 
     public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
             AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
+        this(activityContext, inflater, apps, adapterProvider, null);
+    }
+
+    public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
+            AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider,
+            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
         mActivityContext = activityContext;
         mApps = apps;
         mLayoutInflater = inflater;
@@ -150,6 +158,7 @@
         mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
 
         mAdapterProvider = adapterProvider;
+        mPrivateSpaceHeaderViewController = privateSpaceHeaderViewController;
     }
 
     /** Checks if the passed viewType represents all apps divider. */
@@ -162,6 +171,11 @@
         return isViewType(viewType, VIEW_TYPE_MASK_ICON);
     }
 
+    /** Checks if the passed viewType represents private space header. */
+    public static boolean isPrivateSpaceHeaderView(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER);
+    }
+
     public void setIconFocusListener(OnFocusChangeListener focusListener) {
         mIconFocusListener = focusListener;
     }
@@ -230,6 +244,12 @@
                 break;
             }
             case VIEW_TYPE_PRIVATE_SPACE_HEADER:
+                RelativeLayout psHeaderLayout = holder.itemView.findViewById(
+                        R.id.ps_header_layout);
+                assert mPrivateSpaceHeaderViewController != null;
+                assert psHeaderLayout != null;
+                mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout);
+                break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
             case VIEW_TYPE_WORK_DISABLED_CARD:
                 // nothing to do
diff --git a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
index f7c9058..f4ed754 100644
--- a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
@@ -42,20 +42,19 @@
     private final RectF mTmpRect = new RectF();
     private final Context mContext;
     private final AlphabeticalAppsList<?> mAppsList;
-    private final PrivateProfileManager mPrivateProfileManager;
     private final UserCache mUserCache;
     private final Paint mPaint;
+    private final int mCornerRadius;
 
-    public PrivateAppsSectionDecorator(ActivityAllAppsContainerView<?> appsContainerView,
-            AlphabeticalAppsList<?> appsList,
-            PrivateProfileManager privateProfileManager) {
+    public PrivateAppsSectionDecorator(Context context, AlphabeticalAppsList<?> appsList) {
+        mContext = context;
         mAppsList = appsList;
-        mPrivateProfileManager = privateProfileManager;
-        mContext = appsContainerView.mActivityContext;
-        mUserCache = UserCache.getInstance(appsContainerView.mActivityContext);
+        mUserCache = UserCache.getInstance(context);
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPaint.setColor(ContextCompat.getColor(mContext,
+        mPaint.setColor(ContextCompat.getColor(context,
                 R.color.material_color_surface_container_high));
+        mCornerRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.ps_container_corner_radius);
     }
 
     /** Decorates Private Space Header and Icon Rows to give the shape of a container. */
@@ -70,9 +69,7 @@
             int position = parent.getChildAdapterPosition(view);
             BaseAllAppsAdapter.AdapterItem adapterItem = mAppsList.getAdapterItems().get(position);
             // Rectangle that covers the bottom half of the PS Header View when Space is unlocked.
-            if (adapterItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER
-                    && mPrivateProfileManager
-                    .getCurrentState() == PrivateProfileManager.STATE_ENABLED) {
+            if (adapterItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
                 // We flatten the bottom corners of the rectangle, so that it merges with
                 // the private space app row decorator.
                 mTmpRect.set(
@@ -103,9 +100,8 @@
                 iconView.getBottom());
         // Decorates last app row with rounded bottom corners.
         if (adapterPosition + numCol >= mAppsList.getAdapterItems().size()) {
-            int corner = mContext.getResources().getDimensionPixelSize(
-                    R.dimen.ps_container_corner_radius);
-            float[] mCornersBot = new float[]{0, 0, 0, 0, corner, corner, corner, corner};
+            float[] mCornersBot = new float[]{0, 0, 0, 0, mCornerRadius, mCornerRadius,
+                    mCornerRadius, mCornerRadius};
             mTmpPath.addRoundRect(mTmpRect, mCornersBot, Path.Direction.CW);
         } else {
             // Decorate other rows as a plain rectangle
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index ec01aee..3e73c6a 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
+import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
 
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -29,6 +30,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SettingsCache;
 
 import java.util.ArrayList;
 import java.util.function.Predicate;
@@ -44,11 +46,12 @@
     private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
     private final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
+    private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
 
     public PrivateProfileManager(UserManager userManager,
-            UserCache userCache,
-            ActivityAllAppsContainerView allApps,
-            StatsLogManager statsLogManager) {
+            ActivityAllAppsContainerView<?> allApps,
+            StatsLogManager statsLogManager,
+            UserCache userCache) {
         super(userManager, statsLogManager, userCache);
         mAllApps = allApps;
         mPrivateProfileMatcher = (user) -> userCache.getUserInfo(user).isPrivate();
@@ -75,9 +78,8 @@
 
     /** Whether private profile should be hidden on Launcher. */
     public boolean isPrivateSpaceHidden() {
-        // TODO (b/289223923): Update this when we are able to read PsSettingsFlag
-        //  from SettingsProvider.
-        return false;
+        return getCurrentState() == STATE_DISABLED && SettingsCache.INSTANCE
+                    .get(mAllApps.mActivityContext).getValue(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, 0);
     }
 
     /** Resets the current state of Private Profile, w.r.t. to Launcher. */
@@ -86,6 +88,7 @@
                 .hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
         int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
         setCurrentState(updatedState);
+        resetPrivateSpaceDecorator(updatedState);
     }
 
     /** Opens the Private Space Settings Entry Point. */
@@ -102,11 +105,29 @@
         Preconditions.assertNonUiThread();
         Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
         psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
-        ResolveInfo resolveInfo = mAllApps.getContext().getPackageManager()
+        ResolveInfo resolveInfo = mAllApps.mActivityContext.getPackageManager()
                 .resolveActivity(psSettingsIntent, PackageManager.MATCH_SYSTEM_ONLY);
         return resolveInfo != null;
     }
 
+    void resetPrivateSpaceDecorator(int updatedState) {
+        if (updatedState == STATE_ENABLED) {
+            // Add Private Space Decorator to the Recycler view.
+            if (mPrivateAppsSectionDecorator == null) {
+                mPrivateAppsSectionDecorator = new PrivateAppsSectionDecorator(
+                        mAllApps.mActivityContext,
+                        mAllApps.mAH.get(MAIN).mAppsList);
+            }
+            mAllApps.mAH.get(MAIN).mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
+        } else {
+            // Remove Private Space Decorator from the Recycler view.
+            if (mPrivateAppsSectionDecorator != null) {
+                mAllApps.mAH.get(MAIN).mRecyclerView
+                        .removeItemDecoration(mPrivateAppsSectionDecorator);
+            }
+        }
+    }
+
     /** Posts quiet mode enable/disable call for private profile. */
     private void enableQuietMode(boolean enable) {
         setQuietMode(enable);
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
index 9420b4c..c49d0b1 100644
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
 import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
 import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import android.view.View;
 import android.widget.ImageButton;
@@ -49,7 +50,7 @@
         //Add image and action for private space settings button
         ImageButton settingsButton = parent.findViewById(R.id.ps_settings_button);
         assert settingsButton != null;
-        addPrivateSpaceSettingsButton(settingsButton);
+        UI_HELPER_EXECUTOR.post(() -> addPrivateSpaceSettingsButton(settingsButton));
 
         //Add image for private space transitioning view
         ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
diff --git a/src/com/android/launcher3/util/SettingsCache.java b/src/com/android/launcher3/util/SettingsCache.java
index 29ec5ab..2ab6dc3 100644
--- a/src/com/android/launcher3/util/SettingsCache.java
+++ b/src/com/android/launcher3/util/SettingsCache.java
@@ -55,6 +55,9 @@
     /** Hidden field Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED */
     public static final String ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED =
             "swipe_bottom_to_notification_enabled";
+    /** Hidden field Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT */
+    public static final Uri PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI =
+            Settings.Secure.getUriFor("hide_privatespace_entry_point");
     public static final Uri ROTATION_SETTING_URI =
             Settings.System.getUriFor(ACCELEROMETER_ROTATION);
 
diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
new file mode 100644
index 0000000..259f519
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.allapps;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.Flags;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.util.ActivityContextWrapper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+@RunWith(AndroidJUnit4.class)
+public class AlphabeticalAppsListTest {
+
+    private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
+    private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+
+    private static final int PRIVATE_SPACE_HEADER_ITEM_COUNT = 1;
+    private static final int MAIN_USER_APP_COUNT = 2;
+    private static final int PRIVATE_USER_APP_COUNT = 1;
+
+    private AlphabeticalAppsList<?> mAlphabeticalAppsList;
+    @Mock
+    private AllAppsStore<?> mAllAppsStore;
+    @Mock
+    private PrivateProfileManager mPrivateProfileManager;
+    private Context mContext;
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule =
+            new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = new ActivityContextWrapper(getApplicationContext());
+        when(mPrivateProfileManager.getItemInfoMatcher()).thenReturn(info ->
+                info != null && info.user.equals(PRIVATE_HANDLE));
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, mPrivateProfileManager);
+    }
+
+    @Test
+    public void privateProfileEnabled_allPrivateProfileViewsArePresent() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
+        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+                .thenAnswer(answer(this::addPrivateSpaceHeader));
+        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(MAIN_USER_APP_COUNT + PRIVATE_SPACE_HEADER_ITEM_COUNT
+                + PRIVATE_USER_APP_COUNT, mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(PRIVATE_SPACE_HEADER_ITEM_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size());
+        assertEquals(PRIVATE_USER_APP_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.itemInfo != null
+                                && item.itemInfo.user.equals(PRIVATE_HANDLE)).toList().size());
+    }
+
+    @Test
+    public void privateProfileDisabled_onlyPrivateProfileHeaderViewIsPresent() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
+        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+                .thenAnswer(answer(this::addPrivateSpaceHeader));
+        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(MAIN_USER_APP_COUNT + PRIVATE_SPACE_HEADER_ITEM_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(PRIVATE_SPACE_HEADER_ITEM_COUNT, mAlphabeticalAppsList
+                .getAdapterItems().stream().filter(item ->
+                        item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                item.itemInfo != null
+                        && item.itemInfo.user.equals(PRIVATE_HANDLE)).toList().size());
+    }
+
+    @Test
+    public void privateProfileTransitioning_onlyPrivateProfileHeaderViewIsPresent() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
+        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+                .thenAnswer(answer(this::addPrivateSpaceHeader));
+        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(MAIN_USER_APP_COUNT + PRIVATE_SPACE_HEADER_ITEM_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(PRIVATE_SPACE_HEADER_ITEM_COUNT, mAlphabeticalAppsList
+                .getAdapterItems().stream().filter(item ->
+                        item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                item.itemInfo != null
+                        && item.itemInfo.user.equals(PRIVATE_HANDLE)).toList().size());
+    }
+
+    @Test
+    public void privateProfileHidden_noPrivateProfileViewIsPresent() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
+        when(mPrivateProfileManager.isPrivateSpaceHidden()).thenReturn(true);
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(MAIN_USER_APP_COUNT, mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                item.itemInfo != null
+                        && item.itemInfo.user.equals(PRIVATE_HANDLE)).toList().size());
+    }
+
+    @Test
+    public void privateProfileNotPresent_onlyMainUserViewsArePresent() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainUser());
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(2, mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.itemInfo != null
+                                && item.itemInfo.itemType == VIEW_TYPE_PRIVATE_SPACE_HEADER)
+                .toList().size());
+        assertEquals(0, mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.itemInfo != null && item.itemInfo.user.equals(PRIVATE_HANDLE))
+                .toList().size());
+    }
+
+    private int addPrivateSpaceHeader(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
+        adapterItemList.add(new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_PRIVATE_SPACE_HEADER));
+        return adapterItemList.size();
+    }
+
+    private AppInfo[] createAppInfoListForMainUser() {
+        ComponentName gmailComponentName = new ComponentName(mContext,
+                "com.android.launcher3.tests.Activity" + "Gmail");
+        AppInfo gmailAppInfo = new
+                AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
+        ComponentName driveComponentName = new ComponentName(mContext,
+                "com.android.launcher3.tests.Activity" + "Drive");
+        AppInfo driveAppInfo = new
+                AppInfo(driveComponentName, "Drive", MAIN_HANDLE, new Intent());
+        return new AppInfo[]{gmailAppInfo, driveAppInfo};
+    }
+
+    private AppInfo[] createAppInfoListForPrivateUser() {
+        ComponentName privateMessengercomponentName = new ComponentName(mContext,
+                "com.android.launcher3.tests.Activity" + "PrivateMessenger");
+        AppInfo privateMessengerAppInfo = new AppInfo(privateMessengercomponentName,
+                "Private Messenger", PRIVATE_HANDLE, new Intent());
+        return new AppInfo[]{privateMessengerAppInfo};
+    }
+
+    private AppInfo[] createAppInfoListForMainAndPrivateUser() {
+        return Stream.concat(Arrays.stream(createAppInfoListForMainUser()),
+                Arrays.stream(createAppInfoListForPrivateUser())).toArray(AppInfo[]::new);
+    }
+
+}
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index bfa9241..f461c8c 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -22,6 +22,9 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -82,8 +85,8 @@
         when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
         when(mActivityAllAppsContainerView.getContext()).thenReturn(mContext);
         when(mActivityAllAppsContainerView.getAppsStore()).thenReturn(mAllAppsStore);
-        mPrivateProfileManager = new PrivateProfileManager(mUserManager, mUserCache,
-                mActivityAllAppsContainerView, mStatsLogManager);
+        mPrivateProfileManager = new PrivateProfileManager(mUserManager,
+                mActivityAllAppsContainerView, mStatsLogManager, mUserCache);
     }
 
     @Test
@@ -108,16 +111,18 @@
 
     @Test
     public void quietModeFlagPresent_privateSpaceIsResetToDisabled() {
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(false, true);
 
         // In first call the state should be disabled.
-        mPrivateProfileManager.reset();
-        assertEquals(STATE_ENABLED, mPrivateProfileManager.getCurrentState());
+        privateProfileManager.reset();
+        assertEquals(STATE_ENABLED, privateProfileManager.getCurrentState());
 
         // In the next call the state should be disabled.
-        mPrivateProfileManager.reset();
-        assertEquals(STATE_DISABLED, mPrivateProfileManager.getCurrentState());
+        privateProfileManager.reset();
+        assertEquals(STATE_DISABLED, privateProfileManager.getCurrentState());
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
index 87adaa1..ea8be3f 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
@@ -75,11 +76,12 @@
     }
 
     @Test
-    public void privateProfileDisabled_psHeaderContainsLockedView() {
+    public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
         Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.bg_ps_unlock_button));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
 
         mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
         int totalLockUnlockButtonView = 0;
@@ -102,13 +104,14 @@
     }
 
     @Test
-    public void privateProfileEnabled_psHeaderContainsUnlockedView() {
+    public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
         Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
         Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_settings_button));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
         when(mPrivateProfileManager.isPrivateSpaceSettingsButtonVisible()).thenReturn(true);
 
         mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
         int totalLockUnlockButtonView = 0;
@@ -138,12 +141,14 @@
     }
 
     @Test
-    public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView() {
+    public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
+            throws Exception {
         Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
         when(mPrivateProfileManager.isPrivateSpaceSettingsButtonVisible()).thenReturn(false);
 
         mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
         int totalLockUnlockButtonView = 0;
@@ -168,11 +173,12 @@
     }
 
     @Test
-    public void privateProfileTransitioning_psHeaderContainsTransitionView() {
+    public void privateProfileTransitioning_psHeaderContainsTransitionView() throws Exception {
         Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
 
         mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
         int totalLockUnlockButtonView = 0;
@@ -216,4 +222,8 @@
         }
         return result;
     }
+
+    private static void awaitTasksCompleted() throws Exception {
+        UI_HELPER_EXECUTOR.submit(() -> null).get();
+    }
 }