Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98bf9f75 authored by Brandon Dayauon's avatar Brandon Dayauon
Browse files

Apply the expand animation on Private Space

- Using the refactoring that took place in ag/25414154

Bug: 299294792
Test: Verified SearchTransitionController didn't regress by turning off BACKGROUND_DRAWABLES flag.
- Verified QL highlight still works
- video: https://drive.google.com/file/d/15yjBWofebn6m7VgEnLK6kEYqhC_adJQ3/view?usp=sharing

Flag: ACONFIG com.android.launcher3.Flags.private_space_animation DEVELOPMENT

Change-Id: Ib6229b404b48616966f3e6ab6884099b6e4b4023
parent 96901c45
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
            }
        }
@@ -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
+22 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
        }
@@ -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:
+24 −66
Original line number Diff line number Diff line
@@ -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;
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -128,7 +130,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++) {
@@ -140,6 +141,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) {
+4 −0
Original line number Diff line number Diff line
@@ -93,4 +93,8 @@ public class PrivateSpaceHeaderViewController {
            transitionImage.setVisibility(View.GONE);
        }
    }

    PrivateProfileManager getPrivateProfileManager() {
        return mPrivateProfileManager;
    }
}