Loading src/com/android/launcher3/allapps/AlphabeticalAppsList.java +35 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING; import android.content.Context; import androidx.annotation.Nullable; Loading Loading @@ -318,6 +322,10 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement case PrivateProfileManager.STATE_ENABLED: // Add PS Apps only in Enabled State. addAppsWithSections(mPrivateApps, position); if (mActivityContext.getAppsView() != null) { mActivityContext.getAppsView().getActiveRecyclerView() .scrollToBottomWithMotion(); } break; } } Loading @@ -325,8 +333,34 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement private void addAppsWithSections(List<AppInfo> appList, int startPosition) { String lastSectionName = null; boolean hasPrivateApps = false; if (mPrivateProviderManager != null) { hasPrivateApps = appList.stream(). allMatch(mPrivateProviderManager.getItemInfoMatcher()); } int privateAppCount = 0; int numberOfColumns = mActivityContext.getDeviceProfile().numShownAllAppsColumns; int numberOfAppRows = (int) Math.ceil((double) appList.size() / numberOfColumns); for (AppInfo info : appList) { // Apply decorator to private apps. if (hasPrivateApps) { int roundRegion = ROUND_NOTHING; if ((privateAppCount / numberOfColumns) == numberOfAppRows - 1) { if ((privateAppCount % numberOfColumns) == 0) { // App is the first column roundRegion = ROUND_BOTTOM_LEFT; } else if ((privateAppCount % numberOfColumns) == numberOfColumns-1) { roundRegion = ROUND_BOTTOM_RIGHT; } } mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info, new SectionDecorationInfo(mActivityContext.getApplicationContext(), roundRegion, true /* decorateTogether */))); privateAppCount += 1; } else { mAdapterItems.add(AdapterItem.asApp(info)); } String sectionName = info.sectionName; // Create a new section if the section names do not match Loading src/com/android/launcher3/allapps/BaseAllAppsAdapter.java +22 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_RIGHT; import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED; import android.content.Context; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -108,6 +114,13 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex return item; } public static AdapterItem asAppWithDecorationInfo(AppInfo appInfo, SectionDecorationInfo decorationInfo) { AdapterItem item = asApp(appInfo); item.decorationInfo = decorationInfo; return item; } protected boolean isCountedForAccessibility() { return viewType == VIEW_TYPE_ICON; } Loading Loading @@ -259,6 +272,15 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex assert mPrivateSpaceHeaderViewController != null; assert psHeaderLayout != null; mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout); AdapterItem adapterItem = mApps.getAdapterItems().get(position); int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT; if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) { roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT); } adapterItem.decorationInfo = new SectionDecorationInfo(mActivityContext, roundRegions, false /* decorateTogether */); break; case VIEW_TYPE_ALL_APPS_DIVIDER: case VIEW_TYPE_WORK_DISABLED_CARD: Loading src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java +24 −66 Original line number Diff line number Diff line Loading @@ -16,97 +16,55 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.view.View; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; import com.android.launcher3.pm.UserCache; import com.android.launcher3.views.ActivityContext; import java.util.HashMap; /** * Decorator which changes the background color for Private Space Icon Rows in AllAppsContainer. */ public class PrivateAppsSectionDecorator extends RecyclerView.ItemDecoration { private final Path mTmpPath = new Path(); private final RectF mTmpRect = new RectF(); private final Context mContext; private static final String PRIVATE_APP_SECTION = "private_apps"; private final AlphabeticalAppsList<?> mAppsList; private final UserCache mUserCache; private final Paint mPaint; private final int mCornerRadius; public PrivateAppsSectionDecorator(Context context, AlphabeticalAppsList<?> appsList) { mContext = context; public PrivateAppsSectionDecorator(AlphabeticalAppsList<?> appsList) { mAppsList = appsList; mUserCache = UserCache.getInstance(context); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 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. */ @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { mTmpPath.reset(); mTmpRect.setEmpty(); int numCol = ActivityContext.lookupContext(mContext).getDeviceProfile() .numShownAllAppsColumns; HashMap<String, SectionDecorationHandler.UnionDecorationHandler> deferredDecorations = new HashMap<>(); for (int i = 0; i < parent.getChildCount(); i++) { View view = parent.getChildAt(i); 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) { // We flatten the bottom corners of the rectangle, so that it merges with // the private space app row decorator. mTmpRect.set( view.getLeft(), view.getTop() + (float) (view.getBottom() - view.getTop()) / 2, view.getRight(), view.getBottom()); mTmpPath.addRect(mTmpRect, Path.Direction.CW); c.drawPath(mTmpPath, mPaint); } else if (adapterItem.viewType == VIEW_TYPE_ICON && mUserCache.getUserInfo(adapterItem.itemInfo.user).isPrivate() // No decoration for any private space app icon other than those at first row. && adapterItem.rowAppIndex == 0) { c.drawPath(getPrivateAppRowPath(parent, view, position, numCol), mPaint); SectionDecorationInfo info = adapterItem.decorationInfo; if (info == null) { continue; } SectionDecorationHandler decorationHandler = info.getDecorationHandler(); if (info.shouldDecorateItemsTogether()) { SectionDecorationHandler.UnionDecorationHandler unionHandler = deferredDecorations.getOrDefault( PRIVATE_APP_SECTION, new SectionDecorationHandler.UnionDecorationHandler( decorationHandler, parent.getPaddingLeft(), parent.getPaddingRight())); unionHandler.addChild(decorationHandler, view, true /* applyBackground */); deferredDecorations.put(PRIVATE_APP_SECTION, unionHandler); } else { decorationHandler.onFocusDraw(c, view); } } /** Returns the path to be decorated for Private Space App Row */ private Path getPrivateAppRowPath(RecyclerView parent, View iconView, int adapterPosition, int numCol) { // We always decorate the entire app row here. // As the iconView just represents the first icon of the row, we get the right margin of // our decorator using the parent view. mTmpRect.set(iconView.getLeft(), iconView.getTop(), parent.getRight() - parent.getPaddingRight(), iconView.getBottom()); // Decorates last app row with rounded bottom corners. if (adapterPosition + numCol >= mAppsList.getAdapterItems().size()) { 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 mTmpPath.addRect(mTmpRect, Path.Direction.CW); for (SectionDecorationHandler.UnionDecorationHandler decorationHandler : deferredDecorations.values()) { decorationHandler.onGroupDecorate(c); } return mTmpPath; } } src/com/android/launcher3/allapps/PrivateProfileManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.UserManager; import androidx.annotation.VisibleForTesting; import com.android.launcher3.Flags; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.pm.UserCache; import com.android.launcher3.util.Preconditions; Loading @@ -47,6 +48,7 @@ public class PrivateProfileManager extends UserProfileManager { private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER; private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key"; private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal"; private static final int ANIMATION_DURATION = 2000; private final ActivityAllAppsContainerView<?> mAllApps; private final Predicate<UserHandle> mPrivateProfileMatcher; private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator; Loading Loading @@ -125,7 +127,6 @@ public class PrivateProfileManager extends UserProfileManager { // Create a new decorator instance if not already available. if (mPrivateAppsSectionDecorator == null) { mPrivateAppsSectionDecorator = new PrivateAppsSectionDecorator( mAllApps.mActivityContext, mainAdapterHolder.mAppsList); } for (int i = 0; i < mainAdapterHolder.mRecyclerView.getItemDecorationCount(); i++) { Loading @@ -137,6 +138,13 @@ public class PrivateProfileManager extends UserProfileManager { } // Add Private Space Decorator to the Recycler view. mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator); if (Flags.privateSpaceAnimation() && mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) { RecyclerViewAnimationController recyclerViewAnimationController = new RecyclerViewAnimationController(mAllApps); recyclerViewAnimationController.animateToState(true /* expand */, ANIMATION_DURATION, () -> {}); } } else { // Remove Private Space Decorator from the Recycler view. if (mPrivateAppsSectionDecorator != null) { Loading src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java +4 −0 Original line number Diff line number Diff line Loading @@ -105,4 +105,8 @@ public class PrivateSpaceHeaderViewController { transitionImage.setVisibility(View.GONE); } } PrivateProfileManager getPrivateProfileManager() { return mPrivateProfileManager; } } Loading
src/com/android/launcher3/allapps/AlphabeticalAppsList.java +35 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING; import android.content.Context; import androidx.annotation.Nullable; Loading Loading @@ -318,6 +322,10 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement case PrivateProfileManager.STATE_ENABLED: // Add PS Apps only in Enabled State. addAppsWithSections(mPrivateApps, position); if (mActivityContext.getAppsView() != null) { mActivityContext.getAppsView().getActiveRecyclerView() .scrollToBottomWithMotion(); } break; } } Loading @@ -325,8 +333,34 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement private void addAppsWithSections(List<AppInfo> appList, int startPosition) { String lastSectionName = null; boolean hasPrivateApps = false; if (mPrivateProviderManager != null) { hasPrivateApps = appList.stream(). allMatch(mPrivateProviderManager.getItemInfoMatcher()); } int privateAppCount = 0; int numberOfColumns = mActivityContext.getDeviceProfile().numShownAllAppsColumns; int numberOfAppRows = (int) Math.ceil((double) appList.size() / numberOfColumns); for (AppInfo info : appList) { // Apply decorator to private apps. if (hasPrivateApps) { int roundRegion = ROUND_NOTHING; if ((privateAppCount / numberOfColumns) == numberOfAppRows - 1) { if ((privateAppCount % numberOfColumns) == 0) { // App is the first column roundRegion = ROUND_BOTTOM_LEFT; } else if ((privateAppCount % numberOfColumns) == numberOfColumns-1) { roundRegion = ROUND_BOTTOM_RIGHT; } } mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info, new SectionDecorationInfo(mActivityContext.getApplicationContext(), roundRegion, true /* decorateTogether */))); privateAppCount += 1; } else { mAdapterItems.add(AdapterItem.asApp(info)); } String sectionName = info.sectionName; // Create a new section if the section names do not match Loading
src/com/android/launcher3/allapps/BaseAllAppsAdapter.java +22 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ */ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_RIGHT; import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED; import android.content.Context; import android.view.LayoutInflater; import android.view.View; Loading Loading @@ -108,6 +114,13 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex return item; } public static AdapterItem asAppWithDecorationInfo(AppInfo appInfo, SectionDecorationInfo decorationInfo) { AdapterItem item = asApp(appInfo); item.decorationInfo = decorationInfo; return item; } protected boolean isCountedForAccessibility() { return viewType == VIEW_TYPE_ICON; } Loading Loading @@ -259,6 +272,15 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex assert mPrivateSpaceHeaderViewController != null; assert psHeaderLayout != null; mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout); AdapterItem adapterItem = mApps.getAdapterItems().get(position); int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT; if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) { roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT); } adapterItem.decorationInfo = new SectionDecorationInfo(mActivityContext, roundRegions, false /* decorateTogether */); break; case VIEW_TYPE_ALL_APPS_DIVIDER: case VIEW_TYPE_WORK_DISABLED_CARD: Loading
src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java +24 −66 Original line number Diff line number Diff line Loading @@ -16,97 +16,55 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.view.View; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; import com.android.launcher3.pm.UserCache; import com.android.launcher3.views.ActivityContext; import java.util.HashMap; /** * Decorator which changes the background color for Private Space Icon Rows in AllAppsContainer. */ public class PrivateAppsSectionDecorator extends RecyclerView.ItemDecoration { private final Path mTmpPath = new Path(); private final RectF mTmpRect = new RectF(); private final Context mContext; private static final String PRIVATE_APP_SECTION = "private_apps"; private final AlphabeticalAppsList<?> mAppsList; private final UserCache mUserCache; private final Paint mPaint; private final int mCornerRadius; public PrivateAppsSectionDecorator(Context context, AlphabeticalAppsList<?> appsList) { mContext = context; public PrivateAppsSectionDecorator(AlphabeticalAppsList<?> appsList) { mAppsList = appsList; mUserCache = UserCache.getInstance(context); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 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. */ @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { mTmpPath.reset(); mTmpRect.setEmpty(); int numCol = ActivityContext.lookupContext(mContext).getDeviceProfile() .numShownAllAppsColumns; HashMap<String, SectionDecorationHandler.UnionDecorationHandler> deferredDecorations = new HashMap<>(); for (int i = 0; i < parent.getChildCount(); i++) { View view = parent.getChildAt(i); 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) { // We flatten the bottom corners of the rectangle, so that it merges with // the private space app row decorator. mTmpRect.set( view.getLeft(), view.getTop() + (float) (view.getBottom() - view.getTop()) / 2, view.getRight(), view.getBottom()); mTmpPath.addRect(mTmpRect, Path.Direction.CW); c.drawPath(mTmpPath, mPaint); } else if (adapterItem.viewType == VIEW_TYPE_ICON && mUserCache.getUserInfo(adapterItem.itemInfo.user).isPrivate() // No decoration for any private space app icon other than those at first row. && adapterItem.rowAppIndex == 0) { c.drawPath(getPrivateAppRowPath(parent, view, position, numCol), mPaint); SectionDecorationInfo info = adapterItem.decorationInfo; if (info == null) { continue; } SectionDecorationHandler decorationHandler = info.getDecorationHandler(); if (info.shouldDecorateItemsTogether()) { SectionDecorationHandler.UnionDecorationHandler unionHandler = deferredDecorations.getOrDefault( PRIVATE_APP_SECTION, new SectionDecorationHandler.UnionDecorationHandler( decorationHandler, parent.getPaddingLeft(), parent.getPaddingRight())); unionHandler.addChild(decorationHandler, view, true /* applyBackground */); deferredDecorations.put(PRIVATE_APP_SECTION, unionHandler); } else { decorationHandler.onFocusDraw(c, view); } } /** Returns the path to be decorated for Private Space App Row */ private Path getPrivateAppRowPath(RecyclerView parent, View iconView, int adapterPosition, int numCol) { // We always decorate the entire app row here. // As the iconView just represents the first icon of the row, we get the right margin of // our decorator using the parent view. mTmpRect.set(iconView.getLeft(), iconView.getTop(), parent.getRight() - parent.getPaddingRight(), iconView.getBottom()); // Decorates last app row with rounded bottom corners. if (adapterPosition + numCol >= mAppsList.getAdapterItems().size()) { 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 mTmpPath.addRect(mTmpRect, Path.Direction.CW); for (SectionDecorationHandler.UnionDecorationHandler decorationHandler : deferredDecorations.values()) { decorationHandler.onGroupDecorate(c); } return mTmpPath; } }
src/com/android/launcher3/allapps/PrivateProfileManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.UserManager; import androidx.annotation.VisibleForTesting; import com.android.launcher3.Flags; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.pm.UserCache; import com.android.launcher3.util.Preconditions; Loading @@ -47,6 +48,7 @@ public class PrivateProfileManager extends UserProfileManager { private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER; private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key"; private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal"; private static final int ANIMATION_DURATION = 2000; private final ActivityAllAppsContainerView<?> mAllApps; private final Predicate<UserHandle> mPrivateProfileMatcher; private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator; Loading Loading @@ -125,7 +127,6 @@ public class PrivateProfileManager extends UserProfileManager { // Create a new decorator instance if not already available. if (mPrivateAppsSectionDecorator == null) { mPrivateAppsSectionDecorator = new PrivateAppsSectionDecorator( mAllApps.mActivityContext, mainAdapterHolder.mAppsList); } for (int i = 0; i < mainAdapterHolder.mRecyclerView.getItemDecorationCount(); i++) { Loading @@ -137,6 +138,13 @@ public class PrivateProfileManager extends UserProfileManager { } // Add Private Space Decorator to the Recycler view. mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator); if (Flags.privateSpaceAnimation() && mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) { RecyclerViewAnimationController recyclerViewAnimationController = new RecyclerViewAnimationController(mAllApps); recyclerViewAnimationController.animateToState(true /* expand */, ANIMATION_DURATION, () -> {}); } } else { // Remove Private Space Decorator from the Recycler view. if (mPrivateAppsSectionDecorator != null) { Loading
src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java +4 −0 Original line number Diff line number Diff line Loading @@ -105,4 +105,8 @@ public class PrivateSpaceHeaderViewController { transitionImage.setVisibility(View.GONE); } } PrivateProfileManager getPrivateProfileManager() { return mPrivateProfileManager; } }