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

Commit 986a447e authored by Jon Miranda's avatar Jon Miranda Committed by Automerger Merge Worker
Browse files

Merge "Play return to icon animation if user swipes back to All Apps." into...

Merge "Play return to icon animation if user swipes back to All Apps." into sc-v2-dev am: 52ee4ec4 am: faedc900

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/16194658

Change-Id: If3e72442f3cd3b976d688ffef366a188683247fe
parents 5ec74a16 faedc900
Loading
Loading
Loading
Loading
+33 −31
Original line number Diff line number Diff line
@@ -1214,14 +1214,14 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
    }

    /**
     * Returns view on the workspace that corresponds to the closing app in the list of app targets
     * Returns view on launcher that corresponds to the closing app in the list of app targets
     */
    private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat[] appTargets) {
    private @Nullable View findLauncherView(RemoteAnimationTargetCompat[] appTargets) {
        for (RemoteAnimationTargetCompat appTarget : appTargets) {
            if (appTarget.mode == MODE_CLOSING) {
                View workspaceView = findWorkspaceView(appTarget);
                if (workspaceView != null) {
                    return workspaceView;
                View launcherView = findLauncherView(appTarget);
                if (launcherView != null) {
                    return launcherView;
                }
            }
        }
@@ -1229,9 +1229,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
    }

    /**
     * Returns view on the workspace that corresponds to the {@param runningTaskTarget}.
     * Returns view on launcher that corresponds to the {@param runningTaskTarget}.
     */
    private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat runningTaskTarget) {
    private @Nullable View findLauncherView(RemoteAnimationTargetCompat runningTaskTarget) {
        if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) {
            return null;
        }
@@ -1269,7 +1269,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
            }
        }

        return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
        return mLauncher.getFirstMatchForAppClose(launchCookieItemId,
                packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
    }

@@ -1292,7 +1292,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
     * Closing animator that animates the window into its final location on the workspace.
     */
    private void getClosingWindowAnimators(AnimatorSet animation,
            RemoteAnimationTargetCompat[] targets, View workspaceView) {
            RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS) {
        FloatingIconView floatingIconView = null;
        FloatingWidgetView floatingWidget = null;
        RectF targetRect = new RectF();
@@ -1308,17 +1308,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        }

        // Get floating view and target rect.
        if (workspaceView instanceof LauncherAppWidgetHostView) {
        if (launcherView instanceof LauncherAppWidgetHostView) {
            Size windowSize = new Size(mDeviceProfile.availableWidthPx,
                    mDeviceProfile.availableHeightPx);
            int fallbackBackgroundColor =
                    FloatingWidgetView.getDefaultBackgroundColor(mLauncher, runningTaskTarget);
            floatingWidget = FloatingWidgetView.getFloatingWidgetView(mLauncher,
                    (LauncherAppWidgetHostView) workspaceView, targetRect, windowSize,
                    (LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
                    mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
                    isTransluscent, fallbackBackgroundColor);
        } else if (workspaceView != null) {
            floatingIconView = getFloatingIconView(mLauncher, workspaceView,
        } else if (launcherView != null) {
            floatingIconView = getFloatingIconView(mLauncher, launcherView,
                    true /* hideOriginal */, targetRect, false /* isOpening */);
        } else {
            targetRect.set(getDefaultWindowTargetRect());
@@ -1373,15 +1373,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        }

        // Use a fixed velocity to start the animation.
        float velocityPxPerS = DynamicResource.provider(mLauncher)
                .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
        PointF velocity = new PointF(0, -velocityPxPerS);
        animation.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
                true /* animateOverviewScrim */, workspaceView).getAnimators());
        animation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                anim.start(mLauncher, velocity);
                anim.start(mLauncher, velocityPxPerS);
            }
        });
    }
