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

Commit d952a88d authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6118234 from c0f06941 to rvc-release

Change-Id: I8d6890e5dd9ee211fa52d63cbb773b23328a4863
parents 4f5f6d78 c0f06941
Loading
Loading
Loading
Loading
+0 −119
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.shortcuts;

import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;

import com.android.launcher3.ItemInfo;
import com.android.launcher3.notification.NotificationKeyData;

import java.util.ArrayList;
import java.util.List;

/**
 * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
 */
public class DeepShortcutManager {

    private static final DeepShortcutManager sInstance = new DeepShortcutManager();

    public static DeepShortcutManager getInstance(Context context) {
        return sInstance;
    }

    private final QueryResult mFailure = new QueryResult();

    private DeepShortcutManager() { }

    /**
     * Queries for the shortcuts with the package name and provided ids.
     *
     * This method is intended to get the full details for shortcuts when they are added or updated,
     * because we only get "key" fields in onShortcutsChanged().
     */
    public QueryResult queryForFullDetails(String packageName,
            List<String> shortcutIds, UserHandle user) {
        return mFailure;
    }

    /**
     * Gets all the manifest and dynamic shortcuts associated with the given package and user,
     * to be displayed in the shortcuts container on long press.
     */
    public QueryResult queryForShortcutsContainer(ComponentName activity,
            UserHandle user) {
        return mFailure;
    }

    /**
     * Removes the given shortcut from the current list of pinned shortcuts.
     * (Runs on background thread)
     */
    public void unpinShortcut(final ShortcutKey key) {
    }

    /**
     * Adds the given shortcut to the current list of pinned shortcuts.
     * (Runs on background thread)
     */
    public void pinShortcut(final ShortcutKey key) {
    }

    public void startShortcut(String packageName, String id, Rect sourceBounds,
            Bundle startActivityOptions, UserHandle user) {
    }

    public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
        return null;
    }

    /**
     * Returns the id's of pinned shortcuts associated with the given package and user.
     *
     * If packageName is null, returns all pinned shortcuts regardless of package.
     */
    public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
        return mFailure;
    }

    public QueryResult queryForPinnedShortcuts(String packageName,
            List<String> shortcutIds, UserHandle user) {
        return mFailure;
    }

    public QueryResult queryForAllShortcuts(UserHandle user) {
        return mFailure;
    }

    public boolean hasHostPermission() {
        return false;
    }


    public static class QueryResult extends ArrayList<ShortcutInfo> {

        public boolean wasSuccess() {
            return true;
        }
    }
}
+0 −8
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:inset="@dimen/predicted_icon_background_inset">
    <shape>
        <solid android:color="?attr/folderFillColor" />
        <corners android:radius="@dimen/predicted_icon_background_corner_radius" />
    </shape>
</inset>
+101 −32
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -61,7 +62,7 @@ import java.util.stream.IntStream;
public class HotseatPredictionController implements DragController.DragListener,
        View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>,
        InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener,
        IconCache.ItemInfoUpdateReceiver {
        IconCache.ItemInfoUpdateReceiver, DragSource {

    private static final String TAG = "PredictiveHotseat";
    private static final boolean DEBUG = false;
@@ -72,6 +73,9 @@ public class HotseatPredictionController implements DragController.DragListener,
    private static final String APP_LOCATION_HOTSEAT = "hotseat";
    private static final String APP_LOCATION_WORKSPACE = "workspace";

    private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps";
    private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps";

    private static final String PREDICTION_CLIENT = "hotseat";

    private DropTarget.DragObject mDragObject;
@@ -79,7 +83,7 @@ public class HotseatPredictionController implements DragController.DragListener,
    private int mPredictedSpotsCount = 0;

    private Launcher mLauncher;
    private Hotseat mHotseat;
    private final Hotseat mHotseat;

    private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();

@@ -87,10 +91,18 @@ public class HotseatPredictionController implements DragController.DragListener,

    private AppPredictor mAppPredictor;
    private AllAppsStore mAllAppsStore;
    private AnimatorSet mIconRemoveAnimators;


    private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();

    private static HotseatPredictionController sInstance;
    private final View.OnLongClickListener mPredictionLongClickListener = v -> {
        if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
        if (mLauncher.getWorkspace().isSwitchingState()) return false;
        // Start the drag
        mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
        return false;
    };

    public HotseatPredictionController(Launcher launcher) {
        mLauncher = launcher;
@@ -101,7 +113,9 @@ public class HotseatPredictionController implements DragController.DragListener,
        mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
        launcher.getDeviceProfile().inv.addOnChangeListener(this);
        mHotseat.addOnAttachStateChangeListener(this);
        sInstance = this;
        if (mHotseat.isAttachedToWindow()) {
            onViewAttachedToWindow(mHotseat);
        }
    }

    @Override
@@ -125,6 +139,17 @@ public class HotseatPredictionController implements DragController.DragListener,
        List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
        int predictionIndex = 0;
        ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>();
        // make sure predicted icon removal and filling predictions don't step on each other
        if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) {
            mIconRemoveAnimators.addListener(new AnimationSuccessListener() {
                @Override
                public void onAnimationSuccess(Animator animator) {
                    fillGapsWithPrediction(animate, callback);
                    mIconRemoveAnimators.removeListener(this);
                }
            });
            return;
        }
        for (int rank = 0; rank < mHotSeatItemsCount; rank++) {
            View child = mHotseat.getChildAt(
                    mHotseat.getCellXFromOrder(rank),
@@ -140,12 +165,11 @@ public class HotseatPredictionController implements DragController.DragListener,
                }
                continue;
            }

            WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++);
            if (isPredictedIcon(child) && child.isEnabled()) {
                PredictedAppIcon icon = (PredictedAppIcon) child;
                icon.applyFromWorkspaceItem(predictedItem);
                icon.finishBinding();
                icon.finishBinding(mPredictionLongClickListener);
            } else {
                newItems.add(predictedItem);
            }
