From 0ac045fe23cc7b29c4d6712211c2b77bb4eff6e2 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 3 Nov 2021 13:17:02 -0700 Subject: [PATCH 01/18] Update CellLayout.DEBUG_VISUALIZE_OCCUPIED to include drag over targets Instead of just drawing the occupied cells in red, now we draw the occupied cells based on drag over regions: - Dragging over the red regions will reorder the cell - Dragging over the green regions will create/add to a folder Test: visual with internal flag on Bug: 204406063 Change-Id: I62105c1c1a1101b6cd6f9fd222980d03ba6d8b84 --- src/com/android/launcher3/CellLayout.java | 58 ++++++++++++++++++----- src/com/android/launcher3/Workspace.java | 13 ++--- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 02eb1dea6f..bd1d736ab4 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -19,6 +19,7 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; +import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,7 +38,6 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Parcelable; import android.util.ArrayMap; @@ -61,6 +61,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.folder.PreviewBackground; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.CellAndSpan; @@ -442,18 +443,41 @@ public class CellLayout extends ViewGroup { } if (DEBUG_VISUALIZE_OCCUPIED) { - int[] pt = new int[2]; - ColorDrawable cd = new ColorDrawable(Color.RED); - cd.setBounds(0, 0, mCellWidth, mCellHeight); - for (int i = 0; i < mCountX; i++) { - for (int j = 0; j < mCountY; j++) { - if (mOccupied.cells[i][j]) { - cellToPoint(i, j, pt); - canvas.save(); - canvas.translate(pt[0], pt[1]); - cd.draw(canvas); - canvas.restore(); + Rect cellBounds = new Rect(); + // Will contain the bounds of the cell including spacing between cells. + Rect cellBoundsWithSpacing = new Rect(); + int[] cellCenter = new int[2]; + Paint debugPaint = new Paint(); + debugPaint.setStrokeWidth(Utilities.dpToPx(1)); + for (int x = 0; x < mCountX; x++) { + for (int y = 0; y < mCountY; y++) { + if (!mOccupied.cells[x][y]) { + continue; } + View child = getChildAt(x, y); + boolean canCreateFolder = child instanceof DraggableView + && ((DraggableView) child).getViewType() == DRAGGABLE_ICON; + + cellToRect(x, y, 1, 1, cellBounds); + cellBoundsWithSpacing.set(cellBounds); + cellBoundsWithSpacing.inset(-mBorderSpace.x / 2, -mBorderSpace.y / 2); + cellToCenterPoint(x, y, cellCenter); + + canvas.save(); + canvas.clipRect(cellBoundsWithSpacing); + + // Draw reorder drag target. + debugPaint.setColor(Color.RED); + canvas.drawRect(cellBoundsWithSpacing, debugPaint); + + // Draw folder creation drag target. + if (canCreateFolder) { + debugPaint.setColor(Color.GREEN); + canvas.drawCircle(cellCenter[0], cellCenter[1], + getFolderCreationRadius(), debugPaint); + } + + canvas.restore(); } } } @@ -817,7 +841,7 @@ public class CellLayout extends ViewGroup { } /** - * Given a cell coordinate and span return the point that represents the center of the regio + * Given a cell coordinate and span return the point that represents the center of the region * * @param cellX X coordinate of the cell * @param cellY Y coordinate of the cell @@ -835,6 +859,14 @@ public class CellLayout extends ViewGroup { return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]); } + /** + * Returns the max distance from the center of a cell that can accept a drop to create a folder. + */ + public float getFolderCreationRadius() { + DeviceProfile grid = mActivity.getDeviceProfile(); + return grid.isTablet ? 0.75f * grid.iconSizePx : 0.55f * grid.iconSizePx; + } + public int getCellWidth() { return mCellWidth; } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index fc717c9387..bac71013ae 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -220,7 +220,6 @@ public class Workspace extends PagedView private FolderIcon mDragOverFolderIcon = null; private boolean mCreateUserFolderOnDrop = false; private boolean mAddToExistingFolderOnDrop = false; - private float mMaxDistanceForFolderCreation; // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; @@ -308,8 +307,6 @@ public class Workspace extends PagedView public void setInsets(Rect insets) { DeviceProfile grid = mLauncher.getDeviceProfile(); - mMaxDistanceForFolderCreation = grid.isTablet - ? 0.75f * grid.iconSizePx : 0.55f * grid.iconSizePx; mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens(); Rect padding = grid.workspacePadding; @@ -1789,7 +1786,7 @@ public class Workspace extends PagedView boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float distance, boolean considerTimeout) { - if (distance > mMaxDistanceForFolderCreation) return false; + if (distance > target.getFolderCreationRadius()) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); return willCreateUserFolder(info, dropOverView, considerTimeout); } @@ -1824,7 +1821,7 @@ public class Workspace extends PagedView boolean willAddToExistingUserFolder(ItemInfo dragInfo, CellLayout target, int[] targetCell, float distance) { - if (distance > mMaxDistanceForFolderCreation) return false; + if (distance > target.getFolderCreationRadius()) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); return willAddToExistingUserFolder(dragInfo, dropOverView); @@ -1848,7 +1845,7 @@ public class Workspace extends PagedView boolean createUserFolderIfNecessary(View newView, int container, CellLayout target, int[] targetCell, float distance, boolean external, DragObject d) { - if (distance > mMaxDistanceForFolderCreation) return false; + if (distance > target.getFolderCreationRadius()) return false; View v = target.getChildAt(targetCell[0], targetCell[1]); boolean hasntMoved = false; @@ -1905,7 +1902,7 @@ public class Workspace extends PagedView boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, float distance, DragObject d, boolean external) { - if (distance > mMaxDistanceForFolderCreation) return false; + if (distance > target.getFolderCreationRadius()) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); if (!mAddToExistingFolderOnDrop) return false; @@ -2509,7 +2506,7 @@ public class Workspace extends PagedView } private void manageFolderFeedback(float distance, DragObject dragObject) { - if (distance > mMaxDistanceForFolderCreation) { + if (distance > mDragTargetLayout.getFolderCreationRadius()) { if ((mDragMode == DRAG_MODE_ADD_TO_FOLDER || mDragMode == DRAG_MODE_CREATE_FOLDER)) { setDragMode(DRAG_MODE_NONE); From 3cfa5edc9329a36834066351520f2b50f377ee9e Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 3 Nov 2021 13:20:43 -0700 Subject: [PATCH 02/18] Fix misaligned folder creation drag over target Previously, the folder creation distance was based on the center of the cell, rather than the *visual* center, i.e. around the icon. Updated to use existing getWorkspaceVisualDragBounds() to handle this. Test: with DEBUG_VISUALIZE_OCCUPIED=true, ensure green circles are centered around the app icons; manually drag and drop to check the drawn regions are correct Bug: 204406063 Change-Id: I691a5cbbfc18c88436b88b7bda42f7920b9a5750 --- src/com/android/launcher3/CellLayout.java | 25 ++++++++++++++++++++--- src/com/android/launcher3/Workspace.java | 18 ++++++++-------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index bd1d736ab4..c9befe8451 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -461,7 +461,7 @@ public class CellLayout extends ViewGroup { cellToRect(x, y, 1, 1, cellBounds); cellBoundsWithSpacing.set(cellBounds); cellBoundsWithSpacing.inset(-mBorderSpace.x / 2, -mBorderSpace.y / 2); - cellToCenterPoint(x, y, cellCenter); + getWorkspaceCellVisualCenter(x, y, cellCenter); canvas.save(); canvas.clipRect(cellBoundsWithSpacing); @@ -854,11 +854,30 @@ public class CellLayout extends ViewGroup { result[1] = mTempRect.centerY(); } - public float getDistanceFromCell(float x, float y, int[] cell) { - cellToCenterPoint(cell[0], cell[1], mTmpPoint); + /** + * Returns the distance between the given coordinate and the visual center of the given cell. + */ + public float getDistanceFromWorkspaceCellVisualCenter(float x, float y, int[] cell) { + getWorkspaceCellVisualCenter(cell[0], cell[1], mTmpPoint); return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]); } + private void getWorkspaceCellVisualCenter(int cellX, int cellY, int[] outPoint) { + View child = getChildAt(cellX, cellY); + if (child instanceof DraggableView) { + DraggableView draggableChild = (DraggableView) child; + if (draggableChild.getViewType() == DRAGGABLE_ICON) { + cellToPoint(cellX, cellY, outPoint); + draggableChild.getWorkspaceVisualDragBounds(mTempRect); + mTempRect.offset(outPoint[0], outPoint[1]); + outPoint[0] = mTempRect.centerX(); + outPoint[1] = mTempRect.centerY(); + return; + } + } + cellToCenterPoint(cellX, cellY, outPoint); + } + /** * Returns the max distance from the center of a cell that can accept a drop to create a folder. */ diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index bac71013ae..2345f51694 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1751,8 +1751,8 @@ public class Workspace extends PagedView mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout, mTargetCell); - float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], - mDragViewVisualCenter[1], mTargetCell); + float distance = dropTargetLayout.getDistanceFromWorkspaceCellVisualCenter( + mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); if (mCreateUserFolderOnDrop && willCreateUserFolder(d.dragInfo, dropTargetLayout, mTargetCell, distance, true)) { return true; @@ -1966,8 +1966,8 @@ public class Workspace extends PagedView mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell); - float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], - mDragViewVisualCenter[1], mTargetCell); + float distance = dropTargetLayout.getDistanceFromWorkspaceCellVisualCenter( + mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); // If the item being dropped is a shortcut and the nearest drop // cell also contains a shortcut, then create a folder with the two shortcuts. @@ -2395,7 +2395,7 @@ public class Workspace extends PagedView setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]); - float targetCellDistance = mDragTargetLayout.getDistanceFromCell( + float targetCellDistance = mDragTargetLayout.getDistanceFromWorkspaceCellVisualCenter( mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); manageFolderFeedback(targetCellDistance, d); @@ -2651,8 +2651,8 @@ public class Workspace extends PagedView if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { mTargetCell = findNearestArea(touchXY[0], touchXY[1], spanX, spanY, cellLayout, mTargetCell); - float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], - mDragViewVisualCenter[1], mTargetCell); + float distance = cellLayout.getDistanceFromWorkspaceCellVisualCenter( + mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); if (willCreateUserFolder(d.dragInfo, cellLayout, mTargetCell, distance, true) || willAddToExistingUserFolder( d.dragInfo, cellLayout, mTargetCell, distance)) { @@ -2751,8 +2751,8 @@ public class Workspace extends PagedView if (touchXY != null) { mTargetCell = findNearestArea(touchXY[0], touchXY[1], spanX, spanY, cellLayout, mTargetCell); - float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], - mDragViewVisualCenter[1], mTargetCell); + float distance = cellLayout.getDistanceFromWorkspaceCellVisualCenter( + mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance, true, d)) { return; From 1278490ac03f2fd8894d05fcdbb7e20204303e6d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 3 Nov 2021 14:02:10 -0700 Subject: [PATCH 03/18] Update reorder and folder creation radii - Before, dragging anywhere in the cell (including space between cells) would trigger a reorder. Now, we compute the radius to the closest cell edge - For creating folders on icons, we split the difference between the reorder circle (above) and the icon size Test: enable DEBUG_VISUALIZE_OCCUPIED and manually drag to ensure works as described above Bug: 204406063 Change-Id: I368714634ed42a930fd16849f2bde1589df1aa63 --- src/com/android/launcher3/CellLayout.java | 52 ++++++++++++++++++++--- src/com/android/launcher3/Workspace.java | 15 ++++--- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index c9befe8451..adb1613e9d 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -20,6 +20,7 @@ import static android.animation.ValueAnimator.areAnimatorsEnabled; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON; +import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -446,6 +447,7 @@ public class CellLayout extends ViewGroup { Rect cellBounds = new Rect(); // Will contain the bounds of the cell including spacing between cells. Rect cellBoundsWithSpacing = new Rect(); + int[] targetCell = new int[2]; int[] cellCenter = new int[2]; Paint debugPaint = new Paint(); debugPaint.setStrokeWidth(Utilities.dpToPx(1)); @@ -454,10 +456,10 @@ public class CellLayout extends ViewGroup { if (!mOccupied.cells[x][y]) { continue; } - View child = getChildAt(x, y); - boolean canCreateFolder = child instanceof DraggableView - && ((DraggableView) child).getViewType() == DRAGGABLE_ICON; + targetCell[0] = x; + targetCell[1] = y; + boolean canCreateFolder = canCreateFolder(getChildAt(x, y)); cellToRect(x, y, 1, 1, cellBounds); cellBoundsWithSpacing.set(cellBounds); cellBoundsWithSpacing.inset(-mBorderSpace.x / 2, -mBorderSpace.y / 2); @@ -468,13 +470,14 @@ public class CellLayout extends ViewGroup { // Draw reorder drag target. debugPaint.setColor(Color.RED); - canvas.drawRect(cellBoundsWithSpacing, debugPaint); + canvas.drawCircle(cellCenter[0], cellCenter[1], getReorderRadius(targetCell), + debugPaint); // Draw folder creation drag target. if (canCreateFolder) { debugPaint.setColor(Color.GREEN); canvas.drawCircle(cellCenter[0], cellCenter[1], - getFolderCreationRadius(), debugPaint); + getFolderCreationRadius(targetCell), debugPaint); } canvas.restore(); @@ -505,6 +508,14 @@ public class CellLayout extends ViewGroup { } } + /** + * Returns whether dropping an icon on the given View can create (or add to) a folder. + */ + private boolean canCreateFolder(View child) { + return child instanceof DraggableView + && ((DraggableView) child).getViewType() == DRAGGABLE_ICON; + } + /** * Indicates the progress of the Workspace entering the SpringLoaded state; allows the * CellLayout to update various visuals for this state. @@ -881,9 +892,36 @@ public class CellLayout extends ViewGroup { /** * Returns the max distance from the center of a cell that can accept a drop to create a folder. */ - public float getFolderCreationRadius() { + public float getFolderCreationRadius(int[] targetCell) { DeviceProfile grid = mActivity.getDeviceProfile(); - return grid.isTablet ? 0.75f * grid.iconSizePx : 0.55f * grid.iconSizePx; + float iconVisibleRadius = ICON_VISIBLE_AREA_FACTOR * grid.iconSizePx / 2; + // Halfway between reorder radius and icon. + return (getReorderRadius(targetCell) + iconVisibleRadius) / 2; + } + + /** + * Returns the max distance from the center of a cell that will start to reorder on drag over. + */ + public float getReorderRadius(int[] targetCell) { + int[] centerPoint = mTmpPoint; + getWorkspaceCellVisualCenter(targetCell[0], targetCell[1], centerPoint); + + Rect cellBoundsWithSpacing = mTempRect; + cellToRect(targetCell[0], targetCell[1], 1, 1, cellBoundsWithSpacing); + cellBoundsWithSpacing.inset(-mBorderSpace.x / 2, -mBorderSpace.y / 2); + + if (canCreateFolder(getChildAt(targetCell[0], targetCell[1]))) { + // Take only the circle in the smaller dimension, to ensure we don't start reordering + // too soon before accepting a folder drop. + int minRadius = centerPoint[0] - cellBoundsWithSpacing.left; + minRadius = Math.min(minRadius, centerPoint[1] - cellBoundsWithSpacing.top); + minRadius = Math.min(minRadius, cellBoundsWithSpacing.right - centerPoint[0]); + minRadius = Math.min(minRadius, cellBoundsWithSpacing.bottom - centerPoint[1]); + return minRadius; + } + // Take up the entire cell, including space between this cell and the adjacent ones. + return (float) Math.hypot(cellBoundsWithSpacing.width() / 2f, + cellBoundsWithSpacing.height() / 2f); } public int getCellWidth() { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 2345f51694..00c8d8e305 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1786,7 +1786,7 @@ public class Workspace extends PagedView boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float distance, boolean considerTimeout) { - if (distance > target.getFolderCreationRadius()) return false; + if (distance > target.getFolderCreationRadius(targetCell)) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); return willCreateUserFolder(info, dropOverView, considerTimeout); } @@ -1821,7 +1821,7 @@ public class Workspace extends PagedView boolean willAddToExistingUserFolder(ItemInfo dragInfo, CellLayout target, int[] targetCell, float distance) { - if (distance > target.getFolderCreationRadius()) return false; + if (distance > target.getFolderCreationRadius(targetCell)) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); return willAddToExistingUserFolder(dragInfo, dropOverView); @@ -1845,7 +1845,7 @@ public class Workspace extends PagedView boolean createUserFolderIfNecessary(View newView, int container, CellLayout target, int[] targetCell, float distance, boolean external, DragObject d) { - if (distance > target.getFolderCreationRadius()) return false; + if (distance > target.getFolderCreationRadius(targetCell)) return false; View v = target.getChildAt(targetCell[0], targetCell[1]); boolean hasntMoved = false; @@ -1902,7 +1902,7 @@ public class Workspace extends PagedView boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, float distance, DragObject d, boolean external) { - if (distance > target.getFolderCreationRadius()) return false; + if (distance > target.getFolderCreationRadius(targetCell)) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); if (!mAddToExistingFolderOnDrop) return false; @@ -2408,8 +2408,9 @@ public class Workspace extends PagedView mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, d); } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER) - && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX || - mLastReorderY != reorderY)) { + && !mReorderAlarm.alarmPending() + && (mLastReorderX != reorderX || mLastReorderY != reorderY) + && targetCellDistance < mDragTargetLayout.getReorderRadius(mTargetCell)) { int[] resultSpan = new int[2]; mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0], @@ -2506,7 +2507,7 @@ public class Workspace extends PagedView } private void manageFolderFeedback(float distance, DragObject dragObject) { - if (distance > mDragTargetLayout.getFolderCreationRadius()) { + if (distance > mDragTargetLayout.getFolderCreationRadius(mTargetCell)) { if ((mDragMode == DRAG_MODE_ADD_TO_FOLDER || mDragMode == DRAG_MODE_CREATE_FOLDER)) { setDragMode(DRAG_MODE_NONE); From d0865f821949c59ae8f88a805830788750a3015b Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Tue, 9 Nov 2021 13:19:21 -0800 Subject: [PATCH 04/18] Add animated background to the suw all set page. Test: Ran all set page in landscape/portrait, dark/light mode Fixes: 190828563 Change-Id: Ie7fbc6ce6777e9cec8d4dcb5dff3090dc167a161 --- Android.bp | 1 + build.gradle | 2 + quickstep/res/layout/activity_allset.xml | 154 ++++++++++-------- .../quickstep/interaction/AllSetActivity.java | 64 ++++++++ res/raw/all_set_page_bg.json | 1 + 5 files changed, 154 insertions(+), 68 deletions(-) create mode 100644 res/raw/all_set_page_bg.json diff --git a/Android.bp b/Android.bp index 8b7eb54b9e..60ef5b1ab7 100644 --- a/Android.bp +++ b/Android.bp @@ -204,6 +204,7 @@ android_library { ], static_libs: [ "Launcher3ResLib", + "lottie", "SystemUISharedLib", "SystemUI-statsd", ], diff --git a/build.gradle b/build.gradle index 617738a5ed..683a4cfaf1 100644 --- a/build.gradle +++ b/build.gradle @@ -163,6 +163,8 @@ dependencies { androidTestImplementation 'com.android.support.test:rules:1.0.0' androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2' androidTestImplementation "androidx.annotation:annotation:${ANDROID_X_VERSION}" + + api 'com.airbnb.android:lottie:3.3.0' } protobuf { diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml index b4ee4828a6..9ad10dc54e 100644 --- a/quickstep/res/layout/activity_allset.xml +++ b/quickstep/res/layout/activity_allset.xml @@ -25,82 +25,100 @@ + android:fitsSystemWindows="true"> - - - + android:layout_height="match_parent" + android:gravity="center" + android:scaleType="centerCrop" - + app:lottie_rawRes="@raw/all_set_page_bg" + app:lottie_autoPlay="true" + app:lottie_loop="true" /> - + - + - + + + + + + + + + + + + - \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 965c1bcc32..1c3e784308 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -19,6 +19,7 @@ import static com.android.launcher3.Utilities.mapBoundToRange; import static com.android.launcher3.Utilities.mapRange; import static com.android.launcher3.anim.Interpolators.LINEAR; +import android.animation.Animator; import android.app.Activity; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; @@ -38,6 +39,8 @@ import android.graphics.Rect; import android.graphics.Shader.TileMode; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.util.Log; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -56,6 +59,8 @@ import com.android.quickstep.GestureState; import com.android.quickstep.TouchInteractionService.TISBinder; import com.android.quickstep.util.TISBindHelper; +import com.airbnb.lottie.LottieAnimationView; + import java.net.URISyntaxException; /** @@ -80,6 +85,10 @@ public class AllSetActivity extends Activity { private View mContentView; private float mSwipeUpShift; + @Nullable private Vibrator mVibrator; + private LottieAnimationView mAnimatedBackground; + private Animator.AnimatorListener mBackgroundAnimatorListener; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -115,6 +124,52 @@ public class AllSetActivity extends Activity { findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); + + mVibrator = getSystemService(Vibrator.class); + mAnimatedBackground = findViewById(R.id.animated_background); + startBackgroundAnimation(); + } + + private void startBackgroundAnimation() { + if (Utilities.ATLEAST_S && mVibrator != null && mVibrator.areAllPrimitivesSupported( + VibrationEffect.Composition.PRIMITIVE_THUD)) { + if (mBackgroundAnimatorListener == null) { + mBackgroundAnimatorListener = + new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + mVibrator.vibrate(getVibrationEffect()); + } + + @Override + public void onAnimationRepeat(Animator animation) { + mVibrator.vibrate(getVibrationEffect()); + } + + @Override + public void onAnimationEnd(Animator animation) { + mVibrator.cancel(); + } + + @Override + public void onAnimationCancel(Animator animation) { + mVibrator.cancel(); + } + }; + } + mAnimatedBackground.addAnimatorListener(mBackgroundAnimatorListener); + } + mAnimatedBackground.playAnimation(); + } + + /** + * Sets up the vibration effect for the next round of animation. The parameters vary between + * different illustrations. + */ + private VibrationEffect getVibrationEffect() { + return VibrationEffect.startComposition() + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD, 1.0f, 50) + .compose(); } @Override @@ -153,6 +208,9 @@ public class AllSetActivity extends Activity { super.onDestroy(); mTISBindHelper.onDestroy(); clearBinderOverride(); + if (mBackgroundAnimatorListener != null) { + mAnimatedBackground.removeAnimatorListener(mBackgroundAnimatorListener); + } } private AnimatedFloat createSwipeUpProxy(GestureState state) { @@ -173,6 +231,12 @@ public class AllSetActivity extends Activity { 1, 0, LINEAR); mContentView.setAlpha(alpha); mContentView.setTranslationY((alpha - 1) * mSwipeUpShift); + + if (alpha == 0f) { + mAnimatedBackground.pauseAnimation(); + } else if (!mAnimatedBackground.isAnimating()) { + mAnimatedBackground.resumeAnimation(); + } } /** diff --git a/res/raw/all_set_page_bg.json b/res/raw/all_set_page_bg.json new file mode 100644 index 0000000000..9705837912 --- /dev/null +++ b/res/raw/all_set_page_bg.json @@ -0,0 +1 @@ +{"v":"5.7.8","fr":24,"ip":0,"op":72,"w":2472,"h":5352,"nm":"3Second_MAIN_Welcome","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 60","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1508,1364,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"PinkFlower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":72,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[1505.832,1379.455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":38,"s":[1505.832,575,0],"to":[0,0,0],"ti":[0,0,0]},{"t":72,"s":[1505.832,1379.455,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.839215746113,0.439215716194,0.388235324037,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":288,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse_Bottom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":38,"s":[-38]},{"t":72,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1720]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":38,"s":[1544]},{"t":72,"s":[1720]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4069]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":38,"s":[3872]},{"t":72,"s":[4069]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.882353001015,0.894118006089,0.886274988511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]} From b7abf7e96d8b4dc896cae330f97f701f8f8450ae Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Mon, 15 Nov 2021 20:02:43 +0000 Subject: [PATCH 05/18] Fix launch animation from bottom row and end of grid - Apply gridTranslationY when calculating taskRect so it's used to calculate RecnetsView pivot - Moved recentsViewScroll to RecentsView group and applied after recentsViewScale - Before: http://dr/file/d/1-Nrqa80J4FRbjcdZ3GZSeKwfQF8fN9a1/view?resourcekey=0-gYT9z1HA0YksW5Ujbzsmeg - After: http://dr/file/d/1-DpZrg5_nFeUKS-8APnLvG8SJVvke9BU/view?resourcekey=0-p59hm-abzpU7Y7tqWyneTQ Fix: 200813202 Test: Launch task from grid from top/bottom/left/right/focus Test: Launch task from left/middle/right in small screen Change-Id: I814512c02611f59a5a6d1f53411d42cf4f0f26b3 --- .../com/android/quickstep/TaskViewUtils.java | 10 +--------- .../quickstep/util/TaskViewSimulator.java | 20 ++++++++++++++++--- .../android/quickstep/views/RecentsView.java | 14 ------------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index ae3cc50ac6..6addfe30f4 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -32,7 +32,6 @@ import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURA import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; -import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.statehandlers.DepthController.DEPTH; @@ -193,7 +192,6 @@ public final class TaskViewUtils { boolean showAsGrid = dp.overviewShowAsGrid; boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage() && !showAsGrid; - float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex); int startScroll = recentsView.getScrollOffset(taskIndex); RemoteTargetHandle[] topMostSimulators = null; @@ -211,11 +209,9 @@ public final class TaskViewUtils { tvsLocal.fullScreenProgress.value = 0; tvsLocal.recentsViewScale.value = 1; - if (showAsGrid) { - tvsLocal.taskSecondaryTranslation.value = gridTranslationSecondary; - } tvsLocal.setScroll(startScroll); tvsLocal.setIsGridTask(v.isGridTask()); + tvsLocal.setGridTranslationY(v.getGridTranslationY()); // Fade in the task during the initial 20% of the animation out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1, @@ -230,10 +226,6 @@ public final class TaskViewUtils { out.setFloat(tvsLocal.recentsViewScale, AnimatedFloat.VALUE, tvsLocal.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR); - if (showAsGrid) { - out.setFloat(tvsLocal.taskSecondaryTranslation, AnimatedFloat.VALUE, 0, - TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL); - } out.setFloat(tvsLocal.recentsViewScroll, AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR); diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 146d2355f1..7d396ba002 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -102,6 +102,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private StagedSplitBounds mStagedSplitBounds; private boolean mDrawsBelowRecents; private boolean mIsGridTask; + private float mGridTranslationY; public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) { mContext = context; @@ -156,9 +157,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { fullTaskSize = new Rect(mTaskRect); mOrientationState.getOrientationHandler() .setSplitTaskSwipeRect(mDp, mTaskRect, mStagedSplitBounds, mStagePosition); + if (mIsGridTask) { + mTaskRect.offset(0, (int) mGridTranslationY); + } } else { fullTaskSize = mTaskRect; } + if (mIsGridTask) { + fullTaskSize.offset(0, (int) mGridTranslationY); + } return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot); } @@ -217,6 +224,13 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mIsGridTask = isGridTask; } + /** + * Sets the y-translation when overview is in grid. + */ + public void setGridTranslationY(float gridTranslationY) { + mGridTranslationY = gridTranslationY; + } + /** * Adds animation for all the components corresponding to transition from an app to overview. */ @@ -320,14 +334,12 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mMatrix.postTranslate(insets.left, insets.top); mMatrix.postScale(scale, scale); - // Apply TaskView matrix: translate, scroll + // Apply TaskView matrix: taskRect, translate mMatrix.postTranslate(mTaskRect.left, mTaskRect.top); mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE, taskPrimaryTranslation.value); mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE, taskSecondaryTranslation.value); - mOrientationState.getOrientationHandler().set( - mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value); // Apply RecentsView matrix mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y); @@ -335,6 +347,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { recentsViewSecondaryTranslation.value); mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE, recentsViewPrimaryTranslation.value); + mOrientationState.getOrientationHandler().set( + mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value); applyWindowToHomeRotation(mMatrix); // Crop rect is the inverse of thumbnail matrix diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 223ce1c556..586693cfa7 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4654,20 +4654,6 @@ public abstract class RecentsView getEventDispatcher(float navbarRotation) { float degreesRotated; if (navbarRotation == 0) { From a4edc07ec899d5bda08964c1f807e580a365953b Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Tue, 16 Nov 2021 21:17:19 -0800 Subject: [PATCH 06/18] Refine when to move live tile app below recents view - We will still need to figure out why, but currently the overview scrim blocks the cut out during transition. To go around this, we need to move live tile app after the overview transition animation is over - Some of the logic in RecentsView is no longer necessary since we are no longer reusing live tile params and simulator, but assign new targets each time Fixes: 205587164 Test: manual Change-Id: Icadf26182112bba544a4103b626effa37d4028b5 --- .../quickstep/fallback/FallbackRecentsView.java | 9 ++++++++- .../quickstep/views/LauncherRecentsView.java | 9 ++++++++- .../com/android/quickstep/views/RecentsView.java | 14 +------------- .../src/com/android/quickstep/views/TaskView.java | 14 -------------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index eff59e24bc..95095fa8eb 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -16,6 +16,7 @@ package com.android.quickstep.fallback; import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; +import static com.android.quickstep.ViewUtils.postFrameDrawn; import static com.android.quickstep.fallback.RecentsState.DEFAULT; import static com.android.quickstep.fallback.RecentsState.HOME; import static com.android.quickstep.fallback.RecentsState.MODAL_TASK; @@ -218,8 +219,14 @@ public class FallbackRecentsView extends RecentsView runActionOnRemoteHandles(remoteTargetHandle -> + remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true))); + } } @Override diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 5d6b6563f7..3cba3921b2 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -21,6 +21,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.LauncherState.SPRING_LOADED; +import static com.android.quickstep.ViewUtils.postFrameDrawn; import android.annotation.TargetApi; import android.content.Context; @@ -104,8 +105,14 @@ public class LauncherRecentsView extends RecentsView runActionOnRemoteHandles(remoteTargetHandle -> + remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true))); + } } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 0188962da9..f15a9a25cf 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1506,17 +1506,6 @@ public abstract class RecentsView { - TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator(); - simulator.taskPrimaryTranslation.value = 0; - simulator.taskSecondaryTranslation.value = 0; - simulator.fullScreenProgress.value = 0; - simulator.recentsViewScale.value = 1; - }); - // Similar to setRunningTaskHidden below, reapply the state before runningTaskView is // null. if (!mRunningTaskShowScreenshot) { @@ -1904,7 +1893,7 @@ public abstract class RecentsView { remoteTargetHandle.getTransformParams().setTargetSet(null); - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true); + remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false); }); mSplitSelectStateController.resetState(); @@ -4387,7 +4376,6 @@ public abstract class RecentsView) remoteTargetHandle -> - remoteTargetHandle - .getTaskViewSimulator() - .setDrawsBelowRecents(false)); - } - @Override public void onAnimationEnd(Animator animator) { - recentsView.runActionOnRemoteHandles( - (Consumer) remoteTargetHandle -> - remoteTargetHandle - .getTaskViewSimulator() - .setDrawsBelowRecents(true)); mIsClickableAsLiveTile = true; } }); From 60ba2ac084f7450ed3124b1161a2e9fbff24b070 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 17 Nov 2021 11:06:09 -0800 Subject: [PATCH 07/18] Recognizing Launcher builds consisting only of digits Bug: 206687633 Test: online regex tools Change-Id: Ia6155f22fb9a0eba3beb6edb607f44f901629330 --- .../src/com/android/launcher3/util/rule/TestStabilityRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java index de36d5f1b5..f33a50ae5a 100644 --- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java +++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java @@ -41,7 +41,7 @@ public class TestStabilityRule implements TestRule { Pattern.compile("^(" + "(?(BuildFromAndroidStudio|" + "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|" - + "(?[A-Z]([a-z]|[0-9])*)" + + "(?([A-Z][a-z]*[0-9]*|[0-9]+)*)" + ")$"); private static final Pattern PLATFORM_BUILD = Pattern.compile("^(" From 92c6ae64dee6adca0ef8b8174f04f5ef13a93b19 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Wed, 17 Nov 2021 12:22:02 -0800 Subject: [PATCH 08/18] Add TODO to fix b/206508141 before removing or changing the default value to the feature flag ENABLE_LOCAL_COLOR_POPUPS Bug: 206508141 Test: None Change-Id: I8a8290f1e7d24c9fd2e8922f0126fa3d713e10a4 --- src/com/android/launcher3/config/FeatureFlags.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index e253505426..ed4f316912 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -72,6 +72,7 @@ public final class FeatureFlags { "PROMISE_APPS_NEW_INSTALLS", true, "Adds a promise icon to the home screen for new install sessions."); + // TODO: b/206508141: Long pressing on some icons on home screen cause launcher to crash. public static final BooleanFlag ENABLE_LOCAL_COLOR_POPUPS = getDebugFlag( "ENABLE_LOCAL_COLOR_POPUPS", false, "Enable local color extraction for popups."); From 0a1328d9fb1ec02bb27eaf8573c94d1ba31fba5b Mon Sep 17 00:00:00 2001 From: Sebastian Franco Date: Sat, 23 Oct 2021 22:21:07 -0500 Subject: [PATCH 09/18] Adding back the badges on widgets for widget recommendations. Test: Manual Testing Fix: 202956924 Change-Id: I859d3d93d95bdc8d0742eb6b5dd40ad12a386928 --- res/layout/widget_cell_content.xml | 8 +++ .../widget/DatabaseWidgetPreviewLoader.java | 54 +++++++++++++++++++ .../android/launcher3/widget/WidgetCell.java | 21 ++++++++ .../WidgetsRecommendationTableLayout.java | 1 + 4 files changed, 84 insertions(+) diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml index b27b50560e..0f6fc6cdb7 100644 --- a/res/layout/widget_cell_content.xml +++ b/res/layout/widget_cell_content.xml @@ -33,6 +33,14 @@ android:layout_height="match_parent" android:importantForAccessibility="no" android:layout_gravity="fill"/> + + diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java index aacb9c5dff..784f4f050e 100644 --- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java +++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java @@ -25,11 +25,15 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Handler; import android.os.Process; +import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Log; import android.util.Size; @@ -40,6 +44,7 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.icons.BitmapRenderer; +import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.ShadowGenerator; import com.android.launcher3.icons.cache.HandlerRunnable; @@ -60,6 +65,9 @@ public class DatabaseWidgetPreviewLoader { private final Context mContext; private final float mPreviewBoxCornerRadius; + private final UserHandle mMyUser = Process.myUserHandle(); + private final ArrayMap mUserBadges = new ArrayMap<>(); + public DatabaseWidgetPreviewLoader(Context context) { mContext = context; float previewCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context); @@ -100,6 +108,52 @@ public class DatabaseWidgetPreviewLoader { } } + /** + * Returns a drawable that can be used as a badge for the user or null. + */ + // @UiThread + public Drawable getBadgeForUser(UserHandle user, int badgeSize) { + if (mMyUser.equals(user)) { + return null; + } + + Bitmap badgeBitmap = getUserBadge(user, badgeSize); + FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap); + d.setFilterBitmap(true); + d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight()); + return d; + } + + private Bitmap getUserBadge(UserHandle user, int badgeSize) { + synchronized (mUserBadges) { + Bitmap badgeBitmap = mUserBadges.get(user); + if (badgeBitmap != null) { + return badgeBitmap; + } + + final Resources res = mContext.getResources(); + badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888); + + Drawable drawable = mContext.getPackageManager().getUserBadgedDrawableForDensity( + new BitmapDrawable(res, badgeBitmap), user, + new Rect(0, 0, badgeSize, badgeSize), + 0); + if (drawable instanceof BitmapDrawable) { + badgeBitmap = ((BitmapDrawable) drawable).getBitmap(); + } else { + badgeBitmap.eraseColor(Color.TRANSPARENT); + Canvas c = new Canvas(badgeBitmap); + drawable.setBounds(0, 0, badgeSize, badgeSize); + drawable.draw(c); + c.setBitmap(null); + } + + mUserBadges.put(user, badgeBitmap); + return badgeBitmap; + } + } + + /** * Generates the widget preview from either the {@link WidgetManagerHelper} or cache * and add badge at the bottom right corner. diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index f1ac656d60..c92fe5a516 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -36,6 +36,7 @@ import android.view.ViewGroup; import android.view.ViewPropertyAnimator; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.TextView; @@ -47,6 +48,7 @@ import com.android.launcher3.CheckLongPressHelper; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.RoundDrawableWrapper; import com.android.launcher3.icons.cache.HandlerRunnable; @@ -111,6 +113,7 @@ public class WidgetCell extends LinearLayout { private FrameLayout mWidgetImageContainer; private WidgetImageView mWidgetImage; + private ImageView mWidgetBadge; private TextView mWidgetName; private TextView mWidgetDims; private TextView mWidgetDescription; @@ -166,6 +169,7 @@ public class WidgetCell extends LinearLayout { mWidgetImageContainer = findViewById(R.id.widget_preview_container); mWidgetImage = findViewById(R.id.widget_preview); + mWidgetBadge = findViewById(R.id.widget_badge); mWidgetName = findViewById(R.id.widget_name); mWidgetDims = findViewById(R.id.widget_dims); mWidgetDescription = findViewById(R.id.widget_description); @@ -195,6 +199,8 @@ public class WidgetCell extends LinearLayout { mWidgetImage.animate().cancel(); mWidgetImage.setDrawable(null); mWidgetImage.setVisibility(View.VISIBLE); + mWidgetBadge.setImageDrawable(null); + mWidgetBadge.setVisibility(View.GONE); mWidgetName.setText(null); mWidgetDims.setText(null); mWidgetDescription.setText(null); @@ -349,6 +355,7 @@ public class WidgetCell extends LinearLayout { mAppWidgetHostViewPreview = null; } } + if (mAnimatePreview) { mWidgetImageContainer.setAlpha(0f); ViewPropertyAnimator anim = mWidgetImageContainer.animate(); @@ -362,6 +369,20 @@ public class WidgetCell extends LinearLayout { } } + /** Used to show the badge when the widget is in the recommended section + */ + public void showBadge() { + Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user, + BaseIconFactory.getBadgeSizeForIconSize( + mActivity.getDeviceProfile().allAppsIconSizePx)); + if (badge == null) { + mWidgetBadge.setVisibility(View.GONE); + } else { + mWidgetBadge.setVisibility(View.VISIBLE); + mWidgetBadge.setImageDrawable(badge); + } + } + private void setContainerSize(int width, int height) { LayoutParams layoutParams = (LayoutParams) mWidgetImageContainer.getLayoutParams(); layoutParams.width = width; diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java index c986007a3f..06cc65e4c1 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java @@ -109,6 +109,7 @@ public final class WidgetsRecommendationTableLayout extends TableLayout { for (WidgetItem widgetItem : widgetItems) { WidgetCell widgetCell = addItemCell(tableRow); widgetCell.applyFromCellItem(widgetItem, data.mPreviewScale); + widgetCell.showBadge(); } addView(tableRow); } From 5163574b7ab6fa8b48b7f3fefae340258b9d0e63 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 17 Nov 2021 13:59:02 -0800 Subject: [PATCH 10/18] Move live tile app to top when the task view is tapped - transition animation for foldables need it Bug: 205789573 Test: manual Change-Id: Icf11d204968dbffa6bb9c930deaa57d35e2eff4a --- quickstep/src/com/android/quickstep/views/TaskView.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index e9a3779b7f..67128f01fe 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -647,6 +647,15 @@ public class TaskView extends FrameLayout implements Reusable { mActivity.getStateManager(), recentsView, recentsView.getDepthController()); anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + recentsView.runActionOnRemoteHandles( + (Consumer) remoteTargetHandle -> + remoteTargetHandle + .getTaskViewSimulator() + .setDrawsBelowRecents(false)); + } + @Override public void onAnimationEnd(Animator animator) { mIsClickableAsLiveTile = true; From bf4a91b0f1d75833f8013dc4a2778cc8ca997bdc Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 17 Nov 2021 14:04:25 -0800 Subject: [PATCH 11/18] Use TOUCHABLE_INSETS_REGION when IME is visible This ensures the dismiss button is fully clickable even if taskbar is stashed. Test: Stash taskbar, can dismiss keyboard by tapping anywhere on the back button (Same with taskbar unstashed) Fixes: 206851484 Change-Id: I06f86191e36b596a928c8db8d67a012be033daba --- .../android/launcher3/taskbar/TaskbarDragLayerController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 8c6185cb0f..81039d4d58 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -143,8 +143,7 @@ public class TaskbarDragLayerController { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } else if (mControllers.navbarButtonsViewController.isImeVisible()) { - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_CONTENT); - insetsIsTouchableRegion = false; + insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } else if (!mControllers.uiController.isTaskbarTouchable()) { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); From be7ce023dee823c99e26031a9cad9db850f29047 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 17 Nov 2021 19:05:29 -0800 Subject: [PATCH 12/18] Use split thumbnail width/height directly * When swiping to QS from home, the bounds for the rect on screen are incorrect because it's technically off-screen when it's being queried Fixes: 206155441 Change-Id: Ibb17f2ac291f867b6de06041c980e434ce92cf27 --- .../com/android/quickstep/views/GroupedTaskView.java | 7 +------ .../launcher3/touch/LandscapePagedViewHandler.java | 7 +++---- .../launcher3/touch/PagedOrientationHandler.java | 2 +- .../launcher3/touch/PortraitPagedViewHandler.java | 11 ++++------- .../launcher3/touch/SeascapePagedViewHandler.java | 4 ++-- 5 files changed, 11 insertions(+), 20 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index df99d27376..ea83b4deaf 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -4,7 +4,6 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; import android.content.Context; -import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; @@ -50,8 +49,6 @@ public class GroupedTaskView extends TaskView { private final float[] mIcon2CenterCoords = new float[2]; private TransformingTouchDelegate mIcon2TouchDelegate; @Nullable private StagedSplitBounds mSplitBoundsConfig; - private final Rect mPrimaryTempRect = new Rect(); - private final Rect mSecondaryTempRect = new Rect(); public GroupedTaskView(Context context) { super(context); @@ -239,10 +236,8 @@ public class GroupedTaskView extends TaskView { int taskIconHeight = deviceProfile.overviewTaskIconSizePx; boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; - mSnapshotView.getBoundsOnScreen(mPrimaryTempRect); - mSnapshotView2.getBoundsOnScreen(mSecondaryTempRect); getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2, - taskIconHeight, mPrimaryTempRect, mSecondaryTempRect, + taskIconHeight, mSnapshotView.getWidth(), mSnapshotView.getHeight(), isRtl, deviceProfile, mSplitBoundsConfig); } diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 93e3ea7599..498f6dbc60 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -429,7 +429,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, - int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds, + int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); @@ -439,13 +439,12 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { splitConfig.visualDividerBounds.height() : splitConfig.visualDividerBounds.width()); - int primaryHeight = primarySnapshotBounds.height(); primaryIconParams.gravity = (isRtl ? START : END) | TOP; - primaryIconView.setTranslationY(primaryHeight - primaryIconView.getHeight() / 2f); + primaryIconView.setTranslationY(primarySnapshotHeight - primaryIconView.getHeight() / 2f); primaryIconView.setTranslationX(0); secondaryIconParams.gravity = (isRtl ? START : END) | TOP; - secondaryIconView.setTranslationY(primaryHeight + taskIconHeight + dividerBar); + secondaryIconView.setTranslationY(primarySnapshotHeight + taskIconHeight + dividerBar); secondaryIconView.setTranslationX(0); primaryIconView.setLayoutParams(primaryIconParams); secondaryIconView.setLayoutParams(secondaryIconParams); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 2ff2feb4c5..95336cd399 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -152,7 +152,7 @@ public interface PagedOrientationHandler { void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight, FrameLayout.LayoutParams snapshotParams, boolean isRtl); void setSplitIconParams(View primaryIconView, View secondaryIconView, - int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds, + int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig); /* diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index ba9d09cfc6..835c2401ae 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -523,7 +523,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, - int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds, + int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); @@ -533,15 +533,12 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { splitConfig.visualDividerBounds.height() : splitConfig.visualDividerBounds.width()); - int primaryWidth = primarySnapshotBounds.width(); if (deviceProfile.isLandscape) { primaryIconParams.gravity = TOP | START; - primaryIconView.setTranslationX(primaryWidth - primaryIconView.getWidth()); + primaryIconView.setTranslationX(primarySnapshotWidth - primaryIconView.getWidth()); primaryIconView.setTranslationY(0); - secondaryIconParams.gravity = TOP | START; - secondaryIconView.setTranslationX(primaryWidth + dividerBar); - secondaryIconView.setTranslationY(0); + secondaryIconView.setTranslationX(primarySnapshotWidth + dividerBar); } else { primaryIconParams.gravity = TOP | CENTER_HORIZONTAL; primaryIconView.setTranslationX(-(primaryIconView.getWidth()) / 2f); @@ -549,8 +546,8 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL; secondaryIconView.setTranslationX(secondaryIconView.getWidth() / 2f); - secondaryIconView.setTranslationY(0); } + secondaryIconView.setTranslationY(0); primaryIconView.setLayoutParams(primaryIconParams); secondaryIconView.setLayoutParams(secondaryIconParams); } diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index a0dde22d84..539e3f82c5 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -132,10 +132,10 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, - int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds, + int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight, - primarySnapshotBounds, secondarySnapshotBounds, isRtl, deviceProfile, splitConfig); + primarySnapshotWidth, primarySnapshotHeight, isRtl, deviceProfile, splitConfig); FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); FrameLayout.LayoutParams secondaryIconParams = From 3e39786ec3f35ec9297003a54f4439af7d198a36 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 18 Nov 2021 04:19:33 +0000 Subject: [PATCH 13/18] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I88e2ee9b0d5fd68d79eb888f201d649541ea0844 --- res/values-it/strings.xml | 6 +++--- res/values-pt-rPT/strings.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 71a3403835..482a9ad68b 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -37,12 +37,12 @@ "Aggiungi a schermata Home" "Widget %1$s aggiunto alla schermata Home" + %1$d widget %1$d widget - %1$d widget + %1$d scorciatoia %1$d scorciatoie - %1$d scorciatoia "%1$s, %2$s" "Widget" @@ -90,8 +90,8 @@ "Modifica nome" "App %1$s disattivata" + %1$s, ha %2$d notifiche %1$s, ha %2$d notifiche - %1$s, ha %2$d notifica "Pagina %1$d di %2$d" "Schermata Home %1$d di %2$d" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index f0ba02156a..5763e6e1d7 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -37,12 +37,12 @@ "Adicionar ao ecrã principal" "Widget %1$s adicionado ao ecrã principal" - %1$d widgets %1$d widget + %1$d widgets - %1$d atalhos %1$d atalho + %1$d atalhos "%1$s, %2$s" "Widgets" @@ -90,8 +90,8 @@ "Edite o nome" "%1$s desativado" - A app %1$s tem %2$d notificações. A app %1$s tem %2$d notificação + A app %1$s tem %2$d notificações. "Página %1$d de %2$d" "Ecrã principal %1$d de %2$d" From f841aa488d27af94efdcbc059bdaec0103514ec7 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 18 Nov 2021 04:20:12 +0000 Subject: [PATCH 14/18] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I15ccd3db00e2a2353337a834b41706dedeac2749 --- res/values-it/strings.xml | 6 +++--- res/values-pt-rPT/strings.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index cedcafa444..708a0c5ca4 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -37,12 +37,12 @@ "Aggiungi a schermata Home" "Widget %1$s aggiunto alla schermata Home" + %1$d widget %1$d widget - %1$d widget + %1$d scorciatoia %1$d scorciatoie - %1$d scorciatoia "%1$s, %2$s" "Widget" @@ -92,8 +92,8 @@ "Modifica nome" "App %1$s disattivata" + %1$s, ha %2$d notifiche %1$s, ha %2$d notifiche - %1$s, ha %2$d notifica "Pagina %1$d di %2$d" "Schermata Home %1$d di %2$d" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 636724969f..d40ed835f6 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -37,12 +37,12 @@ "Adicionar ao ecrã principal" "Widget %1$s adicionado ao ecrã principal" - %1$d widgets %1$d widget + %1$d widgets - %1$d atalhos %1$d atalho + %1$d atalhos "%1$s, %2$s" "Widgets" @@ -92,8 +92,8 @@ "Edite o nome" "%1$s desativado" - A app %1$s tem %2$d notificações. A app %1$s tem %2$d notificação + A app %1$s tem %2$d notificações. "Página %1$d de %2$d" "Ecrã principal %1$d de %2$d" From 645278133c13e5f7b9e3e59be32a89c440a0026d Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 18 Nov 2021 04:20:51 +0000 Subject: [PATCH 15/18] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I96e0a393c618e4bf956a23d2da8066d123f13932 --- res/values-it/strings.xml | 6 +++--- res/values-pt-rPT/strings.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 3758093ebd..0235ef0c2d 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -36,8 +36,8 @@ "Tocca e tieni premuto il widget per spostarlo nella schermata Home" "Aggiungi a schermata Home" "Widget %1$s aggiunto alla schermata Home" - "{count,plural, =1{# widget}other{# widget}}" - "{count,plural, =1{# scorciatoia}other{# scorciatoie}}" + "{count,plural, =1{# widget}one{# widget}other{# widget}}" + "{count,plural, =1{# scorciatoia}one{# scorciatoia}other{# scorciatoie}}" "%1$s, %2$s" "Widget" "Cerca" @@ -86,7 +86,7 @@ "Questa è un\'app di sistema e non può essere disinstallata." "Modifica nome" "App %1$s disattivata" - "{count,plural,offset:1 =1{{app_name} ha # notifica}other{{app_name} ha # notifiche}}" + "{count,plural,offset:1 =1{{app_name} ha # notifica}one{{app_name} ha # notifica}other{{app_name} ha # notifiche}}" "Pagina %1$d di %2$d" "Schermata Home %1$d di %2$d" "Nuova pagina Schermata Home" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 09a12007e1..a3c225a257 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -36,8 +36,8 @@ "Toque sem soltar no widget para o mover à volta do ecrã principal" "Adicionar ao ecrã principal" "Widget %1$s adicionado ao ecrã principal" - "{count,plural, =1{# widget}other{# widgets}}" - "{count,plural, =1{# atalho}other{# atalhos}}" + "{count,plural, =1{# widget}one{# widget(s)}other{# widgets}}" + "{count,plural, =1{# atalho}one{# atalho(s)}other{# atalhos}}" "%1$s, %2$s" "Widgets" "Pesquisar" @@ -86,7 +86,7 @@ "É uma app de sistema e não pode ser desinstalada." "Edite o nome" "%1$s desativado" - "{count,plural,offset:1 =1{A app {app_name} tem # notificação}other{A app {app_name} tem # notificações}}" + "{count,plural,offset:1 =1{A app {app_name} tem # notificação}one{A app {app_name} tem # notificação(ões)}other{A app {app_name} tem # notificações}}" "Página %1$d de %2$d" "Ecrã principal %1$d de %2$d" "Nova página do ecrã principal" From 60d5315e19fdd422fbff97ee33c0acf79c9f627c Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Wed, 17 Nov 2021 19:03:04 +0000 Subject: [PATCH 16/18] Refresh overlay when thumbnail was set for first time Bug: 202414125 Test: TaplTestsNexus.testOverviewActions && TaplTestsQuickstep.testOverviewActions Change-Id: I2cc38df4c891fb21a8295d4f9c75e396c71449f2 --- .../com/android/quickstep/TaskOverlayFactory.java | 7 ------- .../quickstep/views/TaskThumbnailView.java | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index c45159e48e..02468497bb 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -208,13 +208,6 @@ public class TaskOverlayFactory implements ResourceBasedOverride { } } - /** - * Called when the current task's thumbnail has changed. - */ - public void refreshActionVisibility(ThumbnailData thumbnail) { - getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null); - } - /** * End rendering live tile in Overview. * diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index f8368aed6c..d91669ad96 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -148,10 +148,11 @@ public class TaskThumbnailView extends View { public void setThumbnail(@Nullable Task task, @Nullable ThumbnailData thumbnailData, boolean refreshNow) { mTask = task; + boolean thumbnailWasNull = mThumbnailData == null; mThumbnailData = (thumbnailData != null && thumbnailData.thumbnail != null) ? thumbnailData : null; if (refreshNow) { - refresh(); + refresh(thumbnailWasNull && mThumbnailData != null); } } @@ -162,14 +163,22 @@ public class TaskThumbnailView extends View { /** Updates the shader, paint, matrix to redraw. */ public void refresh() { + refresh(false); + } + + /** + * Updates the shader, paint, matrix to redraw. + * @param shouldRefreshOverlay whether to re-initialize overlay + */ + private void refresh(boolean shouldRefreshOverlay) { if (mThumbnailData != null && mThumbnailData.thumbnail != null) { Bitmap bm = mThumbnailData.thumbnail; bm.prepareToDraw(); mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint.setShader(mBitmapShader); updateThumbnailMatrix(); - if (mOverlayEnabled) { - getTaskOverlay().refreshActionVisibility(mThumbnailData); + if (shouldRefreshOverlay) { + refreshOverlay(); } } else { mBitmapShader = null; From 45f2306ce96246b5ceb1d7723f1768e73aaa990f Mon Sep 17 00:00:00 2001 From: Thales Lima Date: Fri, 12 Nov 2021 11:20:09 +0000 Subject: [PATCH 17/18] open grid task menu to the right of icon This makes the TaskMenuViewWithArrow open to the right of the icon if there is enough space, and to the left if not. It also works correctly in RTL, inverting the side to open by default. Bug: 193432925 Test: open Overview and tap the app icon Change-Id: Ib1098f48ed28d2e0758fb0e3fb733e86271fa1a0 --- quickstep/res/values/dimens.xml | 1 + quickstep/src/com/android/quickstep/KtR.java | 1 + .../quickstep/views/TaskMenuViewWithArrow.kt | 123 +++++++++++++++++- .../android/launcher3/popup/ArrowPopup.java | 51 +++++--- .../launcher3/popup/RoundedArrowDrawable.java | 26 ++++ 5 files changed, 177 insertions(+), 25 deletions(-) diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index e48c9e8b6b..4e6b7b99df 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -28,6 +28,7 @@ 4dp 2dp 234dp + 8dp 48dp 16dp diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java index 57dad08456..a768ef5253 100644 --- a/quickstep/src/com/android/quickstep/KtR.java +++ b/quickstep/src/com/android/quickstep/KtR.java @@ -30,6 +30,7 @@ public class KtR { public static final class dimen { public static int task_menu_spacing = R.dimen.task_menu_spacing; + public static int task_menu_horizontal_padding = R.dimen.task_menu_horizontal_padding; } public static final class layout { diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt index 5059f8b532..179fd68361 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt @@ -23,14 +23,18 @@ import android.graphics.Rect import android.graphics.drawable.ShapeDrawable import android.graphics.drawable.shapes.RectShape import android.util.AttributeSet +import android.view.Gravity import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout import android.widget.LinearLayout import com.android.launcher3.BaseDraggingActivity import com.android.launcher3.DeviceProfile +import com.android.launcher3.InsettableFrameLayout import com.android.launcher3.R import com.android.launcher3.popup.ArrowPopup +import com.android.launcher3.popup.RoundedArrowDrawable import com.android.launcher3.popup.SystemShortcut import com.android.launcher3.util.Themes import com.android.quickstep.KtR @@ -43,9 +47,13 @@ class TaskMenuViewWithArrow : ArrowPopup { fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean { val activity = BaseDraggingActivity - .fromContext(taskContainer.taskView.context) + .fromContext(taskContainer.taskView.context) val taskMenuViewWithArrow = activity.layoutInflater - .inflate(KtR.layout.task_menu_with_arrow, activity.dragLayer, false) as TaskMenuViewWithArrow<*> + .inflate( + KtR.layout.task_menu_with_arrow, + activity.dragLayer, + false + ) as TaskMenuViewWithArrow<*> return taskMenuViewWithArrow.populateAndShowForTask(taskContainer) } @@ -53,10 +61,21 @@ class TaskMenuViewWithArrow : ArrowPopup { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) init { clipToOutline = true + + shouldScaleArrow = true + // This synchronizes the arrow and menu to open at the same time + OPEN_CHILD_FADE_START_DELAY = OPEN_FADE_START_DELAY + OPEN_CHILD_FADE_DURATION = OPEN_FADE_DURATION + CLOSE_FADE_START_DELAY = CLOSE_CHILD_FADE_START_DELAY + CLOSE_FADE_DURATION = CLOSE_CHILD_FADE_DURATION } private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid) @@ -65,6 +84,13 @@ class TaskMenuViewWithArrow : ArrowPopup { private lateinit var optionLayout: LinearLayout private lateinit var taskContainer: TaskIdAttributeContainer + private var optionMeasuredHeight = 0 + private val arrowHorizontalPadding: Int + get() = if (taskView.isFocusedTask) + resources.getDimensionPixelSize(KtR.dimen.task_menu_horizontal_padding) + else + 0 + override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0 override fun getTargetObjectLocation(outPos: Rect?) { @@ -147,7 +173,10 @@ class TaskMenuViewWithArrow : ArrowPopup { } override fun assignMarginsAndBackgrounds(viewGroup: ViewGroup) { - assignMarginsAndBackgrounds(this, Themes.getAttrColor(context, com.android.internal.R.attr.colorSurface)) + assignMarginsAndBackgrounds( + this, + Themes.getAttrColor(context, com.android.internal.R.attr.colorSurface) + ) } override fun onCreateOpenAnimation(anim: AnimatorSet) { @@ -164,4 +193,90 @@ class TaskMenuViewWithArrow : ArrowPopup { ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f) ) } + + /** + * Orients this container to the left or right of the given icon, aligning with the first option + * or second. + * + * These are the preferred orientations, in order (RTL prefers right-aligned over left): + * - Right and first option aligned + * - Right and second option aligned + * - Left and first option aligned + * - Left and second option aligned + * + * So we always align right if there is enough horizontal space + */ + override fun orientAboutObject() { + measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) + // Needed for offsets later + optionMeasuredHeight = optionLayout.getChildAt(0).measuredHeight + val extraHorizontalSpace = (mArrowHeight + mArrowOffsetVertical + arrowHorizontalPadding) + + val widthWithArrow = measuredWidth + paddingLeft + paddingRight + extraHorizontalSpace + getTargetObjectLocation(mTempRect) + val dragLayer: InsettableFrameLayout = popupContainer + val insets = dragLayer.insets + + // Put to the right of the icon if there is space, which means left aligned with the menu + val rightAlignedMenuStartX = mTempRect.left - widthWithArrow + val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace + mIsLeftAligned = if (mIsRtl) { + rightAlignedMenuStartX + insets.left < 0 + } else { + leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left < + dragLayer.width - insets.right + } + + var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX + + // Offset y so that the arrow and first row are center-aligned with the original icon. + val iconHeight = mTempRect.height() + val optionHeight = optionMeasuredHeight + val yOffset = (optionHeight - iconHeight) / 2 + var menuStartY = mTempRect.top - yOffset + + // Insets are added later, so subtract them now. + menuStartX -= insets.left + menuStartY -= insets.top + + setX(menuStartX.toFloat()) + setY(menuStartY.toFloat()) + + val lp = layoutParams as FrameLayout.LayoutParams + val arrowLp = mArrow.layoutParams as FrameLayout.LayoutParams + lp.gravity = Gravity.TOP + arrowLp.gravity = lp.gravity + } + + override fun addArrow() { + popupContainer.addView(mArrow) + mArrow.x = getArrowX() + mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) + + updateArrowColor() + + // This is inverted (x = height, y = width) because the arrow is rotated + mArrow.pivotX = if (mIsLeftAligned) 0f else mArrowHeight.toFloat() + mArrow.pivotY = 0f + } + + private fun getArrowX(): Float { + return if (mIsLeftAligned) + x - mArrowHeight + else + x + measuredWidth + mArrowOffsetVertical + } + + override fun updateArrowColor() { + mArrow.background = RoundedArrowDrawable( + mArrowWidth.toFloat(), + mArrowHeight.toFloat(), + mArrowPointRadius.toFloat(), + mIsLeftAligned, + mArrowColor + ) + elevation = mElevation + mArrow.elevation = mElevation + } + } \ No newline at end of file diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 5a1e4bf27e..b1a41093f5 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -77,44 +77,45 @@ public abstract class ArrowPopup extends AbstractFloatingView { // Duration values (ms) for popup open and close animations. - private static final int OPEN_DURATION = 276; - private static final int OPEN_FADE_START_DELAY = 0; - private static final int OPEN_FADE_DURATION = 38; - private static final int OPEN_CHILD_FADE_START_DELAY = 38; - private static final int OPEN_CHILD_FADE_DURATION = 76; + protected int OPEN_DURATION = 276; + protected int OPEN_FADE_START_DELAY = 0; + protected int OPEN_FADE_DURATION = 38; + protected int OPEN_CHILD_FADE_START_DELAY = 38; + protected int OPEN_CHILD_FADE_DURATION = 76; - private static final int CLOSE_DURATION = 200; - private static final int CLOSE_FADE_START_DELAY = 140; - private static final int CLOSE_FADE_DURATION = 50; - private static final int CLOSE_CHILD_FADE_START_DELAY = 0; - private static final int CLOSE_CHILD_FADE_DURATION = 140; + protected int CLOSE_DURATION = 200; + protected int CLOSE_FADE_START_DELAY = 140; + protected int CLOSE_FADE_DURATION = 50; + protected int CLOSE_CHILD_FADE_START_DELAY = 0; + protected int CLOSE_CHILD_FADE_DURATION = 140; // Index used to get background color when using local wallpaper color extraction, private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_neutral2_800; private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50; - private final Rect mTempRect = new Rect(); + protected final Rect mTempRect = new Rect(); protected final LayoutInflater mInflater; - private final float mOutlineRadius; + protected final float mOutlineRadius; protected final T mActivityContext; protected final boolean mIsRtl; - private final int mArrowOffsetVertical; - private final int mArrowOffsetHorizontal; - private final int mArrowWidth; - private final int mArrowHeight; - private final int mArrowPointRadius; - private final View mArrow; + protected final int mArrowOffsetVertical; + protected final int mArrowOffsetHorizontal; + protected final int mArrowWidth; + protected final int mArrowHeight; + protected final int mArrowPointRadius; + protected final View mArrow; private final int mMargin; protected boolean mIsLeftAligned; protected boolean mIsAboveIcon; - private int mGravity; + protected int mGravity; protected AnimatorSet mOpenCloseAnimator; protected boolean mDeferContainerRemoval; + protected boolean shouldScaleArrow = false; private final GradientDrawable mRoundedTop; private final GradientDrawable mRoundedBottom; @@ -122,10 +123,10 @@ public abstract class ArrowPopup private Runnable mOnCloseCallback = () -> { }; // The rect string of the view that the arrow is attached to, in screen reference frame. - private int mArrowColor; + protected int mArrowColor; protected final List mColorExtractors; - private final float mElevation; + protected final float mElevation; private final int mBackgroundColor; private final String mIterateChildrenTag; @@ -729,6 +730,14 @@ public abstract class ArrowPopup scale.setInterpolator(interpolator); animatorSet.play(scale); + if (shouldScaleArrow) { + Animator arrowScaleAnimator = ObjectAnimator.ofFloat(mArrow, View.SCALE_Y, + scaleValues); + arrowScaleAnimator.setDuration(totalDuration); + arrowScaleAnimator.setInterpolator(interpolator); + animatorSet.play(arrowScaleAnimator); + } + fadeInChildViews(this, alphaValues, childFadeStartDelay, childFadeDuration, animatorSet); return animatorSet; diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java index e662d5c039..436aa51de9 100644 --- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java +++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java @@ -78,6 +78,32 @@ public class RoundedArrowDrawable extends Drawable { mPath.transform(pathTransform); } + /** + * Constructor for an arrow that points to the left or right. + * + * @param width of the arrow. + * @param height of the arrow. + * @param radius of the tip of the arrow. + * @param isPointingLeft or not. + * @param color to draw the triangle. + */ + public RoundedArrowDrawable(float width, float height, float radius, boolean isPointingLeft, + int color) { + mPath = new Path(); + mPaint = new Paint(); + mPaint.setColor(color); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setAntiAlias(true); + + // Make the drawable with the triangle pointing down... + addDownPointingRoundedTriangleToPath(width, height, radius, mPath); + + // ... then rotate it to the side it needs to point. + Matrix pathTransform = new Matrix(); + pathTransform.setRotate(isPointingLeft ? 90 : -90, width * 0.5f, height * 0.5f); + mPath.transform(pathTransform); + } + @Override public void draw(Canvas canvas) { canvas.drawPath(mPath, mPaint); From 4670d37e55c65caa46d6ec45be137028ff355aba Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Thu, 18 Nov 2021 15:57:28 +0000 Subject: [PATCH 18/18] Check if ThumbnailData's bitmap is null in TaskThumbnailCache - This makes sure TaskThumbnailCache fetch for thumbnail when its Bitamp is null Fix: 206959035 Test: See steps in b/206959035 Change-Id: I03b574b0f8cc7390a8cad618bd810f44f0dee279 --- quickstep/src/com/android/quickstep/TaskThumbnailCache.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java index eaa43cfd9c..3175ba8463 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java @@ -134,7 +134,8 @@ public class TaskThumbnailCache { Preconditions.assertUIThread(); boolean lowResolution = !mHighResLoadingState.isEnabled(); - if (task.thumbnail != null && (!task.thumbnail.reducedResolution || lowResolution)) { + if (task.thumbnail != null && task.thumbnail.thumbnail != null + && (!task.thumbnail.reducedResolution || lowResolution)) { // Nothing to load, the thumbnail is already high-resolution or matches what the // request, so just callback callback.accept(task.thumbnail); @@ -152,7 +153,8 @@ public class TaskThumbnailCache { Preconditions.assertUIThread(); ThumbnailData cachedThumbnail = mCache.getAndInvalidateIfModified(key); - if (cachedThumbnail != null && (!cachedThumbnail.reducedResolution || lowResolution)) { + if (cachedThumbnail != null && cachedThumbnail.thumbnail != null + && (!cachedThumbnail.reducedResolution || lowResolution)) { // Already cached, lets use that thumbnail callback.accept(cachedThumbnail); return null;