@@ -1556,22 +1551,30 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
            if (anim == null) {
                anim = new AnimatorSet();

                View workspaceView = findWorkspaceView(appTargets);
                boolean isWorkspaceViewVisible = workspaceView != null
                        && !mLauncher.isInState(LauncherState.ALL_APPS)
                        && !mLauncher.getWorkspace().isOverlayShown();
                boolean playFallBackAnimation = !isWorkspaceViewVisible
                        && (launcherIsATargetWithMode(appTargets, MODE_OPENING)
                        || mLauncher.isForceInvisible());
                final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
                        || launcherIsATargetWithMode(appTargets, MODE_OPENING);

                View launcherView = findLauncherView(appTargets);
                boolean playFallBackAnimation = (launcherView == null
                        && launcherIsForceInvisibleOrOpening)
                        || mLauncher.getWorkspace().isOverlayShown();

                boolean playWorkspaceReveal = true;
                if (mFromUnlock) {
                    anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
                } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
                        && !playFallBackAnimation) {
                    getClosingWindowAnimators(anim, appTargets, workspaceView);
                    // Use a fixed velocity to start the animation.
                    float velocityPxPerS = DynamicResource.provider(mLauncher)
                            .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
                    PointF velocity = new PointF(0, -velocityPxPerS);
                    getClosingWindowAnimators(anim, appTargets, launcherView, velocity);
                    if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
                        anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
                                true /* animateOverviewScrim */, launcherView).getAnimators());
                        // We play StaggeredWorkspaceAnim as a part of the closing window animation.
                        playWorkspaceReveal = false;
                    }
                } else {
                    anim.play(getFallbackClosingWindowAnimators(appTargets));
                }
@@ -1584,8 +1587,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
                // targets list because it is already visible). In that case, we force
                // invisibility on touch down, and only reset it after the animation to home
                // is initialized.
                if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
                        || mLauncher.isForceInvisible()) {
                if (launcherIsForceInvisibleOrOpening) {
                    addCujInstrumentation(
                            anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
                    // Only register the content animation for cancellation when state changes
+1 −1
Original line number Diff line number Diff line
@@ -244,7 +244,7 @@ public class LauncherSwipeHandlerV2 extends
            }
        }

        return mActivity.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
        return mActivity.getFirstMatchForAppClose(launchCookieItemId,
                runningTaskView.getTask().key.getComponent().getPackageName(),
                UserHandle.of(runningTaskView.getTask().key.userId));
    }