@@ -160,7 +184,7 @@ public class HotseatPredictionController implements DragController.DragListener,
        for (WorkspaceItemInfo item : itemsToAdd) {
            PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
            mLauncher.getWorkspace().addInScreenFromBind(icon, item);
            icon.finishBinding();
            icon.finishBinding(mPredictionLongClickListener);
            if (animate) {
                animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1));
            }
@@ -215,9 +239,9 @@ public class HotseatPredictionController implements DragController.DragListener,

    private Bundle getAppPredictionContextExtra() {
        Bundle bundle = new Bundle();
        bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT,
        bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
                getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets())));
        bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup(
        bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup(
                mLauncher.getWorkspace().getScreenWithId(
                        Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets()));
        return bundle;
@@ -285,9 +309,12 @@ public class HotseatPredictionController implements DragController.DragListener,
            ItemInfoWithIcon info = mapper.getApp(allAppsStore);
            if (info instanceof AppInfo) {
                WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info);
                predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
                predictedApps.add(predictedApp);
            } else if (info instanceof WorkspaceItemInfo) {
                predictedApps.add(new WorkspaceItemInfo((WorkspaceItemInfo) info));
                WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info);
                predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
                predictedApps.add(predictedApp);
            } else {
                if (DEBUG) {
                    Log.e(TAG, "Predicted app not found: " + mapper);
@@ -313,13 +340,27 @@ public class HotseatPredictionController implements DragController.DragListener,
        return icons;
    }

    private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) {
    private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines,
            ItemInfo draggedInfo) {
        if (mIconRemoveAnimators != null) {
            mIconRemoveAnimators.end();
        }
        mIconRemoveAnimators = new AnimatorSet();
        removeOutlineDrawings();
        for (PredictedAppIcon icon : getPredictedIcons()) {
            if (!icon.isEnabled()) {
                continue;
            }
            if (icon.getTag().equals(draggedInfo)) {
                mHotseat.removeView(icon);
                continue;
            }
            int rank = ((WorkspaceItemInfo) icon.getTag()).rank;
            outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing(
                    mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon));
            icon.setEnabled(false);
            icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() {
            ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0);
            animator.addListener(new AnimationSuccessListener() {
                @Override
                public void onAnimationSuccess(Animator animator) {
                    if (icon.getParent() != null) {
@@ -327,10 +368,11 @@ public class HotseatPredictionController implements DragController.DragListener,
                    }
                }
            });
            mIconRemoveAnimators.play(animator);
        }
        mIconRemoveAnimators.start();
    }


    private void notifyItemAction(AppTarget target, String location, int action) {
        if (mAppPredictor != null) {
            mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target,
@@ -340,7 +382,7 @@ public class HotseatPredictionController implements DragController.DragListener,

    @Override
    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
        removePredictedApps(mOutlineDrawings);
        removePredictedApps(mOutlineDrawings, dragObject.dragInfo);
        mDragObject = dragObject;
        if (mOutlineDrawings.isEmpty()) return;
        for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
@@ -354,15 +396,26 @@ public class HotseatPredictionController implements DragController.DragListener,
        if (mDragObject == null) {
            return;
        }

        ItemInfo dragInfo = mDragObject.dragInfo;
        if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) {
        ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets();
        ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId(
                Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets();

        if (dragInfo instanceof WorkspaceItemInfo
                && dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                && dragInfo.getTargetComponent() != null) {
            AppTarget appTarget = getAppTargetFromItemInfo(dragInfo);
            if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) {
                if (!getPinnedAppTargetsInViewGroup(hotseatVG).contains(appTarget)) {
                    notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN);
                }
            }
            if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) {
                if (!getPinnedAppTargetsInViewGroup(firstScreenVG).contains(appTarget)) {
                    notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN);
                }
            }
            if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) {
                notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN);
            }
