Loading quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +33 −31 Original line number Diff line number Diff line Loading @@ -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; } } } Loading @@ -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; } Loading Loading @@ -1269,7 +1269,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } } return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId, return mLauncher.getFirstMatchForAppClose(launchCookieItemId, packageName, UserHandle.of(runningTaskTarget.taskInfo.userId)); } Loading @@ -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(); Loading @@ -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()); Loading Loading @@ -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); } }); } Loading Loading @@ -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)); } Loading @@ -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 Loading quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +1 −1 Original line number Diff line number Diff line Loading @@ -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)); } Loading src/com/android/launcher3/Launcher.java +78 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -2674,6 +2679,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); Loading src/com/android/launcher3/Workspace.java +0 −75 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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 Loading src/com/android/launcher3/util/ItemInfoMatcher.java +11 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading
quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +33 −31 Original line number Diff line number Diff line Loading @@ -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; } } } Loading @@ -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; } Loading Loading @@ -1269,7 +1269,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } } return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId, return mLauncher.getFirstMatchForAppClose(launchCookieItemId, packageName, UserHandle.of(runningTaskTarget.taskInfo.userId)); } Loading @@ -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(); Loading @@ -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()); Loading Loading @@ -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); } }); } Loading Loading @@ -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)); } Loading @@ -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 Loading
quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +1 −1 Original line number Diff line number Diff line Loading @@ -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)); } Loading
src/com/android/launcher3/Launcher.java +78 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -2674,6 +2679,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); Loading
src/com/android/launcher3/Workspace.java +0 −75 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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 Loading
src/com/android/launcher3/util/ItemInfoMatcher.java +11 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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