From 64d74815976a4decc9ee515eed9f53272b3c3a4f Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 15 Oct 2019 15:33:16 -0700 Subject: [PATCH 001/119] Have consistent All Apps UI between grid size changes. We build an IDP with no grid size override values. This allows us to reference the profile measurements so that we can have a consistent UI for areas that the grid size change should not affect. Bug: 124967099 Change-Id: I6235862c95800d8f31dbf2de1d12b1fcf4dbd850 --- res/values/attrs.xml | 8 - src/com/android/launcher3/DeviceProfile.java | 44 +++-- .../launcher3/InvariantDeviceProfile.java | 172 ++++++++++-------- 3 files changed, 125 insertions(+), 99 deletions(-) diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 7be584e932..de17eb7b4f 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -115,8 +115,6 @@ - - @@ -132,12 +130,6 @@ - - - - - - diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 736142f190..a35f598686 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -25,6 +25,8 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.Surface; +import androidx.annotation.Nullable; + import com.android.launcher3.CellLayout.ContainerType; import com.android.launcher3.graphics.IconShape; import com.android.launcher3.icons.DotRenderer; @@ -34,6 +36,8 @@ import com.android.launcher3.util.DefaultDisplay; public class DeviceProfile { public final InvariantDeviceProfile inv; + // IDP with no grid override values. + @Nullable private final InvariantDeviceProfile originalIdp; // Device properties public final boolean isTablet; @@ -134,10 +138,11 @@ public class DeviceProfile { public DotRenderer mDotRendererAllApps; public DeviceProfile(Context context, InvariantDeviceProfile inv, - Point minSize, Point maxSize, + InvariantDeviceProfile originalIDP, Point minSize, Point maxSize, int width, int height, boolean isLandscape, boolean isMultiWindowMode) { this.inv = inv; + this.originalIdp = inv; this.isLandscape = isLandscape; this.isMultiWindowMode = isMultiWindowMode; @@ -229,6 +234,19 @@ public class DeviceProfile { // Recalculate the available dimensions using the new hotseat size. updateAvailableDimensions(dm, res); } + + if (originalIDP != null) { + // Grid size change should not affect All Apps UI, so we use the original profile + // measurements here. + DeviceProfile originalProfile = isLandscape + ? originalIDP.landscapeProfile + : originalIDP.portraitProfile; + allAppsIconSizePx = originalProfile.iconSizePx; + allAppsIconTextSizePx = originalProfile.iconTextSizePx; + allAppsCellHeightPx = originalProfile.allAppsCellHeightPx; + allAppsIconDrawablePaddingPx = originalProfile.iconDrawablePaddingOriginalPx; + allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx; + } updateWorkspacePadding(); // This is done last, after iconSizePx is calculated above. @@ -241,8 +259,8 @@ public class DeviceProfile { public DeviceProfile copy(Context context) { Point size = new Point(availableWidthPx, availableHeightPx); - return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape, - isMultiWindowMode); + return new DeviceProfile(context, inv, originalIdp, size, size, widthPx, heightPx, + isLandscape, isMultiWindowMode); } public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) { @@ -253,8 +271,8 @@ public class DeviceProfile { // In multi-window mode, we can have widthPx = availableWidthPx // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles' // widthPx and heightPx values where it's needed. - DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y, - isLandscape, true); + DeviceProfile profile = new DeviceProfile(context, inv, originalIdp, mwSize, mwSize, + mwSize.x, mwSize.y, isLandscape, true); // If there isn't enough vertical cell padding with the labels displayed, hide the labels. float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx @@ -338,18 +356,10 @@ public class DeviceProfile { } cellWidthPx = iconSizePx + iconDrawablePaddingPx; - // All apps - if (allAppsHasDifferentNumColumns()) { - allAppsIconSizePx = ResourceUtils.pxFromDp(inv.allAppsIconSize, dm); - allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, dm); - allAppsCellHeightPx = getCellSize(inv.numAllAppsColumns, inv.numAllAppsColumns).y; - allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx; - } else { - allAppsIconSizePx = iconSizePx; - allAppsIconTextSizePx = iconTextSizePx; - allAppsIconDrawablePaddingPx = iconDrawablePaddingPx; - allAppsCellHeightPx = getCellSize().y; - } + allAppsIconSizePx = iconSizePx; + allAppsIconTextSizePx = iconTextSizePx; + allAppsIconDrawablePaddingPx = iconDrawablePaddingPx; + allAppsCellHeightPx = getCellSize().y; allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx; if (isVerticalBarLayout()) { diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 310a9e92ff..d66ba73175 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -58,6 +58,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; public class InvariantDeviceProfile { @@ -191,54 +192,11 @@ public class InvariantDeviceProfile { Point smallestSize = new Point(displayInfo.smallestSize); Point largestSize = new Point(displayInfo.largestSize); - ArrayList allOptions = getPredefinedDeviceProfiles(context, gridName); // This guarantees that width < height float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), displayInfo.metrics); float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), displayInfo.metrics); - // Sort the profiles based on the closeness to the device size - Collections.sort(allOptions, (a, b) -> - Float.compare(dist(minWidthDps, minHeightDps, a.minWidthDps, a.minHeightDps), - dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps))); - DisplayOption interpolatedDisplayOption = - invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions); - - GridOption closestProfile = allOptions.get(0).grid; - numRows = closestProfile.numRows; - numColumns = closestProfile.numColumns; - numHotseatIcons = closestProfile.numHotseatIcons; - defaultLayoutId = closestProfile.defaultLayoutId; - demoModeLayoutId = closestProfile.demoModeLayoutId; - numFolderRows = closestProfile.numFolderRows; - numFolderColumns = closestProfile.numFolderColumns; - numAllAppsColumns = closestProfile.numAllAppsColumns; - - mExtraAttrs = closestProfile.extraAttrs; - - if (!closestProfile.name.equals(gridName)) { - Utilities.getPrefs(context).edit() - .putString(KEY_IDP_GRID_NAME, closestProfile.name).apply(); - } - - iconSize = interpolatedDisplayOption.iconSize; - iconShapePath = getIconShapePath(context); - landscapeIconSize = interpolatedDisplayOption.landscapeIconSize; - iconBitmapSize = ResourceUtils.pxFromDp(iconSize, displayInfo.metrics); - iconTextSize = interpolatedDisplayOption.iconTextSize; - fillResIconDpi = getLauncherIconDensity(iconBitmapSize); - - if (Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)) { - allAppsIconSize = interpolatedDisplayOption.allAppsIconSize; - allAppsIconTextSize = interpolatedDisplayOption.allAppsIconTextSize; - } else { - allAppsIconSize = iconSize; - allAppsIconTextSize = iconTextSize; - } - - // If the partner customization apk contains any grid overrides, apply them - // Supported overrides: numRows, numColumns, iconSize - applyPartnerDeviceProfileOverrides(context, displayInfo.metrics); Point realSize = new Point(displayInfo.realSize); // The real size never changes. smallSide and largeSide will remain the @@ -246,10 +204,64 @@ public class InvariantDeviceProfile { int smallSide = Math.min(realSize.x, realSize.y); int largeSide = Math.max(realSize.x, realSize.y); - landscapeProfile = new DeviceProfile(context, this, smallestSize, largestSize, - largeSide, smallSide, true /* isLandscape */, false /* isMultiWindowMode */); - portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize, - smallSide, largeSide, false /* isLandscape */, false /* isMultiWindowMode */); + // We want a list of all options as well as the list of filtered options. This allows us + // to have a consistent UI for areas that the grid size change should not affect + // ie. All Apps should be consistent between grid sizes. + ArrayList allOptions = new ArrayList<>(); + ArrayList filteredOptions = new ArrayList<>(); + getPredefinedDeviceProfiles(context, gridName, filteredOptions, allOptions); + + if (allOptions.isEmpty() && filteredOptions.isEmpty()) { + throw new RuntimeException("No display option with canBeDefault=true"); + } + + // Sort the profiles based on the closeness to the device size + Comparator comparator = (a, b) -> Float.compare(dist(minWidthDps, + minHeightDps, a.minWidthDps, a.minHeightDps), + dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps)); + + // Calculate the device profiles as if there is no grid override. + Collections.sort(allOptions, comparator); + DisplayOption interpolatedDisplayOption = + invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions); + initGridOption(context, allOptions, interpolatedDisplayOption, displayInfo.metrics); + + // Create IDP with no grid override values. + InvariantDeviceProfile originalIDP = new InvariantDeviceProfile(this); + originalIDP.landscapeProfile = new DeviceProfile(context, this, null, smallestSize, + largestSize, largeSide, smallSide, true /* isLandscape */, + false /* isMultiWindowMode */); + originalIDP.portraitProfile = new DeviceProfile(context, this, null, smallestSize, + largestSize, smallSide, largeSide, false /* isLandscape */, + false /* isMultiWindowMode */); + + if (filteredOptions.isEmpty()) { + filteredOptions = allOptions; + + landscapeProfile = originalIDP.landscapeProfile; + portraitProfile = originalIDP.portraitProfile; + } else { + Collections.sort(filteredOptions, comparator); + interpolatedDisplayOption = + invDistWeightedInterpolate(minWidthDps, minHeightDps, filteredOptions); + + initGridOption(context, filteredOptions, interpolatedDisplayOption, + displayInfo.metrics); + numAllAppsColumns = originalIDP.numAllAppsColumns; + + landscapeProfile = new DeviceProfile(context, this, originalIDP, smallestSize, + largestSize, largeSide, smallSide, true /* isLandscape */, + false /* isMultiWindowMode */); + portraitProfile = new DeviceProfile(context, this, originalIDP, smallestSize, + largestSize, smallSide, largeSide, false /* isLandscape */, + false /* isMultiWindowMode */); + } + + GridOption closestProfile = filteredOptions.get(0).grid; + if (!closestProfile.name.equals(gridName)) { + Utilities.getPrefs(context).edit() + .putString(KEY_IDP_GRID_NAME, closestProfile.name).apply(); + } // We need to ensure that there is enough extra space in the wallpaper // for the intended parallax effects @@ -267,6 +279,33 @@ public class InvariantDeviceProfile { return closestProfile.name; } + private void initGridOption(Context context, ArrayList options, + DisplayOption displayOption, DisplayMetrics metrics) { + GridOption closestProfile = options.get(0).grid; + numRows = closestProfile.numRows; + numColumns = closestProfile.numColumns; + numHotseatIcons = closestProfile.numHotseatIcons; + defaultLayoutId = closestProfile.defaultLayoutId; + demoModeLayoutId = closestProfile.demoModeLayoutId; + numFolderRows = closestProfile.numFolderRows; + numFolderColumns = closestProfile.numFolderColumns; + numAllAppsColumns = numColumns; + + mExtraAttrs = closestProfile.extraAttrs; + + iconSize = displayOption.iconSize; + iconShapePath = getIconShapePath(context); + landscapeIconSize = displayOption.landscapeIconSize; + iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics); + iconTextSize = displayOption.iconTextSize; + fillResIconDpi = getLauncherIconDensity(iconBitmapSize); + + // If the partner customization apk contains any grid overrides, apply them + // Supported overrides: numRows, numColumns, iconSize + applyPartnerDeviceProfileOverrides(context, metrics); + } + + @Nullable public TypedValue getAttrValue(int attr) { return mExtraAttrs == null ? null : mExtraAttrs.get(attr); @@ -344,7 +383,13 @@ public class InvariantDeviceProfile { } } - static ArrayList getPredefinedDeviceProfiles(Context context, String gridName) { + /** + * @param gridName The current grid name. + * @param filteredOptionsOut List filled with all the filtered options based on gridName. + * @param allOptionsOut List filled with all the options that can be the default option. + */ + static void getPredefinedDeviceProfiles(Context context, String gridName, + ArrayList filteredOptionsOut, ArrayList allOptionsOut) { ArrayList profiles = new ArrayList<>(); try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) { final int depth = parser.getDepth(); @@ -371,26 +416,19 @@ public class InvariantDeviceProfile { throw new RuntimeException(e); } - ArrayList filteredProfiles = new ArrayList<>(); if (!TextUtils.isEmpty(gridName)) { for (DisplayOption option : profiles) { if (gridName.equals(option.grid.name)) { - filteredProfiles.add(option); + filteredOptionsOut.add(option); } } } - if (filteredProfiles.isEmpty()) { - // No grid found, use the default options - for (DisplayOption option : profiles) { - if (option.canBeDefault) { - filteredProfiles.add(option); - } + + for (DisplayOption option : profiles) { + if (option.canBeDefault) { + allOptionsOut.add(option); } } - if (filteredProfiles.isEmpty()) { - throw new RuntimeException("No display option with canBeDefault=true"); - } - return filteredProfiles; } private int getLauncherIconDensity(int requiredSize) { @@ -514,8 +552,6 @@ public class InvariantDeviceProfile { private final int numHotseatIcons; - private final int numAllAppsColumns; - private final int defaultLayoutId; private final int demoModeLayoutId; @@ -538,8 +574,6 @@ public class InvariantDeviceProfile { R.styleable.GridDisplayOption_numFolderRows, numRows); numFolderColumns = a.getInt( R.styleable.GridDisplayOption_numFolderColumns, numColumns); - numAllAppsColumns = a.getInt( - R.styleable.GridDisplayOption_numAllAppsColumns, numColumns); a.recycle(); @@ -559,8 +593,6 @@ public class InvariantDeviceProfile { private float iconSize; private float iconTextSize; private float landscapeIconSize; - private float allAppsIconSize; - private float allAppsIconTextSize; DisplayOption(GridOption grid, Context context, AttributeSet attrs) { this.grid = grid; @@ -579,10 +611,6 @@ public class InvariantDeviceProfile { iconSize); iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0); - allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize, - iconSize); - allAppsIconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconTextSize, - iconTextSize); a.recycle(); } @@ -597,18 +625,14 @@ public class InvariantDeviceProfile { private DisplayOption multiply(float w) { iconSize *= w; landscapeIconSize *= w; - allAppsIconSize *= w; iconTextSize *= w; - allAppsIconTextSize *= w; return this; } private DisplayOption add(DisplayOption p) { iconSize += p.iconSize; landscapeIconSize += p.landscapeIconSize; - allAppsIconSize += p.allAppsIconSize; iconTextSize += p.iconTextSize; - allAppsIconTextSize += p.allAppsIconTextSize; return this; } } From 01c80d7a0090cb1c4a070d6f665f00a0ab74da93 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 16 Oct 2019 19:50:29 +0000 Subject: [PATCH 002/119] Revert "fetch and update shortcut icons in background thread" This reverts commit 4ec390e490dfb1503909853eb55df85f79e9813a. Reason for revert: the code change introduces significant delay when saving deep shortcut icons in cache. Bug: 142514365 Change-Id: If7a69844aba7f32690ff347f2db11f0a8041b9e4 --- .../launcher3/InstallShortcutReceiver.java | 5 ++-- .../launcher3/icons/LauncherIcons.java | 28 +++++------------ .../launcher3/pm/PinRequestHelper.java | 9 ++++-- .../ShortcutDragPreviewProvider.java | 21 +++++++------ .../android/launcher3/util/ShortcutUtil.java | 30 ------------------- 5 files changed, 27 insertions(+), 66 deletions(-) diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 0b79dd2835..8ebf46442f 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -17,7 +17,6 @@ package com.android.launcher3; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; -import static com.android.launcher3.util.ShortcutUtil.fetchAndUpdateShortcutIconAsync; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; @@ -483,7 +482,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return Pair.create(si, null); } else if (shortcutInfo != null) { WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext); - fetchAndUpdateShortcutIconAsync(mContext, itemInfo, shortcutInfo, true); + LauncherIcons li = LauncherIcons.obtain(mContext); + itemInfo.applyFrom(li.createShortcutIcon(shortcutInfo)); + li.recycle(); return Pair.create(itemInfo, shortcutInfo); } else if (providerInfo != null) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index 0f5d2903ce..c6949afc37 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -24,7 +24,6 @@ import android.graphics.Bitmap; import android.os.Process; import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; import com.android.launcher3.AppInfo; import com.android.launcher3.FastBitmapDrawable; @@ -33,6 +32,7 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.graphics.IconShape; +import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.util.Themes; @@ -114,37 +114,23 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { } // below methods should also migrate to BaseIconFactory - @WorkerThread + public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) { return createShortcutIcon(shortcutInfo, true /* badged */); } - @WorkerThread public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged) { return createShortcutIcon(shortcutInfo, badged, null); } - @WorkerThread - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, - @Nullable Supplier fallbackIconProvider) { - return createShortcutIcon(shortcutInfo, badged, true, fallbackIconProvider); - } - - @WorkerThread - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, - boolean useCache, @Nullable Supplier fallbackIconProvider) { + public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, + boolean badged, @Nullable Supplier fallbackIconProvider) { IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - final BitmapInfo bitmapInfo; - if (useCache) { - bitmapInfo = cache.getDeepShortcutTitleAndIcon(shortcutInfo); - } else { - bitmapInfo = new BitmapInfo(); - new ShortcutCachingLogic().loadIcon(mContext, shortcutInfo, bitmapInfo); - } + BaseIconCache.CacheEntry entry = cache.getDeepShortcutTitleAndIcon(shortcutInfo); final Bitmap unbadgedBitmap; - if (bitmapInfo.icon != null) { - unbadgedBitmap = bitmapInfo.icon; + if (entry.icon != null) { + unbadgedBitmap = entry.icon; } else { if (fallbackIconProvider != null) { // Fallback icons are already badged and with appropriate shadow diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java index 5b6b56d858..68ea6c43ad 100644 --- a/src/com/android/launcher3/pm/PinRequestHelper.java +++ b/src/com/android/launcher3/pm/PinRequestHelper.java @@ -17,7 +17,6 @@ package com.android.launcher3.pm; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; -import static com.android.launcher3.util.ShortcutUtil.fetchAndUpdateShortcutIconAsync; import android.annotation.TargetApi; import android.content.Context; @@ -30,7 +29,9 @@ import android.os.Parcelable; import androidx.annotation.Nullable; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.icons.LauncherIcons; public class PinRequestHelper { @@ -80,7 +81,11 @@ public class PinRequestHelper { ShortcutInfo si = request.getShortcutInfo(); WorkspaceItemInfo info = new WorkspaceItemInfo(si, context); // Apply the unbadged icon and fetch the actual icon asynchronously. - fetchAndUpdateShortcutIconAsync(context, info, si, false); + LauncherIcons li = LauncherIcons.obtain(context); + info.applyFrom(li.createShortcutIcon(si, false /* badged */)); + li.recycle(); + LauncherAppState.getInstance(context).getModel() + .updateAndBindWorkspaceItem(info, si); return info; } else { return null; diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java index 408ced20e2..ee97641109 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java +++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java @@ -26,7 +26,6 @@ import android.view.View; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.DragPreviewProvider; -import com.android.launcher3.icons.BitmapRenderer; /** * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size. @@ -40,22 +39,22 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { mPositionShift = shift; } - @Override public Bitmap createDragBitmap() { - int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; - return BitmapRenderer.createHardwareBitmap( - size + blurSizeOutline, - size + blurSizeOutline, - (c) -> drawDragViewOnBackground(c, size)); - } - - private void drawDragViewOnBackground(Canvas canvas, float size) { Drawable d = mView.getBackground(); Rect bounds = getDrawableBounds(d); + + int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; + final Bitmap b = Bitmap.createBitmap( + size + blurSizeOutline, + size + blurSizeOutline, + Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(b); canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2); - canvas.scale(size / bounds.width(), size / bounds.height(), 0, 0); + canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0); canvas.translate(bounds.left, bounds.top); d.draw(canvas); + return b; } @Override diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java index a69cd6c085..49c97daf35 100644 --- a/src/com/android/launcher3/util/ShortcutUtil.java +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -15,20 +15,10 @@ */ package com.android.launcher3.util; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; - -import android.content.Context; -import android.content.pm.ShortcutInfo; - -import androidx.annotation.NonNull; - import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.shortcuts.ShortcutKey; @@ -71,26 +61,6 @@ public class ShortcutUtil { && info instanceof WorkspaceItemInfo; } - /** - * Fetch the shortcut icon in background, then update the UI. - */ - public static void fetchAndUpdateShortcutIconAsync( - @NonNull Context context, @NonNull WorkspaceItemInfo info, @NonNull ShortcutInfo si, - boolean badged) { - if (info.iconBitmap == null) { - // use low res icon as placeholder while the actual icon is being fetched. - info.iconBitmap = BitmapInfo.LOW_RES_ICON; - info.iconColor = Themes.getColorAccent(context); - } - MODEL_EXECUTOR.execute(() -> { - LauncherIcons li = LauncherIcons.obtain(context); - BitmapInfo bitmapInfo = li.createShortcutIcon(si, badged, true, null); - info.applyFrom(bitmapInfo); - li.recycle(); - LauncherAppState.getInstance(context).getModel().updateAndBindWorkspaceItem(info, si); - }); - } - private static boolean isActive(ItemInfo info) { boolean isLoading = info instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) info).hasPromiseIconUi(); From 7242db1a7c8c876992c59d8eeabbc2d055922bbc Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 16 Oct 2019 19:50:59 +0000 Subject: [PATCH 003/119] Revert "Revert "Revert "Revert "Revert "cache shourtcut image""""" This reverts commit 28dc8de660be05800bfb21c5f4c7f709a5c9cb1f. Reason for revert: the code change introduces significant delay when saving deep shortcut icons in cache. Change-Id: I5d67ac0c4c867a40e882b7a46be446f8f7f63ac7 --- .../launcher3/icons/cache/CachingLogic.java | 8 --- .../icons/cache/IconCacheUpdateHandler.java | 4 +- .../android/launcher3/icons/IconCache.java | 12 ---- .../launcher3/icons/LauncherIcons.java | 10 +-- .../launcher3/icons/ShortcutCachingLogic.java | 72 ------------------- .../android/launcher3/model/LoaderTask.java | 24 ++----- 6 files changed, 12 insertions(+), 118 deletions(-) delete mode 100644 src/com/android/launcher3/icons/ShortcutCachingLogic.java diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index 3aa783a14c..e40a9c2c96 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,7 +17,6 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageInfo; import android.os.LocaleList; import android.os.UserHandle; @@ -43,13 +42,6 @@ public interface CachingLogic { return null; } - /** - * Returns the timestamp the entry was last updated in cache. - */ - default long getLastUpdatedTime(T object, PackageInfo info) { - return info.lastUpdateTime; - } - /** * Returns true the object should be added to mem cache; otherwise returns false. */ diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index bcdbce5e29..8224966d87 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -171,8 +171,7 @@ public class IconCacheUpdateHandler { long updateTime = c.getLong(indexLastUpdate); int version = c.getInt(indexVersion); T app = componentMap.remove(component); - if (version == info.versionCode - && updateTime == cachingLogic.getLastUpdatedTime(app, info) + if (version == info.versionCode && updateTime == info.lastUpdateTime && TextUtils.equals(c.getString(systemStateIndex), mIconCache.getIconSystemState(info.packageName))) { @@ -232,6 +231,7 @@ public class IconCacheUpdateHandler { } } + /** * A runnable that updates invalid icons and adds missing icons in the DB for the provided * LauncherActivityInfo list. Items are updated/added one at a time, so that the diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index ad01f9fa6a..9886f53863 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -28,7 +28,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ShortcutInfo; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Process; @@ -51,7 +50,6 @@ import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.model.PackageItemInfo; -import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; @@ -67,7 +65,6 @@ public class IconCache extends BaseIconCache { private final CachingLogic mComponentWithLabelCachingLogic; private final CachingLogic mLauncherActivityInfoCachingLogic; - private final CachingLogic mShortcutCachingLogic; private final LauncherApps mLauncherApps; private final UserManagerCompat mUserManager; @@ -81,7 +78,6 @@ public class IconCache extends BaseIconCache { inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); - mShortcutCachingLogic = new ShortcutCachingLogic(); mLauncherApps = mContext.getSystemService(LauncherApps.class); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); @@ -179,14 +175,6 @@ public class IconCache extends BaseIconCache { getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon); } - /** - * Fill in info with the icon and label for deep shortcut. - */ - public synchronized CacheEntry getDeepShortcutTitleAndIcon(ShortcutInfo info) { - return cacheLocked(ShortcutKey.fromInfo(info).componentName, info.getUserHandle(), - () -> info, mShortcutCachingLogic, false, false); - } - /** * Fill in {@param info} with the icon and label. If the * corresponding activity is not found, it reverts to the package icon. diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index c6949afc37..adc92c46c4 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; import android.os.Process; import androidx.annotation.Nullable; @@ -32,8 +33,8 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.graphics.IconShape; -import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.model.PackageItemInfo; +import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.util.Themes; import java.util.function.Supplier; @@ -125,12 +126,13 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, @Nullable Supplier fallbackIconProvider) { + Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext) + .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi); IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - BaseIconCache.CacheEntry entry = cache.getDeepShortcutTitleAndIcon(shortcutInfo); final Bitmap unbadgedBitmap; - if (entry.icon != null) { - unbadgedBitmap = entry.icon; + if (unbadgedDrawable != null) { + unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0); } else { if (fallbackIconProvider != null) { // Fallback icons are already badged and with appropriate shadow diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java deleted file mode 100644 index 5d696fd6f3..0000000000 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 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.icons; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.ShortcutInfo; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.icons.cache.CachingLogic; -import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutKey; - -/** - * Caching logic for shortcuts. - */ -public class ShortcutCachingLogic implements CachingLogic { - - @Override - public ComponentName getComponent(ShortcutInfo info) { - return ShortcutKey.fromInfo(info).componentName; - } - - @Override - public UserHandle getUser(ShortcutInfo info) { - return info.getUserHandle(); - } - - @Override - public CharSequence getLabel(ShortcutInfo info) { - return info.getShortLabel(); - } - - @Override - public void loadIcon(Context context, ShortcutInfo info, BitmapInfo target) { - LauncherIcons li = LauncherIcons.obtain(context); - Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context) - .getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi); - if (unbadgedDrawable != null) { - target.icon = li.createScaledBitmapWithoutShadow(unbadgedDrawable, 0); - } - li.recycle(); - } - - @Override - public long getLastUpdatedTime(ShortcutInfo shortcutInfo, PackageInfo info) { - if (shortcutInfo == null) return info.lastUpdateTime; - return Math.max(shortcutInfo.getLastChangedTimestamp(), info.lastUpdateTime); - } - - @Override - public boolean addToMemCache() { - return false; - } -} diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 81b701d716..04f15fc0c0 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -63,7 +63,6 @@ import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.LauncherIcons; -import com.android.launcher3.icons.ShortcutCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.PackageInstallInfo; @@ -192,8 +191,7 @@ public class LoaderTask implements Runnable { } : new TimingLogger(TAG, "run"); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { - List allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts); + loadWorkspace(); logger.addSplit("loadWorkspace"); verifyNotStopped(); @@ -225,29 +223,19 @@ public class LoaderTask implements Runnable { mApp.getModel()::onPackageIconsUpdated); logger.addSplit("update icon cache"); - verifyNotStopped(); - logger.addSplit("save shortcuts in icon cache"); - updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), - mApp.getModel()::onPackageIconsUpdated); - // Take a break waitForIdle(); logger.addSplit("step 2 complete"); verifyNotStopped(); // third step - List allDeepShortcuts = loadDeepShortcuts(); + loadDeepShortcuts(); logger.addSplit("loadDeepShortcuts"); verifyNotStopped(); mResults.bindDeepShortcuts(); logger.addSplit("bindDeepShortcuts"); - verifyNotStopped(); - logger.addSplit("save deep shortcuts in icon cache"); - updateHandler.updateIcons(allDeepShortcuts, - new ShortcutCachingLogic(), (pkgs, user) -> { }); - // Take a break waitForIdle(); logger.addSplit("step 3 complete"); @@ -289,7 +277,7 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace(List allDeepShortcuts) { + private void loadWorkspace() { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -544,7 +532,6 @@ public class LoaderTask implements Runnable { info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; } intent = info.intent; - allDeepShortcuts.add(pinnedShortcut); } else { // Create a shortcut info in disabled mode for now. info = c.loadSimpleWorkspaceItem(); @@ -893,8 +880,7 @@ public class LoaderTask implements Runnable { return allActivityList; } - private List loadDeepShortcuts() { - List allShortcuts = new ArrayList<>(); + private void loadDeepShortcuts() { mBgDataModel.deepShortcutMap.clear(); mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission(); if (mBgDataModel.hasShortcutHostPermission) { @@ -902,12 +888,10 @@ public class LoaderTask implements Runnable { if (mUserManager.isUserUnlocked(user)) { List shortcuts = mShortcutManager.queryForAllShortcuts(user); - allShortcuts.addAll(shortcuts); mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts); } } } - return allShortcuts; } public static boolean isValidProvider(AppWidgetProviderInfo provider) { From 9196cb11a2460b3d8bbe602aa2c18dbb42ac0e72 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 14 Oct 2019 15:27:12 -0700 Subject: [PATCH 004/119] 8.5/ Follow up to comments from previous CLs Bug: 141886704 Change-Id: Ib583753e35e57eab3b1cc413a0f910cf10142e42 --- .../quickstep/TouchInteractionService.java | 27 ++++++++++++------- .../WindowTransformSwipeHandler.java | 3 ++- .../FallbackNoButtonInputConsumer.java | 1 + .../quickstep/util/ActiveGestureLog.java | 2 +- .../quickstep/RecentsAnimationController.java | 2 +- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 0eafb44a53..e244e848fc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -129,10 +129,11 @@ public class TouchInteractionService extends Service implements public void onInitialize(Bundle bundle) { ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); - MAIN_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(TouchInteractionService.this) - .setProxy(proxy)); - MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); - MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */)); + MAIN_EXECUTOR.execute(() -> { + SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy); + TouchInteractionService.this.initInputMonitor(); + preloadOverview(true /* fromInit */); + }); if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS initialized"); } @@ -169,15 +170,19 @@ public class TouchInteractionService extends Service implements @BinderThread @Override public void onAssistantAvailable(boolean available) { - MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantAvailable(available)); - MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); + MAIN_EXECUTOR.execute(() -> { + mDeviceState.setAssistantAvailable(available); + TouchInteractionService.this.onAssistantVisibilityChanged(); + }); } @BinderThread @Override public void onAssistantVisibilityChanged(float visibility) { - MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantVisibility(visibility)); - MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); + MAIN_EXECUTOR.execute(() -> { + mDeviceState.setAssistantVisibility(visibility); + TouchInteractionService.this.onAssistantVisibilityChanged(); + }); } @BinderThread @@ -199,8 +204,10 @@ public class TouchInteractionService extends Service implements @BinderThread public void onSystemUiStateChanged(int stateFlags) { - MAIN_EXECUTOR.execute(() -> mDeviceState.setSystemUiFlags(stateFlags)); - MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); + MAIN_EXECUTOR.execute(() -> { + mDeviceState.setSystemUiFlags(stateFlags); + TouchInteractionService.this.onSystemUiFlagsChanged(); + }); } @BinderThread diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 1168758dfa..35f8be7461 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -229,7 +229,8 @@ public class WindowTransformSwipeHandler GestureState gestureState, RunningTaskInfo runningTaskInfo, long touchTimeMs, OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture, InputConsumerController inputConsumer, RecentsModel recentsModel) { - super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); + super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, + runningTaskInfo.id); mDeviceState = deviceState; mGestureState = gestureState; mTouchTimeMs = touchTimeMs; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 370b48793c..4e01f6f632 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -434,6 +434,7 @@ public class FallbackNoButtonInputConsumer extends @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + super.onRecentsAnimationCanceled(thumbnailData); mRecentsView.setRecentsAnimationTargets(null, null); setStateOnUiThread(STATE_HANDLER_INVALIDATED); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java index 9a3bb760f1..fabfc4bb51 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java @@ -33,7 +33,7 @@ public class ActiveGestureLog extends EventLogArray { */ public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID"; - public ActiveGestureLog() { + private ActiveGestureLog() { super("touch_interaction_log", 40); } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index d938dc5af8..9d5120d90d 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -71,7 +71,7 @@ public class RecentsAnimationController { * currently being animated. */ public ThumbnailData screenshotTask(int taskId) { - return mController != null ? mController.screenshotTask(taskId) : null; + return mController.screenshotTask(taskId); } /** From c9bf6d45ac8964ccd307c1095abfe160304e35ff Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 4 Oct 2019 15:33:18 -0700 Subject: [PATCH 005/119] 9/ Clean up swipe shared state - Add TaskAnimationManager which keeps track of the animation state whose lifecycle can be longer than the gesture. Move some of the logic related to cleaning up old animations into this class (called when the state is shared across gestures). - Instead of calling into the shared state directly via UIFactory, add callback to cleanup the animation and shared state from Launcher Bug: 141886704 Change-Id: Ib6140b37162f7460a20fa1046cfd4f4068e4a1c6 Signed-off-by: Winson Chung --- .../uioverrides/RecentsUiFactory.java | 2 - .../uioverrides/RecentsUiFactory.java | 13 -- .../quickstep/LauncherActivityInterface.java | 21 +-- .../android/quickstep/SwipeSharedState.java | 128 +------------ .../quickstep/TouchInteractionService.java | 49 +++-- .../WindowTransformSwipeHandler.java | 26 ++- .../DeviceLockedInputConsumer.java | 17 +- .../OtherActivityInputConsumer.java | 45 ++--- .../ResetGestureInputConsumer.java | 14 +- .../quickstep/views/LauncherRecentsView.java | 5 +- .../android/quickstep/views/RecentsView.java | 20 +- .../quickstep/BaseActivityInterface.java | 8 +- .../com/android/quickstep/GestureState.java | 19 +- .../quickstep/RecentsAnimationCallbacks.java | 5 +- .../quickstep/RecentsAnimationTargets.java | 9 - .../quickstep/TaskAnimationManager.java | 173 ++++++++++++++++++ src/com/android/launcher3/Launcher.java | 17 +- .../launcher3/uioverrides/UiFactory.java | 3 - 18 files changed, 338 insertions(+), 236 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/TaskAnimationManager.java diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index f2aa842d12..d5ea1ecc18 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -88,6 +88,4 @@ public abstract class RecentsUiFactory { public static RotationMode getRotationMode(DeviceProfile dp) { return RotationMode.NORMAL; } - - public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index ff73679a91..2a22e9d5ae 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -18,7 +18,6 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; @@ -45,7 +44,6 @@ import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.TouchInteractionService; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.views.RecentsView; @@ -188,17 +186,6 @@ public abstract class RecentsUiFactory { return new RecentsViewStateController(launcher); } - /** Clears the swipe shared state for the current swipe gesture. */ - public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - launcher.getOverviewPanel().switchToScreenshot( - () -> TouchInteractionService.getSwipeSharedState().clearAllState( - finishAnimation)); - } else { - TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); - } - } - /** * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. * diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index f6b3654e69..c5289355b8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -493,22 +493,21 @@ public final class LauncherActivityInterface implements BaseActivityInterface { - mLastRecentsAnimationController.cleanupScreenshot(); - clearAnimationState(); - }); - } else { - clearAnimationState(); - } - } - - @Override - public final void onRecentsAnimationFinished(RecentsAnimationController controller) { - if (mLastRecentsAnimationController == controller) { - mLastAnimationRunning = false; - } - } - - private void clearAnimationTarget() { - if (mLastAnimationTarget != null) { - mLastAnimationTarget.release(); - mLastAnimationTarget = null; - } - } - - private void clearAnimationState() { - clearAnimationTarget(); - - mLastAnimationCancelled = true; - mLastAnimationRunning = false; - } - - private void clearListenerState(boolean finishAnimation) { - if (mRecentsAnimationListener != null) { - mRecentsAnimationListener.removeListener(this); - mRecentsAnimationListener.notifyAnimationCanceled(); - if (mLastAnimationRunning && mLastRecentsAnimationController != null) { - Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), - finishAnimation - ? mLastRecentsAnimationController::finishAnimationToHome - : mLastRecentsAnimationController::finishAnimationToApp); - mLastRecentsAnimationController = null; - mLastAnimationTarget = null; - } - } - mRecentsAnimationListener = null; - clearAnimationTarget(); - mLastAnimationCancelled = false; - mLastAnimationRunning = false; - } - - public RecentsAnimationCallbacks newRecentsAnimationCallbacks() { - Preconditions.assertUIThread(); - - if (mLastAnimationRunning) { - String msg = "New animation started before completing old animation"; - if (FeatureFlags.IS_DOGFOOD_BUILD) { - throw new IllegalArgumentException(msg); - } else { - Log.e("SwipeSharedState", msg, new Exception()); - } - } - - clearListenerState(false /* finishAnimation */); - boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false - : mOverviewComponentObserver.getActivityInterface().shouldMinimizeSplitScreen(); - mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen); - mRecentsAnimationListener.addListener(this); - return mRecentsAnimationListener; - } - - public RecentsAnimationCallbacks getActiveListener() { - return mRecentsAnimationListener; - } - - public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) { - if (mLastRecentsAnimationController != null) { - listener.onRecentsAnimationStart(mLastRecentsAnimationController, - mLastAnimationTarget); - } else if (mLastAnimationCancelled) { - listener.onRecentsAnimationCanceled(null); - } - } - /** * Called when a recents animation has finished, but was interrupted before the next task was * launched. The given {@param runningTaskId} should be used as the running task for the @@ -156,11 +36,9 @@ public class SwipeSharedState implements RecentsAnimationListener { public void setRecentsAnimationFinishInterrupted(int runningTaskId) { recentsAnimationFinishInterrupted = true; nextRunningTaskId = runningTaskId; - mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets(); } - public void clearAllState(boolean finishAnimation) { - clearListenerState(finishAnimation); + public void clearAllState() { canGestureBeContinued = false; recentsAnimationFinishInterrupted = false; nextRunningTaskId = -1; @@ -172,8 +50,6 @@ public class SwipeSharedState implements RecentsAnimationListener { pw.println(prefix + "canGestureBeContinued=" + canGestureBeContinued); pw.println(prefix + "recentsAnimationFinishInterrupted=" + recentsAnimationFinishInterrupted); pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId); - pw.println(prefix + "lastAnimationCancelled=" + mLastAnimationCancelled); - pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning); pw.println(prefix + "logTraceId=" + mLogId); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index e244e848fc..cc7eb9bbb4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -250,10 +250,7 @@ public class TouchInteractionService extends Service implements return sSwipeSharedState; } - private final InputConsumer mResetGestureInputConsumer = - new ResetGestureInputConsumer(sSwipeSharedState); - - private final BaseSwipeUpHandler.Factory mWindowTreansformFactory = + private final BaseSwipeUpHandler.Factory mWindowTransformFactory = this::createWindowTransformSwipeHandler; private final BaseSwipeUpHandler.Factory mFallbackNoButtonFactory = this::createFallbackNoButtonSwipeHandler; @@ -264,10 +261,12 @@ public class TouchInteractionService extends Service implements private OverviewComponentObserver mOverviewComponentObserver; private InputConsumerController mInputConsumer; private RecentsAnimationDeviceState mDeviceState; + private TaskAnimationManager mTaskAnimationManager; private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; private InputConsumer mConsumer = InputConsumer.NO_OP; private Choreographer mMainChoreographer; + private InputConsumer mResetGestureInputConsumer; private InputMonitorCompat mInputMonitorCompat; private InputEventReceiver mInputEventReceiver; @@ -338,13 +337,13 @@ public class TouchInteractionService extends Service implements @UiThread public void onUserUnlocked() { + mTaskAnimationManager = new TaskAnimationManager(); mRecentsModel = RecentsModel.INSTANCE.get(this); mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState, mOverviewComponentObserver); + mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager); mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); - - sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); mInputConsumer.registerInputConsumer(); onSystemUiFlagsChanged(); onAssistantVisibilityChanged(); @@ -356,6 +355,18 @@ public class TouchInteractionService extends Service implements resetHomeBounceSeenOnQuickstepEnabledFirstTime(); } + private void onDeferredActivityLaunch() { + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot( + null, () -> { + mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); + sSwipeSharedState.clearAllState(); + }); + } else { + mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); + } + } + private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { if (!mDeviceState.isUserUnlocked() || !mMode.hasGestures) { // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation @@ -509,7 +520,8 @@ public class TouchInteractionService extends Service implements RunningTaskInfo runningTaskInfo = TraceHelper.whitelistIpcs("getRunningTask.0", () -> mAM.getRunningTask(0)); if (!useSharedState) { - sSwipeSharedState.clearAllState(false /* finishAnimation */); + mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); + sSwipeSharedState.clearAllState(); } if (mDeviceState.isKeyguardShowingOccluded()) { // This handles apps showing over the lockscreen (e.g. camera) @@ -572,20 +584,20 @@ public class TouchInteractionService extends Service implements } else { shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event); - factory = mWindowTreansformFactory; + factory = mWindowTransformFactory; } final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); - return new OtherActivityInputConsumer(this, mDeviceState, gestureState, runningTaskInfo, - shouldDefer, this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, - disableHorizontalSwipe, factory, mLogId); + return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, + gestureState, runningTaskInfo, shouldDefer, this::onConsumerInactive, + sSwipeSharedState, mInputMonitorCompat, disableHorizontalSwipe, factory, mLogId); } private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState, RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { - return new DeviceLockedInputConsumer(this, mDeviceState, gestureState, - sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId); + return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager, + gestureState, sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId); } else { return mResetGestureInputConsumer; } @@ -647,9 +659,8 @@ public class TouchInteractionService extends Service implements return; } - // Pass null animation handler to indicate this start is preload. - startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(), - null); + mTaskAnimationManager.preloadRecentsAnimation( + mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState()); } @Override @@ -725,9 +736,9 @@ public class TouchInteractionService extends Service implements private BaseSwipeUpHandler createWindowTransformSwipeHandler(GestureState gestureState, RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) { - return new WindowTransformSwipeHandler(this, mDeviceState, gestureState, runningTask, - touchTimeMs, mOverviewComponentObserver, continuingLastGesture, mInputConsumer, - mRecentsModel); + return new WindowTransformSwipeHandler(this, mDeviceState, mTaskAnimationManager, + gestureState, runningTask, touchTimeMs, mOverviewComponentObserver, + continuingLastGesture, mInputConsumer, mRecentsModel); } private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(GestureState gestureState, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 35f8be7461..29f431d40f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -192,6 +192,7 @@ public class WindowTransformSwipeHandler private static final int LOG_NO_OP_PAGE_INDEX = -1; private final RecentsAnimationDeviceState mDeviceState; + private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; private GestureEndTarget mGestureEndTarget; @@ -225,13 +226,17 @@ public class WindowTransformSwipeHandler private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; + private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch; + public WindowTransformSwipeHandler(Context context, RecentsAnimationDeviceState deviceState, - GestureState gestureState, RunningTaskInfo runningTaskInfo, long touchTimeMs, + TaskAnimationManager taskAnimationManager, GestureState gestureState, + RunningTaskInfo runningTaskInfo, long touchTimeMs, OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture, InputConsumerController inputConsumer, RecentsModel recentsModel) { super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); mDeviceState = deviceState; + mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; @@ -401,9 +406,26 @@ public class WindowTransformSwipeHandler // that time by a previous window transition. setupRecentsViewUi(); + // For the duration of the gesture, in cases where an activity is launched while the + // activity is not yet resumed, finish the animation to ensure we get resumed + mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback( + mOnDeferredActivityLaunch); + notifyGestureStartedAsync(); } + private void onDeferredActivityLaunch() { + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot( + null, () -> { + mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); + TouchInteractionService.getSwipeSharedState().clearAllState(); + }); + } else { + mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); + } + } + private void setupRecentsViewUi() { if (mContinuingLastGesture) { updateSysUiFlags(mCurrentShift.value); @@ -1091,6 +1113,8 @@ public class WindowTransformSwipeHandler mRecentsView.onGestureAnimationEnd(); + // Reset the callback for deferred activity launches + mActivityInterface.setOnDeferredActivityLaunchCallback(null); mActivity.getRootView().setOnApplyWindowInsetsListener(null); removeLiveTileOverlay(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 12b7c2622d..980cfad4e9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -22,7 +22,6 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; @@ -48,6 +47,7 @@ import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationTargets; +import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputMonitorCompat; @@ -76,6 +76,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final Context mContext; private final RecentsAnimationDeviceState mDeviceState; + private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; private final float mTouchSlopSquared; private final SwipeSharedState mSwipeSharedState; @@ -98,10 +99,12 @@ public class DeviceLockedInputConsumer implements InputConsumer, private RecentsAnimationTargets mRecentsAnimationTargets; public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, - GestureState gestureState, SwipeSharedState swipeSharedState, - InputMonitorCompat inputMonitorCompat, int runningTaskId, int logId) { + TaskAnimationManager taskAnimationManager, GestureState gestureState, + SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, + int runningTaskId, int logId) { mContext = context; mDeviceState = deviceState; + mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mTouchSlopSquared = squaredTouchSlop(context); mSwipeSharedState = swipeSharedState; @@ -207,16 +210,14 @@ public class DeviceLockedInputConsumer implements InputConsumer, private void startRecentsTransition() { mThresholdCrossed = true; - RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks(); - callbacks.addListener(this); + mInputMonitorCompat.pilferPointers(); + Intent intent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); - - mInputMonitorCompat.pilferPointers(); - startRecentsActivityAsync(intent, callbacks); + mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 02f4c4032d..6ba326c650 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -26,7 +26,6 @@ import static android.view.MotionEvent.INVALID_POINTER_ID; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS; -import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -58,6 +57,7 @@ import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; +import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; @@ -80,7 +80,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3; private final RecentsAnimationDeviceState mDeviceState; + private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; + private RecentsAnimationCallbacks mActiveCallbacks; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; private final SwipeSharedState mSwipeSharedState; @@ -95,6 +97,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final Consumer mOnCompleteCallback; private final MotionPauseDetector mMotionPauseDetector; private final float mMotionPauseMinDisplacement; + private VelocityTracker mVelocityTracker; private BaseSwipeUpHandler mInteractionHandler; @@ -126,13 +129,15 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private int mLogId; public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, - GestureState gestureState, RunningTaskInfo runningTaskInfo, - boolean isDeferredDownTarget, Consumer onCompleteCallback, + TaskAnimationManager taskAnimationManager, GestureState gestureState, + RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, + Consumer onCompleteCallback, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe, Factory handlerFactory, int logId) { super(base); mLogId = logId; mDeviceState = deviceState; + mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mMainThreadHandler = new Handler(Looper.getMainLooper()); mRunningTask = runningTaskInfo; @@ -147,7 +152,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mVelocityTracker = VelocityTracker.obtain(); mInputMonitorCompat = inputMonitorCompat; - boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null; + boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; mSwipeSharedState = swipeSharedState; @@ -329,25 +334,22 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC long touchTimeMs, boolean isLikelyToStartNewTask) { ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation"); - RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); - final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mGestureState, mRunningTask, - touchTimeMs, listenerSet != null, isLikelyToStartNewTask); + mInteractionHandler = mHandlerFactory.newHandler(mGestureState, mRunningTask, touchTimeMs, + mTaskAnimationManager.isRecentsAnimationRunning(), isLikelyToStartNewTask); + mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished); + mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged); + mInteractionHandler.initWhenReady(); - mInteractionHandler = handler; - handler.setGestureEndCallback(this::onInteractionGestureFinished); - mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged); - handler.initWhenReady(); - - if (listenerSet != null) { - listenerSet.addListener(handler); - mSwipeSharedState.applyActiveRecentsAnimationState(handler); + if (mTaskAnimationManager.isRecentsAnimationRunning()) { + mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState); + mActiveCallbacks.addListener(mInteractionHandler); + mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); notifyGestureStarted(); } else { - RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks(); - callbacks.addListener(handler); - Intent intent = handler.getLaunchIntent(); + Intent intent = mInteractionHandler.getLaunchIntent(); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); - startRecentsActivityAsync(intent, callbacks); + mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, + mInteractionHandler); } } @@ -415,9 +417,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void removeListener() { - RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); - if (listenerSet != null) { - listenerSet.removeListener(mInteractionHandler); + if (mActiveCallbacks != null) { + mActiveCallbacks.removeListener(mInteractionHandler); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java index e04c0c741c..b22a75b7c7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java @@ -18,17 +18,18 @@ package com.android.quickstep.inputconsumers; import android.view.MotionEvent; import com.android.quickstep.InputConsumer; -import com.android.quickstep.SwipeSharedState; +import com.android.quickstep.TaskAnimationManager; +import com.android.quickstep.TouchInteractionService; /** * A NO_OP input consumer which also resets any pending gesture */ public class ResetGestureInputConsumer implements InputConsumer { - private final SwipeSharedState mSwipeSharedState; + private final TaskAnimationManager mTaskAnimationManager; - public ResetGestureInputConsumer(SwipeSharedState swipeSharedState) { - mSwipeSharedState = swipeSharedState; + public ResetGestureInputConsumer(TaskAnimationManager taskAnimationManager) { + mTaskAnimationManager = taskAnimationManager; } @Override @@ -39,8 +40,9 @@ public class ResetGestureInputConsumer implements InputConsumer { @Override public void onMotionEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN - && mSwipeSharedState.getActiveListener() != null) { - mSwipeSharedState.clearAllState(false /* finishAnimation */); + && mTaskAnimationManager.isRecentsAnimationRunning()) { + mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); + TouchInteractionService.getSwipeSharedState().clearAllState(); } } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 0655c733ba..5a65c15376 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -102,8 +102,9 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public void startHome() { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - switchToScreenshot(() -> finishRecentsAnimation(true /* toRecents */, - () -> mActivity.getStateManager().goToState(NORMAL))); + switchToScreenshot(null, + () -> finishRecentsAnimation(true /* toRecents */, + () -> mActivity.getStateManager().goToState(NORMAL))); } else { mActivity.getStateManager().goToState(NORMAL); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 6120b9e9f9..5d4665d48a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1851,20 +1851,20 @@ public abstract class RecentsView extends PagedView impl return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight()); } - /** If it's in the live tile mode, switch the running task into screenshot mode. */ - public void switchToScreenshot(Runnable onFinishRunnable) { + public void switchToScreenshot(ThumbnailData thumbnailData, Runnable onFinishRunnable) { TaskView taskView = getRunningTaskView(); - if (taskView == null) { - if (onFinishRunnable != null) { - onFinishRunnable.run(); + if (taskView != null) { + taskView.setShowScreenshot(true); + if (thumbnailData != null) { + taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData); + } else { + taskView.getThumbnail().refresh(); } - return; + ViewUtils.postDraw(taskView, onFinishRunnable); + } else { + onFinishRunnable.run(); } - - taskView.setShowScreenshot(true); - taskView.getThumbnail().refresh(); - ViewUtils.postDraw(taskView, onFinishRunnable); } @Override diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 409bec6c70..fdf16a1057 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -60,6 +60,11 @@ public interface BaseActivityInterface { ActivityInitListener createActivityInitListener(BiPredicate onInitListener); + /** + * Sets a callback to be run when an activity launch happens while launcher is not yet resumed. + */ + default void setOnDeferredActivityLaunchCallback(Runnable r) {} + @Nullable T getCreatedActivity(); @@ -96,7 +101,8 @@ public interface BaseActivityInterface { default void closeOverlay() { } - default void switchToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {} + default void switchRunningTaskViewToScreenshot(ThumbnailData thumbnailData, + Runnable runnable) {} interface AnimationFactory { diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index de64227c26..4bd962a5ff 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -16,12 +16,13 @@ package com.android.quickstep; import com.android.launcher3.BaseDraggingActivity; +import com.android.systemui.shared.recents.model.ThumbnailData; /** * Manages the state for an active system gesture, listens for events from the system and Launcher, * and fires events when the states change. */ -public class GestureState { +public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener { // Needed to interact with the current activity private BaseActivityInterface mActivityInterface; @@ -33,4 +34,20 @@ public class GestureState { public BaseActivityInterface getActivityInterface() { return mActivityInterface; } + + @Override + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + // To be implemented + } + + @Override + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + // To be implemented + } + + @Override + public void onRecentsAnimationFinished(RecentsAnimationController controller) { + // To be implemented + } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index 2918879d74..acf61b4142 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -127,7 +127,7 @@ public class RecentsAnimationCallbacks implements */ public interface RecentsAnimationListener { default void onRecentsAnimationStart(RecentsAnimationController controller, - RecentsAnimationTargets targetSet) {} + RecentsAnimationTargets targets) {} /** * Callback from the system when the recents animation is canceled. {@param thumbnailData} @@ -135,6 +135,9 @@ public class RecentsAnimationCallbacks implements */ default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {} + /** + * Callback made whenever the recents animation is finished. + */ default void onRecentsAnimationFinished(RecentsAnimationController controller) {} } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java index 93537597d5..718c5baa2c 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java @@ -41,13 +41,4 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets { public boolean hasTargets() { return unfilteredApps.length != 0; } - - /** - * Clones the target set without any actual targets. Used only when continuing a gesture after - * the actual recents animation has finished. - */ - public RecentsAnimationTargets cloneWithoutTargets() { - return new RecentsAnimationTargets(new RemoteAnimationTargetCompat[0], - new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds); - } } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java new file mode 100644 index 0000000000..557be5b554 --- /dev/null +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2019 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.quickstep; + +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; + +import android.content.Intent; +import android.util.Log; + +import androidx.annotation.UiThread; + +import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; +import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ActivityManagerWrapper; + +public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { + + private RecentsAnimationController mController; + private RecentsAnimationCallbacks mCallbacks; + private RecentsAnimationTargets mTargets; + // Temporary until we can hook into gesture state events + private GestureState mLastGestureState; + private ThumbnailData mCanceledThumbnail; + + /** + * Preloads the recents animation. + */ + public void preloadRecentsAnimation(Intent intent) { + // Pass null animation handler to indicate this start is for preloading + UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() + .startRecentsActivity(intent, null, null, null, null)); + } + + /** + * Starts a new recents animation for the activity with the given {@param intent}. + */ + @UiThread + public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState, + Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) { + // Notify if recents animation is still running + if (mController != null) { + String msg = "New recents animation started before old animation completed"; + if (FeatureFlags.IS_DOGFOOD_BUILD) { + throw new IllegalArgumentException(msg); + } else { + Log.e("TaskAnimationManager", msg, new Exception()); + } + } + // But force-finish it anyways + finishRunningRecentsAnimation(false /* toHome */); + + final BaseActivityInterface activityInterface = gestureState.getActivityInterface(); + mLastGestureState = gestureState; + mCallbacks = new RecentsAnimationCallbacks(activityInterface.shouldMinimizeSplitScreen()); + mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() { + @Override + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + mController = controller; + mTargets = targets; + } + + @Override + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + if (thumbnailData != null) { + // If a screenshot is provided, switch to the screenshot before cleaning up + activityInterface.switchRunningTaskViewToScreenshot(thumbnailData, + () -> cleanUpRecentsAnimation()); + } else { + cleanUpRecentsAnimation(); + } + } + + @Override + public void onRecentsAnimationFinished(RecentsAnimationController controller) { + cleanUpRecentsAnimation(); + } + }); + mCallbacks.addListener(gestureState); + mCallbacks.addListener(listener); + UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() + .startRecentsActivity(intent, null, mCallbacks, null, null)); + return mCallbacks; + } + + /** + * Continues the existing running recents animation for a new gesture. + */ + public RecentsAnimationCallbacks continueRecentsAnimation(GestureState gestureState) { + mCallbacks.removeListener(mLastGestureState); + mLastGestureState = gestureState; + mCallbacks.addListener(gestureState); + return mCallbacks; + } + + /** + * Finishes the running recents animation. + */ + public void finishRunningRecentsAnimation(boolean toHome) { + if (mController != null) { + mCallbacks.notifyAnimationCanceled(); + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome + ? mController::finishAnimationToHome + : mController::finishAnimationToApp); + cleanUpRecentsAnimation(); + } + } + + /** + * Used to notify a listener of the current recents animation state (used if the listener was + * not yet added to the callbacks at the point that the listener callbacks would have been + * made). + */ + public void notifyRecentsAnimationState( + RecentsAnimationCallbacks.RecentsAnimationListener listener) { + if (isRecentsAnimationRunning()) { + listener.onRecentsAnimationStart(mController, mTargets); + } + // TODO: Do we actually need to report canceled/finished? + } + + /** + * @return whether there is a recents animation running. + */ + public boolean isRecentsAnimationRunning() { + return mController != null; + } + + /** + * Cleans up the recents animation entirely. + */ + private void cleanUpRecentsAnimation() { + // Clean up the screenshot if necessary + if (mController != null && mCanceledThumbnail != null) { + mController.cleanupScreenshot(); + } + + // Release all the target leashes + if (mTargets != null) { + mTargets.release(); + } + + // Remove gesture state from callbacks + if (mCallbacks != null && mLastGestureState != null) { + mCallbacks.removeListener(mLastGestureState); + } + + mController = null; + mCallbacks = null; + mTargets = null; + mCanceledThumbnail = null; + mLastGestureState = null; + } + + public void dump() { + // TODO + } +} diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 4b4d7939e6..67c1a04163 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -267,6 +267,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, private ArrayList mOnResumeCallbacks = new ArrayList<>(); + // Used to notify when an activity launch has been deferred because launcher is not yet resumed + // TODO: See if we can remove this later + private Runnable mOnDeferredActivityLaunchCallback; + private ViewOnDrawExecutor mPendingExecutor; private LauncherModel mModel; @@ -1886,7 +1890,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, // recents animation into launcher. Defer launching the activity until Launcher is // next resumed. addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer)); - UiFactory.clearSwipeSharedState(this, true /* finishAnimation */); + if (mOnDeferredActivityLaunchCallback != null) { + mOnDeferredActivityLaunchCallback.run(); + mOnDeferredActivityLaunchCallback = null; + } return true; } @@ -1947,6 +1954,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mOnResumeCallbacks.add(callback); } + /** + * Persistant callback which notifies when an activity launch is deferred because the activity + * was not yet resumed. + */ + public void setOnDeferredActivityLaunchCallback(Runnable callback) { + mOnDeferredActivityLaunchCallback = callback; + } + /** * Implementation of the method from LauncherModel.Callbacks. */ diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 6d9ed88e08..606c9905f1 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -96,9 +96,6 @@ public class UiFactory { public static void resetPendingActivityResults(Launcher launcher, int requestCode) { } - /** No-op. */ - public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { } - public static Person[] getPersons(ShortcutInfo si) { return Utilities.EMPTY_PERSON_ARRAY; } From c80b3224aa12c77971ee321e0966c078129d8add Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 7 Oct 2019 16:51:58 -0700 Subject: [PATCH 006/119] 10/ Migrate shared state to the gesture state - Instead of a shared state which is written into, gestures update their own gesture state and that state is passed to the next gesture. - The existing shared state encoded the final end target (which is currently directly correlated with canGestureBeContinued). If we move the end target calculations to the GestureState, the handlers can listen for those changes and we can use the previous gesture state to decide which consumer to choose. In addition, we move over the interrupted- finish-launch-task id. Bug: 141886704 Change-Id: Icb6a3815c16b23692dbcde316114bd3cea06634e Signed-off-by: Winson Chung --- .../uioverrides/states/QuickSwitchState.java | 3 +- .../android/quickstep/BaseSwipeUpHandler.java | 4 +- .../android/quickstep/SwipeSharedState.java | 59 ------ .../quickstep/TouchInteractionService.java | 92 ++++----- .../WindowTransformSwipeHandler.java | 130 +++++------- .../inputconsumers/DelegateInputConsumer.java | 5 - .../DeviceLockedInputConsumer.java | 10 +- .../FallbackNoButtonInputConsumer.java | 71 ++++--- .../OtherActivityInputConsumer.java | 18 +- .../ResetGestureInputConsumer.java | 1 - .../com/android/quickstep/GestureState.java | 190 +++++++++++++++++- .../com/android/quickstep/InputConsumer.java | 6 +- .../android/quickstep/MultiStateCallback.java | 0 .../quickstep/TaskAnimationManager.java | 2 + 14 files changed, 332 insertions(+), 259 deletions(-) delete mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java rename quickstep/{recents_ui_overrides => }/src/com/android/quickstep/MultiStateCallback.java (100%) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index 6c9f46fc47..127927059a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -20,13 +20,14 @@ import android.os.Looper; import com.android.launcher3.Launcher; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.quickstep.GestureState; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; /** * State to indicate we are about to launch a recent task. Note that this state is only used when * quick switching from launcher; quick switching from an app uses WindowTransformSwipeHelper. - * @see com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget#NEW_TASK + * @see GestureState.GestureEndTarget#NEW_TASK */ public class QuickSwitchState extends BackgroundAppState { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index e1e994c6a6..42d0a0c99d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -96,6 +96,7 @@ public abstract class BaseSwipeUpHandler mActivityInterface; protected final RecentsModel mRecentsModel; @@ -139,6 +140,7 @@ public abstract class BaseSwipeUpHandler mAM.getRunningTask(0)); - if (!useSharedState) { - mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); - sSwipeSharedState.clearAllState(); - } if (mDeviceState.isKeyguardShowingOccluded()) { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer(gestureState, runningTaskInfo); @@ -543,26 +537,27 @@ public class TouchInteractionService extends Service implements } } - if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher - && !sSwipeSharedState.recentsAnimationFinishInterrupted) { - return mResetGestureInputConsumer; - } else if (sSwipeSharedState.recentsAnimationFinishInterrupted) { + if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) { // If the finish animation was interrupted, then continue using the other activity input // consumer but with the next task as the running task RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); - info.id = sSwipeSharedState.nextRunningTaskId; - return createOtherActivityInputConsumer(gestureState, event, info); - } else if (sSwipeSharedState.goingToLauncher + info.id = previousGestureState.getFinishingRecentsAnimationTaskId(); + return createOtherActivityInputConsumer(previousGestureState, gestureState, event, + info); + } else if (runningTaskInfo == null) { + return mResetGestureInputConsumer; + } else if (previousGestureState.isRunningAnimationToLauncher() || gestureState.getActivityInterface().isResumed() || forceOverviewInputConsumer) { - return createOverviewInputConsumer(gestureState, event); + return createOverviewInputConsumer(previousGestureState, gestureState, event); } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && gestureState.getActivityInterface().isInLiveTileMode()) { - return createOverviewInputConsumer(gestureState, event); + return createOverviewInputConsumer(previousGestureState, gestureState, event); } else if (mDeviceState.isGestureBlockedActivity(runningTaskInfo)) { return mResetGestureInputConsumer; } else { - return createOtherActivityInputConsumer(gestureState, event, runningTaskInfo); + return createOtherActivityInputConsumer(previousGestureState, gestureState, event, + runningTaskInfo); } } @@ -572,14 +567,15 @@ public class TouchInteractionService extends Service implements && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; } - private InputConsumer createOtherActivityInputConsumer(GestureState gestureState, + private InputConsumer createOtherActivityInputConsumer(GestureState previousGestureState, + GestureState gestureState, MotionEvent event, RunningTaskInfo runningTaskInfo) { final boolean shouldDefer; final BaseSwipeUpHandler.Factory factory; if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) { - shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted; + shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0; factory = mFallbackNoButtonFactory; } else { shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState, @@ -590,26 +586,28 @@ public class TouchInteractionService extends Service implements final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, gestureState, runningTaskInfo, shouldDefer, this::onConsumerInactive, - sSwipeSharedState, mInputMonitorCompat, disableHorizontalSwipe, factory, mLogId); + mInputMonitorCompat, disableHorizontalSwipe, factory); } private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState, RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager, - gestureState, sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId); + gestureState, mInputMonitorCompat, taskInfo.taskId); } else { return mResetGestureInputConsumer; } } - public InputConsumer createOverviewInputConsumer(GestureState gestureState, MotionEvent event) { + public InputConsumer createOverviewInputConsumer(GestureState previousGestureState, + GestureState gestureState, MotionEvent event) { BaseDraggingActivity activity = gestureState.getActivityInterface().getCreatedActivity(); if (activity == null) { return mResetGestureInputConsumer; } - if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) { + if (activity.getRootView().hasWindowFocus() + || previousGestureState.isRunningAnimationToLauncher()) { return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat, false /* startingInActivityBounds */); } else { @@ -704,10 +702,6 @@ public class TouchInteractionService extends Service implements boolean resumed = mOverviewComponentObserver != null && mOverviewComponentObserver.getActivityInterface().isResumed(); pw.println(" resumed=" + resumed); - pw.println(" useSharedState=" + mConsumer.useSharedSwipeState()); - if (mConsumer.useSharedSwipeState()) { - sSwipeSharedState.dump(" ", pw); - } pw.println(" mConsumer=" + mConsumer.getName()); pw.println("FeatureFlags:"); pw.println(" APPLY_CONFIG_AT_RUNTIME=" + APPLY_CONFIG_AT_RUNTIME.get()); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 29f431d40f..77ebc402d2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -26,11 +26,12 @@ import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.HIDE; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.PEEK; +import static com.android.quickstep.GestureState.GestureEndTarget.HOME; +import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; +import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.animation.Animator; @@ -70,6 +71,7 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseActivityInterface.AnimationFactory; import com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState; import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; +import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.util.ActiveGestureLog; @@ -138,42 +140,6 @@ public class WindowTransformSwipeHandler private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED; - public enum GestureEndTarget { - HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false, - ContainerType.WORKSPACE, false), - - RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT - | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true), - - NEW_TASK(0, STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT, false, true, - ContainerType.APP, true), - - LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP, false); - - GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued, - int containerType, boolean recentsAttachedToAppWindow) { - this.endShift = endShift; - this.endState = endState; - this.isLauncher = isLauncher; - this.canBeContinued = canBeContinued; - this.containerType = containerType; - this.recentsAttachedToAppWindow = recentsAttachedToAppWindow; - } - - /** 0 is app, 1 is overview */ - public final float endShift; - /** The state to apply when we reach this final target */ - public final int endState; - /** Whether the target is in the launcher activity */ - public final boolean isLauncher; - /** Whether the user can start a new gesture while this one is finishing */ - public final boolean canBeContinued; - /** Used to log where the user ended up after the gesture ends */ - public final int containerType; - /** Whether RecentsView should be attached to the window as we animate to this target */ - public final boolean recentsAttachedToAppWindow; - } - public static final long MAX_SWIPE_DURATION = 350; public static final long MIN_SWIPE_DURATION = 80; public static final long MIN_OVERSHOOT_DURATION = 120; @@ -195,7 +161,6 @@ public class WindowTransformSwipeHandler private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; - private GestureEndTarget mGestureEndTarget; // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise private RunningWindowAnim mRunningWindowAnim; private boolean mIsShelfPeeking; @@ -287,6 +252,9 @@ public class WindowTransformSwipeHandler | STATE_GESTURE_STARTED, this::setupLauncherUiAfterSwipeUpToRecentsAnimation); + mGestureState.addCallback(STATE_END_TARGET_ANIMATION_FINISHED, + this::onEndTargetSet); + mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, this::invalidateHandlerWithLauncher); @@ -338,7 +306,7 @@ public class WindowTransformSwipeHandler @Override protected boolean moveWindowWithRecentsScroll() { - return mGestureEndTarget != HOME; + return mGestureState.getEndTarget() != HOME; } private void onLauncherStart(final T activity) { @@ -351,7 +319,7 @@ public class WindowTransformSwipeHandler // If we've already ended the gesture and are going home, don't prepare recents UI, // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL. - if (mGestureEndTarget != HOME) { + if (mGestureState.getEndTarget() != HOME) { Runnable initAnimFactory = () -> { mAnimationFactory = mActivityInterface.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible, true, @@ -419,7 +387,6 @@ public class WindowTransformSwipeHandler mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot( null, () -> { mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); - TouchInteractionService.getSwipeSharedState().clearAllState(); }); } else { mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); @@ -460,13 +427,6 @@ public class WindowTransformSwipeHandler .getHighResLoadingState().setVisible(true); } - private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) { - float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + - mContext.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing); - float interpolation = Math.min(1, offsetX / distanceToReachEdge); - return TaskView.getCurveScaleForInterpolation(interpolation); - } - @Override public void onMotionPauseChanged(boolean isPaused) { setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION); @@ -491,9 +451,8 @@ public class WindowTransformSwipeHandler ? null : mRecentsAnimationTargets.findTask(mRunningTaskId); final boolean recentsAttachedToAppWindow; - int runningTaskIndex = mRecentsView.getRunningTaskIndex(); - if (mGestureEndTarget != null) { - recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow; + if (mGestureState.getEndTarget() != null) { + recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow; } else if (mContinuingLastGesture && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) { recentsAttachedToAppWindow = true; @@ -540,9 +499,10 @@ public class WindowTransformSwipeHandler } private void buildAnimationController() { - if (mGestureEndTarget == HOME || mHasLauncherTransitionControllerStarted) { - // We don't want a new mLauncherTransitionController if mGestureEndTarget == HOME (it - // has its own animation) or if we're already animating the current controller. + if (mGestureState.getEndTarget() == HOME || mHasLauncherTransitionControllerStarted) { + // We don't want a new mLauncherTransitionController if + // mGestureState.getEndTarget() == HOME (it has its own animation) or if we're already + // animating the current controller. return; } initTransitionEndpoints(mActivity.getDeviceProfile()); @@ -599,7 +559,7 @@ public class WindowTransformSwipeHandler } private void updateLauncherTransitionProgress() { - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { return; } // Normalize the progress to 0 to 1, as the animation controller will clamp it to that @@ -709,7 +669,7 @@ public class WindowTransformSwipeHandler @Override protected InputConsumer createNewInputProxyHandler() { - endRunningWindowAnim(mGestureEndTarget == HOME /* cancel */); + endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); endLauncherTransitionController(); if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { // Hide the task view, if not already hidden @@ -731,6 +691,24 @@ public class WindowTransformSwipeHandler } } + private void onEndTargetSet() { + switch (mGestureState.getEndTarget()) { + case HOME: + mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); + break; + case RECENTS: + mStateCallback.setState(STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT + | STATE_SCREENSHOT_VIEW_SHOWN); + break; + case NEW_TASK: + mStateCallback.setState(STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT); + break; + case LAST_TASK: + mStateCallback.setState(STATE_RESUME_LAST_TASK); + break; + } + } + private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling, boolean isCancel) { final GestureEndTarget endTarget; @@ -800,7 +778,7 @@ public class WindowTransformSwipeHandler float currentShift = mCurrentShift.value; final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity, isFling, isCancel); - float endShift = endTarget.endShift; + float endShift = endTarget.isLauncher ? 1 : 0; final float startShift; Interpolator interpolator = DEACCEL; if (!isFling) { @@ -903,11 +881,12 @@ public class WindowTransformSwipeHandler @UiThread private void animateToProgressInternal(float start, float end, long duration, Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) { - mGestureEndTarget = target; + // Set the state, but don't notify until the animation completes + mGestureState.setEndTarget(target, false /* isAtomic */); maybeUpdateRecentsAttachedState(); - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { HomeAnimationFactory homeAnimFactory; if (mActivity != null) { homeAnimFactory = mActivityInterface.prepareHomeUI(mActivity); @@ -934,7 +913,8 @@ public class WindowTransformSwipeHandler windowAnim.addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { - setStateOnUiThread(target.endState); + // Finalize the state and notify of the change + mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } }); windowAnim.start(velocityPxPerMs); @@ -959,10 +939,9 @@ public class WindowTransformSwipeHandler // We are about to launch the current running task, so use LAST_TASK state // instead of NEW_TASK. This could happen, for example, if our scroll is // aborted after we determined the target to be NEW_TASK. - setStateOnUiThread(LAST_TASK.endState); - } else { - setStateOnUiThread(target.endState); + mGestureState.setEndTarget(LAST_TASK); } + mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } }); windowAnim.start(); @@ -970,7 +949,7 @@ public class WindowTransformSwipeHandler } // Always play the entire launcher animation when going home, since it is separate from // the animation that has been controlled thus far. - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { start = 0; } @@ -1029,14 +1008,9 @@ public class WindowTransformSwipeHandler } @Override - public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) { - if (mGestureEndTarget != null) { - sharedState.canGestureBeContinued = mGestureEndTarget.canBeContinued; - sharedState.goingToLauncher = mGestureEndTarget.isLauncher; - } - - if (sharedState.canGestureBeContinued) { - cancelCurrentAnimation(sharedState); + public void onConsumerAboutToBeSwitched() { + if (!mGestureState.isRunningAnimationToLauncher()) { + cancelCurrentAnimation(); } else { reset(); } @@ -1075,7 +1049,7 @@ public class WindowTransformSwipeHandler * Cancels any running animation so that the active target can be overriden by a new swipe * handle (in case of quick switch). */ - private void cancelCurrentAnimation(SwipeSharedState sharedState) { + private void cancelCurrentAnimation() { mCanceled = true; mCurrentShift.cancelAnimation(); if (mLauncherTransitionController != null && mLauncherTransitionController @@ -1093,7 +1067,7 @@ public class WindowTransformSwipeHandler ? newRunningTaskView.getTask().key.id : -1; mRecentsView.setCurrentTask(newRunningTaskId); - sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId); + mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId); } } @@ -1160,7 +1134,7 @@ public class WindowTransformSwipeHandler mTaskSnapshot = mRecentsAnimationController.screenshotTask(mRunningTaskId); } final TaskView taskView; - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { // Capture the screenshot before finishing the transition to home to ensure it's // taken in the correct orientation, but no need to update the thumbnail. taskView = null; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java index 0b5129c079..2f73fc1c57 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java @@ -22,11 +22,6 @@ public abstract class DelegateInputConsumer implements InputConsumer { mState = STATE_INACTIVE; } - @Override - public boolean useSharedSwipeState() { - return mDelegate.useSharedSwipeState(); - } - @Override public boolean allowInterceptByParent() { return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 980cfad4e9..8fb2e2ae64 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -44,7 +44,6 @@ import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.TaskAnimationManager; @@ -79,12 +78,10 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; private final float mTouchSlopSquared; - private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final PointF mTouchDown = new PointF(); private final AppWindowAnimationHelper mAppWindowAnimationHelper; - private int mLogId; private final AppWindowAnimationHelper.TransformParams mTransformParams; private final Point mDisplaySize; private final MultiStateCallback mStateCallback; @@ -100,16 +97,13 @@ public class DeviceLockedInputConsumer implements InputConsumer, public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, - SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - int runningTaskId, int logId) { + InputMonitorCompat inputMonitorCompat, int runningTaskId) { mContext = context; mDeviceState = deviceState; mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mTouchSlopSquared = squaredTouchSlop(context); - mSwipeSharedState = swipeSharedState; mAppWindowAnimationHelper = new AppWindowAnimationHelper(context); - mLogId = logId; mTransformParams = new AppWindowAnimationHelper.TransformParams(); mInputMonitorCompat = inputMonitorCompat; mRunningTaskId = runningTaskId; @@ -216,7 +210,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) - .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); + .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 4e01f6f632..5b76ba508f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -15,14 +15,14 @@ */ package com.android.quickstep.inputconsumers; +import static com.android.quickstep.GestureState.GestureEndTarget.HOME; +import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID; import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL; import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.HOME; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.LAST_TASK; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.NEW_TASK; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.animation.Animator; @@ -35,6 +35,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; +import android.util.ArrayMap; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -43,13 +44,13 @@ import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.GestureState; +import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsActivity; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsModel; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.RecentsAnimationTargets; @@ -83,27 +84,23 @@ public class FallbackNoButtonInputConsumer extends private static final int STATE_APP_CONTROLLER_RECEIVED = getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED"); - public enum GestureEndTarget { - HOME(3, 100, 1), - RECENTS(1, 300, 0), - LAST_TASK(0, 150, 1), - NEW_TASK(0, 150, 1); - + public static class EndTargetAnimationParams { private final float mEndProgress; private final long mDurationMultiplier; private final float mLauncherAlpha; - GestureEndTarget(float endProgress, long durationMultiplier, float launcherAlpha) { + EndTargetAnimationParams(float endProgress, long durationMultiplier, float launcherAlpha) { mEndProgress = endProgress; mDurationMultiplier = durationMultiplier; mLauncherAlpha = launcherAlpha; } } + private static ArrayMap + mEndTargetAnimationParams = new ArrayMap(); private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged); private boolean mIsMotionPaused = false; - private GestureEndTarget mEndTarget; private final boolean mInQuickSwitchMode; private final boolean mContinuingLastGesture; @@ -136,6 +133,12 @@ public class FallbackNoButtonInputConsumer extends mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); } + // Going home has an extra long progress to ensure that it animates into the screen + mEndTargetAnimationParams.put(HOME, new EndTargetAnimationParams(3, 100, 1)); + mEndTargetAnimationParams.put(RECENTS, new EndTargetAnimationParams(1, 300, 0)); + mEndTargetAnimationParams.put(LAST_TASK, new EndTargetAnimationParams(0, 150, 1)); + mEndTargetAnimationParams.put(NEW_TASK, new EndTargetAnimationParams(0, 150, 1)); + initStateCallbacks(); } @@ -161,7 +164,7 @@ public class FallbackNoButtonInputConsumer extends } private void onLauncherAlphaChanged() { - if (mRecentsAnimationTargets != null && mEndTarget == null) { + if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) { applyTransformUnchecked(); } } @@ -247,7 +250,7 @@ public class FallbackNoButtonInputConsumer extends @Override public void onGestureCancelled() { updateDisplacement(0); - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); setStateOnUiThread(STATE_GESTURE_CANCELLED); } @@ -256,28 +259,29 @@ public class FallbackNoButtonInputConsumer extends mEndVelocityPxPerMs.set(0, velocity.y / 1000); if (mInQuickSwitchMode) { // For now set it to non-null, it will be reset before starting the animation - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); } else { float flingThreshold = mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_velocity); boolean isFling = Math.abs(endVelocity) > flingThreshold; if (isFling) { - mEndTarget = endVelocity < 0 ? HOME : LAST_TASK; + mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK); } else if (mIsMotionPaused) { - mEndTarget = RECENTS; + mGestureState.setEndTarget(RECENTS); } else { - mEndTarget = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? HOME : LAST_TASK; + mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW + ? HOME + : LAST_TASK); } } setStateOnUiThread(STATE_GESTURE_COMPLETED); } @Override - public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) { - if (mInQuickSwitchMode && mEndTarget != null) { - sharedState.canGestureBeContinued = true; - sharedState.goingToLauncher = false; + public void onConsumerAboutToBeSwitched() { + if (mInQuickSwitchMode && mGestureState.getEndTarget() != null) { + mGestureState.setEndTarget(HOME); mCanceled = true; mCurrentShift.cancelAnimation(); @@ -293,7 +297,7 @@ public class FallbackNoButtonInputConsumer extends ? newRunningTaskView.getTask().key.id : -1; mRecentsView.setCurrentTask(newRunningTaskId); - sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId); + mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId); } mRecentsView.setOnScrollChangeListener(null); } @@ -319,7 +323,7 @@ public class FallbackNoButtonInputConsumer extends } private void finishAnimationTargetSetAnimationComplete() { - switch (mEndTarget) { + switch (mGestureState.getEndTarget()) { case HOME: { if (mSwipeUpOverHome) { mRecentsAnimationController.finish(false, null, false); @@ -370,17 +374,20 @@ public class FallbackNoButtonInputConsumer extends // Recalculate the end target, some views might have been initialized after // gesture has ended. if (mRecentsView == null || !hasTargets()) { - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); } else { final int runningTaskIndex = mRecentsView.getRunningTaskIndex(); final int taskToLaunch = mRecentsView.getNextPage(); - mEndTarget = (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex) - ? NEW_TASK : LAST_TASK; + mGestureState.setEndTarget( + (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex) + ? NEW_TASK + : LAST_TASK); } } - float endProgress = mEndTarget.mEndProgress; - long duration = (long) (mEndTarget.mDurationMultiplier * + EndTargetAnimationParams params = mEndTargetAnimationParams.get(mGestureState.getEndTarget()); + float endProgress = params.mEndProgress; + long duration = (long) (params.mDurationMultiplier * Math.abs(endProgress - mCurrentShift.value)); if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); @@ -395,7 +402,7 @@ public class FallbackNoButtonInputConsumer extends } }; - if (mEndTarget == HOME && !mRunningOverHome) { + if (mGestureState.getEndTarget() == HOME && !mRunningOverHome) { RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration); anim.addAnimatorListener(endListener); anim.start(mEndVelocityPxPerMs); @@ -404,7 +411,7 @@ public class FallbackNoButtonInputConsumer extends AnimatorSet anim = new AnimatorSet(); anim.play(mLauncherAlpha.animateToValue( - mLauncherAlpha.value, mEndTarget.mLauncherAlpha)); + mLauncherAlpha.value, params.mLauncherAlpha)); anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress)); anim.setDuration(duration); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 6ba326c650..c4792504d7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -54,7 +54,6 @@ import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TaskAnimationManager; @@ -85,7 +84,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private RecentsAnimationCallbacks mActiveCallbacks; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; - private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final SysUINavigationMode.Mode mMode; private final BaseActivityInterface mActivityInterface; @@ -126,16 +124,14 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC ActivityManagerWrapper.getInstance().cancelRecentsAnimation( true /* restoreHomeStackPosition */); }; - private int mLogId; public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, Consumer onCompleteCallback, - SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - boolean disableHorizontalSwipe, Factory handlerFactory, int logId) { + InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe, + Factory handlerFactory) { super(base); - mLogId = logId; mDeviceState = deviceState; mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; @@ -154,7 +150,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; - mSwipeSharedState = swipeSharedState; mNavBarPosition = new NavBarPosition(base); mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); @@ -347,7 +342,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC notifyGestureStarted(); } else { Intent intent = mInteractionHandler.getLaunchIntent(); - intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); + intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mInteractionHandler); } @@ -404,7 +399,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // The consumer is being switched while we are active. Set up the shared state to be // used by the next animation removeListener(); - mInteractionHandler.onConsumerAboutToBeSwitched(mSwipeSharedState); + mInteractionHandler.onConsumerAboutToBeSwitched(); } } @@ -432,11 +427,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } } - @Override - public boolean useSharedSwipeState() { - return mInteractionHandler != null; - } - @Override public boolean allowInterceptByParent() { return !mPassedPilferInputSlop; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java index b22a75b7c7..5ef5246c08 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java @@ -42,7 +42,6 @@ public class ResetGestureInputConsumer implements InputConsumer { if (ev.getAction() == MotionEvent.ACTION_DOWN && mTaskAnimationManager.isRecentsAnimationRunning()) { mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); - TouchInteractionService.getSwipeSharedState().clearAllState(); } } } diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index 4bd962a5ff..67eb9de1b9 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -15,8 +15,12 @@ */ package com.android.quickstep; +import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; + import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.systemui.shared.recents.model.ThumbnailData; +import java.util.ArrayList; /** * Manages the state for an active system gesture, listens for events from the system and Launcher, @@ -24,30 +28,202 @@ import com.android.systemui.shared.recents.model.ThumbnailData; */ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener { - // Needed to interact with the current activity - private BaseActivityInterface mActivityInterface; + /** + * Defines the end targets of a gesture and the associated state. + */ + public enum GestureEndTarget { + HOME(true, ContainerType.WORKSPACE, false), - public GestureState(BaseActivityInterface activityInterface) { - mActivityInterface = activityInterface; + RECENTS(true, ContainerType.TASKSWITCHER, true), + + NEW_TASK(false, ContainerType.APP, true), + + LAST_TASK(false, ContainerType.APP, false); + + GestureEndTarget(boolean isLauncher, int containerType, + boolean recentsAttachedToAppWindow) { + this.isLauncher = isLauncher; + this.containerType = containerType; + this.recentsAttachedToAppWindow = recentsAttachedToAppWindow; + } + + /** Whether the target is in the launcher activity. Implicitly, if the end target is going + to Launcher, then we can not interrupt the animation to start another gesture. */ + public final boolean isLauncher; + /** Used to log where the user ended up after the gesture ends */ + public final int containerType; + /** Whether RecentsView should be attached to the window as we animate to this target */ + public final boolean recentsAttachedToAppWindow; } + private static final ArrayList STATE_NAMES = new ArrayList<>(); + private static int FLAG_COUNT = 0; + private static int getFlagForIndex(String name) { + if (DEBUG_STATES) { + STATE_NAMES.add(name); + } + int index = 1 << FLAG_COUNT; + FLAG_COUNT++; + return index; + } + + // Called when the end target as been set + public static final int STATE_END_TARGET_SET = + getFlagForIndex("STATE_END_TARGET_SET"); + + // Called when the end target animation has finished + public static final int STATE_END_TARGET_ANIMATION_FINISHED = + getFlagForIndex("STATE_END_TARGET_ANIMATION_FINISHED"); + + // Called when the recents animation has been requested to start + public static final int STATE_RECENTS_ANIMATION_INITIALIZED = + getFlagForIndex("STATE_RECENTS_ANIMATION_INITIALIZED"); + + // Called when the recents animation is started and the TaskAnimationManager has been updated + // with the controller and targets + public static final int STATE_RECENTS_ANIMATION_STARTED = + getFlagForIndex("STATE_RECENTS_ANIMATION_STARTED"); + + // Called when the recents animation is canceled + public static final int STATE_RECENTS_ANIMATION_CANCELED = + getFlagForIndex("STATE_RECENTS_ANIMATION_CANCELED"); + + // Called when the recents animation finishes + public static final int STATE_RECENTS_ANIMATION_FINISHED = + getFlagForIndex("STATE_RECENTS_ANIMATION_FINISHED"); + + // Always called when the recents animation ends (regardless of cancel or finish) + public static final int STATE_RECENTS_ANIMATION_ENDED = + getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED"); + + + // Needed to interact with the current activity + private final BaseActivityInterface mActivityInterface; + private final MultiStateCallback mStateCallback; + private final int mGestureId; + + private GestureEndTarget mEndTarget; + // TODO: This can be removed once we stop finishing the animation when starting a new task + private int mFinishingRecentsAnimationTaskId = -1; + + public GestureState(BaseActivityInterface activityInterface, int gestureId) { + mActivityInterface = activityInterface; + mGestureId = gestureId; + mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0])); + } + + public GestureState() { + // Do nothing, only used for initializing the gesture state prior to user unlock + mActivityInterface = null; + mGestureId = -1; + mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0])); + } + + /** + * Sets the given {@param stateFlag}s. + */ + public void setState(int stateFlag) { + mStateCallback.setState(stateFlag); + } + + /** + * Adds a callback for when the states matching the given {@param stateMask} is set. + */ + public void addCallback(int stateMask, Runnable callback) { + mStateCallback.addCallback(stateMask, callback); + } + + /** + * @return the interface to the activity handing the UI updates for this gesture. + */ public BaseActivityInterface getActivityInterface() { return mActivityInterface; } + /** + * @return the id for this particular gesture. + */ + public int getGestureId() { + return mGestureId; + } + + /** + * @return the end target for this gesture (if known). + */ + public GestureEndTarget getEndTarget() { + return mEndTarget; + } + + /** + * @return whether the current gesture is still running a recents animation to a state in the + * Launcher or Recents activity. + */ + public boolean isRunningAnimationToLauncher() { + return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher; + } + + /** + * Sets the end target of this gesture and immediately notifies the state changes. + */ + public void setEndTarget(GestureEndTarget target) { + setEndTarget(target, true /* isAtomic */); + } + + /** + * Sets the end target of this gesture, but if {@param isAtomic} is {@code false}, then the + * caller must explicitly set {@link #STATE_END_TARGET_ANIMATION_FINISHED} themselves. + */ + public void setEndTarget(GestureEndTarget target, boolean isAtomic) { + mEndTarget = target; + mStateCallback.setState(STATE_END_TARGET_SET); + if (isAtomic) { + mStateCallback.setState(STATE_END_TARGET_ANIMATION_FINISHED); + } + } + + /** + * @return the id for the task that was about to be launched following the finish of the recents + * animation. Only defined between when the finish-recents call was made and the launch + * activity call is made. + */ + public int getFinishingRecentsAnimationTaskId() { + return mFinishingRecentsAnimationTaskId; + } + + /** + * Sets the id for the task will be launched after the recents animation is finished. Once the + * animation has finished then the id will be reset to -1. + */ + public void setFinishingRecentsAnimationTaskId(int taskId) { + mFinishingRecentsAnimationTaskId = taskId; + mStateCallback.addCallback(STATE_RECENTS_ANIMATION_FINISHED, () -> { + mFinishingRecentsAnimationTaskId = -1; + }); + } + + /** + * @return whether the recents animation is started but not yet ended + */ + public boolean isRecentsAnimationRunning() { + return mStateCallback.hasStates(STATE_RECENTS_ANIMATION_INITIALIZED) && + !mStateCallback.hasStates(STATE_RECENTS_ANIMATION_ENDED); + } + @Override public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED); } @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED); + mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED); } @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_FINISHED); + mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED); } } diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java index 62c0ded534..918645d9aa 100644 --- a/quickstep/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/src/com/android/quickstep/InputConsumer.java @@ -52,10 +52,6 @@ public interface InputConsumer { int getType(); - default boolean useSharedSwipeState() { - return false; - } - /** * Returns true if the user has crossed the threshold for it to be an explicit action. */ @@ -65,6 +61,8 @@ public interface InputConsumer { /** * Called by the event queue when the consumer is about to be switched to a new consumer. + * Consumers should update the state accordingly here before the state is passed to the new + * consumer. */ default void onConsumerAboutToBeSwitched() { } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java similarity index 100% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java rename to quickstep/src/com/android/quickstep/MultiStateCallback.java diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 557be5b554..6873899c6b 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -17,6 +17,7 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import android.content.Intent; import android.util.Log; @@ -95,6 +96,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mCallbacks.addListener(listener); UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() .startRecentsActivity(intent, null, mCallbacks, null, null)); + gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED); return mCallbacks; } From 981ef3a88a45d3656e7ed13288ce77e838418302 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 8 Oct 2019 14:32:15 -0700 Subject: [PATCH 007/119] 11/ Update MultiStateCallbacks to support multiple callbacks - Allow multiple callbacks to be set for the same state - Expose method to set state on ui thread directly - Ensure callbacks are made immediately if the state is already set - Clarify that the one shot callbacks vs the state listeners Bug: 141886704 Change-Id: I8ea0dcd2821ee18d071706eaddeb2852afa13f30 --- .../android/quickstep/BaseSwipeUpHandler.java | 13 +-- .../WindowTransformSwipeHandler.java | 70 +++++++-------- .../DeviceLockedInputConsumer.java | 2 +- .../FallbackNoButtonInputConsumer.java | 24 ++--- .../ResetGestureInputConsumer.java | 1 - .../com/android/quickstep/GestureState.java | 6 +- .../android/quickstep/MultiStateCallback.java | 88 ++++++++++++++----- 7 files changed, 117 insertions(+), 87 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 42d0a0c99d..a16c365af1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -130,7 +130,6 @@ public abstract class BaseSwipeUpHandler mStateCallback.setState(stateFlag)); - } - } - protected void performHapticFeedback() { if (!mVibrator.hasVibrator()) { return; @@ -253,9 +244,9 @@ public abstract class BaseSwipeUpHandler private void initStateCallbacks() { mStateCallback = new MultiStateCallback(STATE_NAMES); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED, + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED, this::onLauncherPresentAndGestureStarted); - mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED, + mStateCallback.runOnceAtState(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED, this::initializeLauncherAnimationController); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN, + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN, this::launcherFrameDrawn); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED | STATE_GESTURE_CANCELLED, this::resetStateForAnimationCancel); - mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED, + mStateCallback.runOnceAtState(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED, this::sendRemoteAnimationsToAnimationFactory); - mStateCallback.addCallback(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED, + mStateCallback.runOnceAtState(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED, this::resumeLastTask); - mStateCallback.addCallback(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED, + mStateCallback.runOnceAtState(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED, this::startNewTask); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_DRAWN | STATE_CAPTURE_SCREENSHOT, this::switchToScreenshot); - mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED + mStateCallback.runOnceAtState(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED | STATE_SCALED_CONTROLLER_RECENTS, this::finishCurrentTransitionToRecents); - mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED + mStateCallback.runOnceAtState(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED | STATE_SCALED_CONTROLLER_HOME, this::finishCurrentTransitionToHome); - mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED, + mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED, this::reset); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_DRAWN | STATE_SCALED_CONTROLLER_RECENTS | STATE_CURRENT_TASK_FINISHED | STATE_GESTURE_COMPLETED | STATE_GESTURE_STARTED, this::setupLauncherUiAfterSwipeUpToRecentsAnimation); - mGestureState.addCallback(STATE_END_TARGET_ANIMATION_FINISHED, - this::onEndTargetSet); + mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, this::onEndTargetSet); - mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, + mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler); + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, this::invalidateHandlerWithLauncher); - mStateCallback.addCallback(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK, + mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK, this::notifyTransitionCancelled); if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT + mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT, (b) -> mRecentsView.setRunningTaskHidden(!b)); } @@ -330,7 +329,7 @@ public class WindowTransformSwipeHandler // Launcher is visible, but might be about to stop. Thus, if we prepare recents // now, it might get overridden by moveToRestState() in onStop(). To avoid this, // wait until the next gesture (and possibly launcher) starts. - mStateCallback.addCallback(STATE_GESTURE_STARTED, initAnimFactory); + mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, initAnimFactory); } else { initAnimFactory.run(); } @@ -596,9 +595,9 @@ public class WindowTransformSwipeHandler super.onRecentsAnimationStart(controller, targets); // Only add the callback to enable the input consumer after we actually have the controller - mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, + mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, mRecentsAnimationController::enableInputConsumer); - setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); + mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); mPassedOverviewThreshold = false; } @@ -608,7 +607,7 @@ public class WindowTransformSwipeHandler super.onRecentsAnimationCanceled(thumbnailData); mRecentsView.setRecentsAnimationTargets(null, null); mActivityInitListener.unregister(); - setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation"); } @@ -616,7 +615,7 @@ public class WindowTransformSwipeHandler public void onGestureStarted() { notifyGestureStartedAsync(); mShiftAtGestureStart = mCurrentShift.value; - setStateOnUiThread(STATE_GESTURE_STARTED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED); mGestureStarted = true; } @@ -639,7 +638,7 @@ public class WindowTransformSwipeHandler @Override public void onGestureCancelled() { updateDisplacement(0); - setStateOnUiThread(STATE_GESTURE_COMPLETED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); mLogAction = Touch.SWIPE_NOOP; handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */); } @@ -654,7 +653,7 @@ public class WindowTransformSwipeHandler float flingThreshold = mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_velocity); boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold; - setStateOnUiThread(STATE_GESTURE_COMPLETED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); mLogAction = isFling ? Touch.FLING : Touch.SWIPE; boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x); @@ -906,7 +905,7 @@ public class WindowTransformSwipeHandler return AnimatorPlaybackController.wrap(new AnimatorSet(), duration); } }; - mStateCallback.addChangeHandler(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, + mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, isPresent -> mRecentsView.startHome()); } RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory); @@ -1042,7 +1041,7 @@ public class WindowTransformSwipeHandler } private void reset() { - setStateOnUiThread(STATE_HANDLER_INVALIDATED); + mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); } /** @@ -1122,10 +1121,10 @@ public class WindowTransformSwipeHandler } mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */); } - setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); + mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else if (!hasTargets()) { // If there are no targets, then we don't need to capture anything - setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); + mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else { boolean finishTransitionPosted = false; if (mRecentsAnimationController != null) { @@ -1145,14 +1144,15 @@ public class WindowTransformSwipeHandler // Defer finishing the animation until the next launcher frame with the // new thumbnail finishTransitionPosted = ViewUtils.postDraw(taskView, - () -> setStateOnUiThread(STATE_SCREENSHOT_CAPTURED), this::isCanceled); + () -> mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED), + this::isCanceled); } } if (!finishTransitionPosted) { // If we haven't posted a draw callback, set the state immediately. Object traceToken = TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT, TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS); - setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); + mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); TraceHelper.INSTANCE.endSection(traceToken); } } @@ -1160,14 +1160,14 @@ public class WindowTransformSwipeHandler private void finishCurrentTransitionToRecents() { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); + mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); } else if (!hasTargets()) { // If there are no targets, then there is nothing to finish - setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); + mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); } else { synchronized (mRecentsAnimationController) { mRecentsAnimationController.finish(true /* toRecents */, - () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); + () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } } ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); @@ -1176,7 +1176,7 @@ public class WindowTransformSwipeHandler private void finishCurrentTransitionToHome() { synchronized (mRecentsAnimationController) { mRecentsAnimationController.finish(true /* toRecents */, - () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED), + () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED), true /* sendUserLeaveHint */); } ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 8fb2e2ae64..370f1611eb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -113,7 +113,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, // Init states mStateCallback = new MultiStateCallback(STATE_NAMES); - mStateCallback.addCallback(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED, + mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED, this::endRemoteAnimation); mVelocityTracker = VelocityTracker.obtain(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 5b76ba508f..e062fc1456 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -145,20 +145,20 @@ public class FallbackNoButtonInputConsumer extends private void initStateCallbacks() { mStateCallback = new MultiStateCallback(STATE_NAMES); - mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, + mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::onHandlerInvalidated); - mStateCallback.addCallback(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED, + mStateCallback.runOnceAtState(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED, this::onHandlerInvalidatedWithRecents); - mStateCallback.addCallback(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED, + mStateCallback.runOnceAtState(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED, this::finishAnimationTargetSetAnimationComplete); if (mInQuickSwitchMode) { - mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED + mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED | STATE_RECENTS_PRESENT, this::finishAnimationTargetSet); } else { - mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED, + mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED, this::finishAnimationTargetSet); } } @@ -186,7 +186,7 @@ public class FallbackNoButtonInputConsumer extends mRecentsView.onGestureAnimationStart(mRunningTaskId); } } - setStateOnUiThread(STATE_RECENTS_PRESENT); + mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT); return true; } @@ -251,7 +251,7 @@ public class FallbackNoButtonInputConsumer extends public void onGestureCancelled() { updateDisplacement(0); mGestureState.setEndTarget(LAST_TASK); - setStateOnUiThread(STATE_GESTURE_CANCELLED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED); } @Override @@ -275,7 +275,7 @@ public class FallbackNoButtonInputConsumer extends : LAST_TASK); } } - setStateOnUiThread(STATE_GESTURE_COMPLETED); + mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); } @Override @@ -302,7 +302,7 @@ public class FallbackNoButtonInputConsumer extends mRecentsView.setOnScrollChangeListener(null); } } else { - setStateOnUiThread(STATE_HANDLER_INVALIDATED); + mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); } } @@ -366,7 +366,7 @@ public class FallbackNoButtonInputConsumer extends } } - setStateOnUiThread(STATE_HANDLER_INVALIDATED); + mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); } private void finishAnimationTargetSet() { @@ -436,14 +436,14 @@ public class FallbackNoButtonInputConsumer extends } applyTransformUnchecked(); - setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); + mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); } @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { super.onRecentsAnimationCanceled(thumbnailData); mRecentsView.setRecentsAnimationTargets(null, null); - setStateOnUiThread(STATE_HANDLER_INVALIDATED); + mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java index 5ef5246c08..d34b40bf0c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java @@ -19,7 +19,6 @@ import android.view.MotionEvent; import com.android.quickstep.InputConsumer; import com.android.quickstep.TaskAnimationManager; -import com.android.quickstep.TouchInteractionService; /** * A NO_OP input consumer which also resets any pending gesture diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index 67eb9de1b9..98ff410bad 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -129,8 +129,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL /** * Adds a callback for when the states matching the given {@param stateMask} is set. */ - public void addCallback(int stateMask, Runnable callback) { - mStateCallback.addCallback(stateMask, callback); + public void runOnceAtState(int stateMask, Runnable callback) { + mStateCallback.runOnceAtState(stateMask, callback); } /** @@ -196,7 +196,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL */ public void setFinishingRecentsAnimationTaskId(int taskId) { mFinishingRecentsAnimationTaskId = taskId; - mStateCallback.addCallback(STATE_RECENTS_ANIMATION_FINISHED, () -> { + mStateCallback.runOnceAtState(STATE_RECENTS_ANIMATION_FINISHED, () -> { mFinishingRecentsAnimationTaskId = -1; }); } diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java index 357c9fc35e..6c65e01c20 100644 --- a/quickstep/src/com/android/quickstep/MultiStateCallback.java +++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java @@ -15,11 +15,17 @@ */ package com.android.quickstep; +import static com.android.launcher3.Utilities.postAsyncCallback; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.os.Looper; import android.util.Log; import android.util.SparseArray; import com.android.launcher3.config.FeatureFlags; +import java.util.ArrayList; +import java.util.LinkedList; import java.util.StringJoiner; import java.util.function.Consumer; @@ -31,16 +37,29 @@ public class MultiStateCallback { private static final String TAG = "MultiStateCallback"; public static final boolean DEBUG_STATES = false; - private final SparseArray mCallbacks = new SparseArray<>(); - private final SparseArray> mStateChangeHandlers = new SparseArray<>(); + private final SparseArray> mCallbacks = new SparseArray<>(); + private final SparseArray>> mStateChangeListeners = + new SparseArray<>(); private final String[] mStateNames; + private int mState = 0; + public MultiStateCallback(String[] stateNames) { mStateNames = DEBUG_STATES ? stateNames : null; } - private int mState = 0; + /** + * Adds the provided state flags to the global state on the UI thread and executes any callbacks + * as a result. + */ + public void setStateOnUiThread(int stateFlag) { + if (Looper.myLooper() == Looper.getMainLooper()) { + setState(stateFlag); + } else { + postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> setState(stateFlag)); + } + } /** * Adds the provided state flags to the global state and executes any callbacks as a result. @@ -51,7 +70,7 @@ public class MultiStateCallback { + convertToFlagNames(stateFlag) + " to " + convertToFlagNames(mState)); } - int oldState = mState; + final int oldState = mState; mState = mState | stateFlag; int count = mCallbacks.size(); @@ -59,15 +78,13 @@ public class MultiStateCallback { int state = mCallbacks.keyAt(i); if ((mState & state) == state) { - Runnable callback = mCallbacks.valueAt(i); - if (callback != null) { - // Set the callback to null, so that it does not run again. - mCallbacks.setValueAt(i, null); - callback.run(); + LinkedList callbacks = mCallbacks.valueAt(i); + while (!callbacks.isEmpty()) { + callbacks.pollFirst().run(); } } } - notifyStateChangeHandlers(oldState); + notifyStateChangeListeners(oldState); } /** @@ -82,38 +99,61 @@ public class MultiStateCallback { int oldState = mState; mState = mState & ~stateFlag; - notifyStateChangeHandlers(oldState); + notifyStateChangeListeners(oldState); } - private void notifyStateChangeHandlers(int oldState) { - int count = mStateChangeHandlers.size(); + private void notifyStateChangeListeners(int oldState) { + int count = mStateChangeListeners.size(); for (int i = 0; i < count; i++) { - int state = mStateChangeHandlers.keyAt(i); + int state = mStateChangeListeners.keyAt(i); boolean wasOn = (state & oldState) == state; boolean isOn = (state & mState) == state; if (wasOn != isOn) { - mStateChangeHandlers.valueAt(i).accept(isOn); + ArrayList> listeners = mStateChangeListeners.valueAt(i); + for (Consumer listener : listeners) { + listener.accept(isOn); + } } } } /** - * Sets the callbacks to be run when the provided states are enabled. - * The callback is only run once. + * Sets a callback to be run when the provided states in the given {@param stateMask} is + * enabled. The callback is only run *once*, and if the states are already set at the time of + * this call then the callback will be made immediately. */ - public void addCallback(int stateMask, Runnable callback) { - if (FeatureFlags.IS_DOGFOOD_BUILD && mCallbacks.get(stateMask) != null) { - throw new IllegalStateException("Multiple callbacks on same state"); + public void runOnceAtState(int stateMask, Runnable callback) { + if ((mState & stateMask) == stateMask) { + callback.run(); + } else { + final LinkedList callbacks; + if (mCallbacks.indexOfKey(stateMask) >= 0) { + callbacks = mCallbacks.get(stateMask); + if (FeatureFlags.IS_DOGFOOD_BUILD && callbacks.contains(callback)) { + throw new IllegalStateException("Existing callback for state found"); + } + } else { + callbacks = new LinkedList<>(); + mCallbacks.put(stateMask, callbacks); + } + callbacks.add(callback); } - mCallbacks.put(stateMask, callback); } /** - * Sets the handler to be called when the provided states are enabled or disabled. + * Adds a persistent listener to be called states in the given {@param stateMask} are enabled + * or disabled. */ - public void addChangeHandler(int stateMask, Consumer handler) { - mStateChangeHandlers.put(stateMask, handler); + public void addChangeListener(int stateMask, Consumer listener) { + final ArrayList> listeners; + if (mStateChangeListeners.indexOfKey(stateMask) >= 0) { + listeners = mStateChangeListeners.get(stateMask); + } else { + listeners = new ArrayList<>(); + mStateChangeListeners.put(stateMask, listeners); + } + listeners.add(listener); } public int getState() { From dd9d1ea1bfb3f22b00dc04f54ba47ccb81c38a55 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 8 Oct 2019 14:51:55 -0700 Subject: [PATCH 008/119] 12/ Clean up some ActivityInterface calls - Require users of the activity interface to go through the interface to get the raw activity - Remove calls that pass in the activity since the interface already can get the reference to it internally (and the interface always has the reference before the caller) Bug: 141886704 Change-Id: I13e52caba593db918e8a7764c751044142fe7ece Signed-off-by: Winson Chung --- .../AppToOverviewAnimationProvider.java | 12 +-- .../quickstep/FallbackActivityInterface.java | 12 +-- .../quickstep/GoActivityInterface.java | 8 +- .../quickstep/LauncherActivityInterface.java | 21 ++--- .../AppToOverviewAnimationProvider.java | 4 +- .../android/quickstep/BaseSwipeUpHandler.java | 6 +- .../quickstep/FallbackActivityInterface.java | 25 ++++-- .../quickstep/LauncherActivityInterface.java | 87 ++++++++++--------- .../quickstep/OverviewCommandHelper.java | 3 +- .../quickstep/TouchInteractionService.java | 4 +- .../WindowTransformSwipeHandler.java | 13 +-- .../FallbackNoButtonInputConsumer.java | 6 +- .../QuickCaptureInputConsumer.java | 8 +- .../quickstep/BaseActivityInterface.java | 20 ++--- 14 files changed, 125 insertions(+), 104 deletions(-) diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 6b50088221..04753d2527 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -46,13 +46,13 @@ final class AppToOverviewAnimationProvider imple RemoteAnimationProvider { private static final String TAG = "AppToOverviewAnimationProvider"; - private final BaseActivityInterface mHelper; + private final BaseActivityInterface mActivityInterface; private final int mTargetTaskId; private IconRecentsView mRecentsView; private AppToOverviewAnimationListener mAnimationReadyListener; - AppToOverviewAnimationProvider(BaseActivityInterface helper, int targetTaskId) { - mHelper = helper; + AppToOverviewAnimationProvider(BaseActivityInterface activityInterface, int targetTaskId) { + mActivityInterface = activityInterface; mTargetTaskId = targetTaskId; } @@ -68,15 +68,15 @@ final class AppToOverviewAnimationProvider imple /** * Callback for when the activity is ready/initialized. * - * @param activity the activity that is ready * @param wasVisible true if it was visible before */ - boolean onActivityReady(T activity, Boolean wasVisible) { + boolean onActivityReady(Boolean wasVisible) { + T activity = mActivityInterface.getCreatedActivity(); if (mAnimationReadyListener != null) { mAnimationReadyListener.onActivityReady(activity); } BaseActivityInterface.AnimationFactory factory = - mHelper.prepareRecentsUI(activity, wasVisible, + mActivityInterface.prepareRecentsUI(wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); ValueAnimator anim = controller.getAnimationPlayer() diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index 2af8441853..ecb9472c72 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -29,8 +29,8 @@ import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.views.IconRecentsView; -import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; /** * {@link BaseActivityInterface} for recents when the default launcher is different than the @@ -43,12 +43,13 @@ public final class FallbackActivityInterface extends public FallbackActivityInterface() { } @Override - public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible, + public AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity, Consumer callback) { if (activityVisible) { return (transitionLength) -> { }; } + RecentsActivity activity = getCreatedActivity(); IconRecentsView rv = activity.getOverviewPanel(); rv.setUsingRemoteAnimation(true); rv.setAlpha(0); @@ -84,8 +85,9 @@ public final class FallbackActivityInterface extends @Override public ActivityInitListener createActivityInitListener( - BiPredicate onInitListener) { - return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); + Predicate onInitListener) { + return new ActivityInitListener<>((activity, alreadyOnHome) -> + onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER); } @Nullable @@ -115,5 +117,5 @@ public final class FallbackActivityInterface extends } @Override - public void onLaunchTaskSuccess(RecentsActivity activity) { } + public void onLaunchTaskSuccess() { } } diff --git a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java index 5ce0f4cdf5..b62d17ce2f 100644 --- a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java @@ -17,7 +17,7 @@ public abstract class GoActivityInterface implem BaseActivityInterface { @Override - public void onTransitionCancelled(T activity, boolean activityVisible) { + public void onTransitionCancelled(boolean activityVisible) { // Go transitions to overview are all atomic. } @@ -29,7 +29,7 @@ public abstract class GoActivityInterface implem } @Override - public void onSwipeUpToRecentsComplete(T activity) { + public void onSwipeUpToRecentsComplete() { // Go does not support swipe up gesture. } @@ -39,7 +39,7 @@ public abstract class GoActivityInterface implem } @Override - public HomeAnimationFactory prepareHomeUI(T activity) { + public HomeAnimationFactory prepareHomeUI() { // Go does not support gestures from app to home. return null; } @@ -63,7 +63,7 @@ public abstract class GoActivityInterface implem } @Override - public void onLaunchTaskFailed(T activity) { + public void onLaunchTaskFailed() { // Go does not support gestures from one task to another. } } diff --git a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 5bff8e8060..3e93480a95 100644 --- a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -26,8 +26,8 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.views.IconRecentsView; -import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; /** * {@link BaseActivityInterface} for the in-launcher recents. @@ -36,15 +36,15 @@ import java.util.function.Consumer; public final class LauncherActivityInterface extends GoActivityInterface { @Override - public AnimationFactory prepareRecentsUI(Launcher activity, - boolean activityVisible, boolean animateActivity, + public AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity, Consumer callback) { - LauncherState fromState = activity.getStateManager().getState(); - activity.getOverviewPanel().setUsingRemoteAnimation(true); + Launcher launcher = getCreatedActivity(); + LauncherState fromState = launcher.getStateManager().getState(); + launcher.getOverviewPanel().setUsingRemoteAnimation(true); //TODO: Implement this based off where the recents view needs to be for app => recents anim. return new AnimationFactory() { public void createActivityInterface(long transitionLength) { - callback.accept(activity.getStateManager().createAnimationToNewWorkspace( + callback.accept(launcher.getStateManager().createAnimationToNewWorkspace( fromState, OVERVIEW, transitionLength)); } @@ -54,9 +54,9 @@ public final class LauncherActivityInterface extends GoActivityInterface onInitListener) { - return new LauncherInitListener(onInitListener); + public LauncherInitListener createActivityInitListener(Predicate onInitListener) { + return new LauncherInitListener((activity, alreadyOnHome) -> + onInitListener.test(alreadyOnHome)); } @Override @@ -105,7 +105,8 @@ public final class LauncherActivityInterface extends GoActivityInterface imple activity.getOverviewPanel().showCurrentTask(mTargetTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); BaseActivityInterface.AnimationFactory factory = - mHelper.prepareRecentsUI(activity, wasVisible, + mHelper.prepareRecentsUI(wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); ValueAnimator anim = controller.getAnimationPlayer() @@ -102,7 +102,7 @@ final class AppToOverviewAnimationProvider imple anim.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { - mHelper.onSwipeUpToRecentsComplete(mActivity); + mHelper.onSwipeUpToRecentsComplete(); if (mRecentsView != null) { mRecentsView.animateUpRunningTaskIconScale(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index a16c365af1..939656eb3e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -239,10 +239,10 @@ public abstract class BaseSwipeUpHandler { resultCallback.accept(success); if (!success) { - mActivityInterface.onLaunchTaskFailed(mActivity); + mActivityInterface.onLaunchTaskFailed(); nextTask.notifyTaskLaunchFailed(TAG); } else { - mActivityInterface.onLaunchTaskSuccess(mActivity); + mActivityInterface.onLaunchTaskSuccess(); } }, MAIN_EXECUTOR.getHandler()); } @@ -359,7 +359,7 @@ public abstract class BaseSwipeUpHandler callback) { + RecentsActivity activity = getCreatedActivity(); if (activityVisible) { return (transitionLength) -> { }; } @@ -176,8 +180,9 @@ public final class FallbackActivityInterface implements @Override public ActivityInitListener createActivityInitListener( - BiPredicate onInitListener) { - return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); + Predicate onInitListener) { + return new ActivityInitListener<>((activity, alreadyOnHome) -> + onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER); } @Nullable @@ -228,13 +233,15 @@ public final class FallbackActivityInterface implements } @Override - public void onLaunchTaskFailed(RecentsActivity activity) { + public void onLaunchTaskFailed() { // TODO: probably go back to overview instead. + RecentsActivity activity = getCreatedActivity(); activity.getOverviewPanel().startHome(); } @Override - public void onLaunchTaskSuccess(RecentsActivity activity) { + public void onLaunchTaskSuccess() { + RecentsActivity activity = getCreatedActivity(); activity.onTaskLaunched(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index c5289355b8..87db83db53 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -69,8 +69,8 @@ import com.android.systemui.plugins.shared.LauncherOverlayManager; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; /** * {@link BaseActivityInterface} for the in-launcher recents. @@ -92,23 +92,26 @@ public final class LauncherActivityInterface implements BaseActivityInterface callback) { - final LauncherState startState = activity.getStateManager().getState(); + Launcher launcher = getCreatedActivity(); + final LauncherState startState = launcher.getStateManager().getState(); LauncherState resetState = startState; if (startState.disableRestore) { - resetState = activity.getStateManager().getRestState(); + resetState = launcher.getStateManager().getRestState(); } - activity.getStateManager().setRestState(resetState); + launcher.getStateManager().setRestState(resetState); final LauncherState fromState = animateActivity ? BACKGROUND_APP : OVERVIEW; - activity.getStateManager().goToState(fromState, false); + launcher.getStateManager().goToState(fromState, false); // Since all apps is not visible, we can safely reset the scroll position. // This ensures then the next swipe up to all-apps starts from scroll 0. - activity.getAppsView().reset(false /* animate */); + launcher.getAppsView().reset(false /* animate */); return new AnimationFactory() { private ShelfAnimState mShelfState; @@ -215,11 +220,11 @@ public final class LauncherActivityInterface implements BaseActivityInterface