@@ -371,14 +424,7 @@ public class HotseatPredictionController implements DragController.DragListener,
            }
        }
        mDragObject = null;
        fillGapsWithPrediction(true, () -> {
            if (mOutlineDrawings.isEmpty()) return;
            for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
                mHotseat.removeDelegatedCellDrawing(outlineDrawing);
            }
            mHotseat.invalidate();
            mOutlineDrawings.clear();
        });
        fillGapsWithPrediction(true, this::removeOutlineDrawings);
    }

    @Nullable
@@ -394,11 +440,20 @@ public class HotseatPredictionController implements DragController.DragListener,
    private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) {
        itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
        itemInfo.rank = rank;
        itemInfo.cellX = rank;
        itemInfo.cellY = mHotSeatItemsCount - rank - 1;
        itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
        itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
        itemInfo.screenId = rank;
    }

    private void removeOutlineDrawings() {
        if (mOutlineDrawings.isEmpty()) return;
        for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
            mHotseat.removeDelegatedCellDrawing(outlineDrawing);
        }
        mHotseat.invalidate();
        mOutlineDrawings.clear();
    }

    @Override
    public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
        this.mHotSeatItemsCount = profile.numHotseatIcons;
@@ -415,6 +470,17 @@ public class HotseatPredictionController implements DragController.DragListener,

    }

    @Override
    public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
        //Does nothing
    }

    @Override
    public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
            LauncherLogProto.Target targetParent) {
        mHotseat.fillInLogContainerData(v, info, target, targetParent);
    }

    private class PinPrediction extends SystemShortcut<QuickstepLauncher> {

        private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
@@ -435,18 +501,22 @@ public class HotseatPredictionController implements DragController.DragListener,
     */
    public static void fillInHybridHotseatRank(
            @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
        if (sInstance == null || itemInfo.getTargetComponent() == null
        QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
        if (launcher == null || launcher.getHotseatPredictionController() == null
                || itemInfo.getTargetComponent() == null
                || itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
            return;
        }
        HotseatPredictionController controller = launcher.getHotseatPredictionController();

        final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);

        final List<ComponentKeyMapper> predictedApps = sInstance.mComponentKeyMappers;
        final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers;
        IntStream.range(0, predictedApps.size())
                .filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
                .findFirst()
                .ifPresent((rank) -> target.predictedRank =
                        Integer.parseInt(sInstance.mPredictedSpotsCount + "0" + rank));
                        Integer.parseInt(controller.mPredictedSpotsCount + "0" + rank));
    }

    private static boolean isPredictedIcon(View view) {
@@ -461,8 +531,7 @@ public class HotseatPredictionController implements DragController.DragListener,
        }
        ItemInfo info = (ItemInfo) view.getTag();
        return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && (
                info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                        || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
                info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
    }

    private static boolean isInHotseat(ItemInfo itemInfo) {
+2 −6
Original line number Diff line number Diff line
@@ -44,8 +44,8 @@ import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.InstantAppResolver;

import java.util.ArrayList;
@@ -167,11 +167,7 @@ public class DynamicItemCache {

    @WorkerThread
    private WorkspaceItemInfo loadShortcutWorker(ShortcutKey shortcutKey) {
        DeepShortcutManager mgr = DeepShortcutManager.getInstance(mContext);
        List<ShortcutInfo> details = mgr.queryForFullDetails(
                shortcutKey.componentName.getPackageName(),
                Collections.<String>singletonList(shortcutKey.getId()),
                shortcutKey.user);
        List<ShortcutInfo> details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL);
        if (!details.isEmpty()) {
            WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext);
            try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
+3 −12
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.view.ViewGroup;

import androidx.core.graphics.ColorUtils;

import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -37,7 +36,6 @@ import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
@@ -47,14 +45,13 @@ import com.android.launcher3.views.DoubleShadowBubbleTextView;
 */
public class PredictedAppIcon extends DoubleShadowBubbleTextView {

    private static final float RING_EFFECT_RATIO = 0.12f;
    private static final float RING_EFFECT_RATIO = 0.11f;

    private DeviceProfile mDeviceProfile;
    private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private boolean mIsPinned = false;
    private int mNormalizedIconRadius;


    public PredictedAppIcon(Context context) {
        this(context, null, 0);
    }
@@ -105,14 +102,8 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
    /**
     * prepares prediction icon for usage after bind
     */
    public void finishBinding() {
        setOnLongClickListener((v) -> {
            PopupContainerWithArrow.showForIcon((BubbleTextView) v);
            if (getParent() != null) {
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            return true;
        });
    public void finishBinding(OnLongClickListener longClickListener) {
        setOnLongClickListener(longClickListener);
        ((CellLayout.LayoutParams) getLayoutParams()).canReorder = false;
        setTextVisibility(false);
        verifyHighRes();
Loading