+78 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -39,6 +40,7 @@ import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -55,6 +57,7 @@ import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -90,6 +93,7 @@ import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -215,6 +219,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -2676,6 +2681,79 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
        }
    }

    /**
     * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
     * animation.
     *
     * @param preferredItemId The id of the preferred item to match to if it exists.
     * @param packageName The package name of the app to match.
     * @param user The user of the app to match.
     */
    public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
        final ItemInfoMatcher preferredItem = (info, cn) ->
                info != null && info.id == preferredItemId;
        final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
                info != null
                        && info.itemType == ITEM_TYPE_APPLICATION
                        && info.user.equals(user)
                        && info.getTargetComponent() != null
                        && TextUtils.equals(info.getTargetComponent().getPackageName(),
                        packageName);

        if (isInState(LauncherState.ALL_APPS)) {
            return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
                    preferredItem, packageAndUserAndApp);
        } else {
            List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1);
            containers.add(mWorkspace.getHotseat().getShortcutsAndWidgets());
            mWorkspace.forEachVisiblePage(page
                    -> containers.add(((CellLayout) page).getShortcutsAndWidgets()));

            // Order: Preferred item by itself or in folder, then by matching package/user
            if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
                return getFirstMatch(containers, preferredItem, forFolderMatch(preferredItem),
                        packageAndUserAndApp, forFolderMatch(packageAndUserAndApp));
            } else {
                // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
                // FolderAdaptiveIcon as the background.
                return getFirstMatch(containers, preferredItem, packageAndUserAndApp);
            }
        }
    }

    /**
     * Finds the first view matching the ordered operators across the given viewgroups in order.
     * @param containers List of ViewGroups to scan, in order of preference.
     * @param operators List of operators, in order starting from best matching operator.
     */
    private static View getFirstMatch(Iterable<ViewGroup> containers,
            final ItemInfoMatcher... operators) {
        for (ItemInfoMatcher operator : operators) {
            for (ViewGroup container : containers) {
                View match = mapOverViewGroup(container, operator);
                if (match != null) {
                    return match;
                }
            }
        }
        return null;
    }

    /**
     * Returns the first view matching the operator in the given ViewGroups, or null if none.
     * Forward iteration matters.
     */
    private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
        final int itemCount = container.getChildCount();
        for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
            View item = container.getChildAt(itemIdx);
            if (op.matchesInfo((ItemInfo) item.getTag())) {
                return item;
            }
        }
        return null;
    }

    private ValueAnimator createNewAppBounceAnimation(View v, int i) {
        ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
                .setDuration(ItemInstallQueue.NEW_SHORTCUT_BOUNCE_DURATION);
+0 −75
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
@@ -51,7 +50,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -3146,62 +3144,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
        return layouts;
    }

    /**
     * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
     * animation.
     *
     * @param preferredItemId The id of the preferred item to match to if it exists.
     * @param packageName The package name of the app to match.
     * @param user The user of the app to match.
     */
    public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
        final ItemOperator preferredItem = (ItemInfo info, View view) ->
                info != null && info.id == preferredItemId;
        final ItemOperator preferredItemInFolder = (info, view) -> {
            if (info instanceof FolderInfo) {
                FolderInfo folderInfo = (FolderInfo) info;
                for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
                    if (preferredItem.evaluate(shortcutInfo, view)) {
                        return true;
                    }
                }
            }
            return false;
        };
        final ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
                info != null
                        && info.itemType == ITEM_TYPE_APPLICATION
                        && info.user.equals(user)
                        && info.getTargetComponent() != null
                        && TextUtils.equals(info.getTargetComponent().getPackageName(),
                                packageName);
        final ItemOperator packageAndUserAndAppInFolder = (info, view) -> {
            if (info instanceof FolderInfo) {
                FolderInfo folderInfo = (FolderInfo) info;
                for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
                    if (packageAndUserAndApp.evaluate(shortcutInfo, view)) {
                        return true;
                    }
                }
            }
            return false;
        };

        List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
        cellLayouts.add(getHotseat());
        forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));

        // Order: Preferred item, App icons in hotseat/workspace, app in folder in hotseat/workspace
        if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
            return getFirstMatch(cellLayouts, preferredItem, preferredItemInFolder,
                    packageAndUserAndApp, packageAndUserAndAppInFolder);
        } else {
            // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
            // FolderAdaptiveIcon as the background.
            return getFirstMatch(cellLayouts, preferredItem, packageAndUserAndApp);
        }
    }

    public View getHomescreenIconByItemId(final int id) {
        return getFirstMatch((info, v) -> info != null && info.id == id);
    }
@@ -3227,23 +3169,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
        return value[0];
    }

    /**
     * Finds the first view matching the ordered operators across the given cell layouts by order.
     * @param cellLayouts List of CellLayouts to scan, in order of preference.
     * @param operators List of operators, in order starting from best matching operator.
     */
    View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
        for (ItemOperator operator : operators) {
            for (CellLayout cellLayout : cellLayouts) {
                View match = mapOverCellLayout(cellLayout, operator);
                if (match != null) {
                    return match;
                }
            }
        }
        return null;
    }

    void clearDropTargets() {
        mapOverItems(new ItemOperator() {
            @Override
+11 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.os.UserHandle;

import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;

@@ -85,8 +86,16 @@ public interface ItemInfoMatcher {
    }

    static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
        return  (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
                        keys.contains(ShortcutKey.fromItemInfo(info));
        return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
                && keys.contains(ShortcutKey.fromItemInfo(info));
    }

    /**
     * Returns a matcher for items within folders.
     */
    static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
        return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
                .anyMatch(childOperator::matchesInfo);
    }

    /**
Loading