diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index 4462f20810..2730be1b57 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -118,7 +118,7 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba FolderInfo fi = (FolderInfo) info; if (fi.anyMatch(matcher)) { FolderDotInfo folderDotInfo = new FolderDotInfo(); - for (WorkspaceItemInfo si : fi.getContents()) { + for (ItemInfo si : fi.getContents()) { folderDotInfo.addDotInfo(mPopupDataProvider.getDotInfoForItem(si)); } ((FolderIcon) v).setDotInfo(folderDotInfo); diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java index f4da867646..59bf10533c 100644 --- a/quickstep/src/com/android/quickstep/util/AppPairsController.java +++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java @@ -153,7 +153,7 @@ public class AppPairsController { IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache(); MODEL_EXECUTOR.execute(() -> { - newAppPair.getContents().forEach(member -> { + newAppPair.getAppContents().forEach(member -> { member.title = ""; member.bitmap = iconCache.getDefaultIcon(newAppPair.user); iconCache.getTitleAndIcon(member, member.usingLowResIcon()); diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index 6b27004593..a2d3859135 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -671,6 +671,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC appIcon2, dividerPos ) + floatingView.bringToFront() // Launcher animation: animate the floating view, expanding to fill the display surface progressUpdater.addUpdateListener( diff --git a/res/layout/folder_app_pair.xml b/res/layout/folder_app_pair.xml new file mode 100644 index 0000000000..acecd46314 --- /dev/null +++ b/res/layout/folder_app_pair.xml @@ -0,0 +1,39 @@ + + + + + + \ No newline at end of file diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index ce3c55adb7..e80156cd1f 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -17,7 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; -import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE; @@ -1873,12 +1873,9 @@ public class Workspace extends PagedView return false; } - boolean aboveShortcut = (dropOverView.getTag() instanceof WorkspaceItemInfo - && ((WorkspaceItemInfo) dropOverView.getTag()).container - != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION); - boolean willBecomeShortcut = - (info.itemType == ITEM_TYPE_APPLICATION || - info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT); + boolean aboveShortcut = Folder.willAccept(dropOverView.getTag()) + && ((ItemInfo) dropOverView.getTag()).container != CONTAINER_HOTSEAT_PREDICTION; + boolean willBecomeShortcut = Folder.willAcceptItemType(info.itemType); return (aboveShortcut && willBecomeShortcut); } @@ -1925,12 +1922,12 @@ public class Workspace extends PagedView mCreateUserFolderOnDrop = false; final int screenId = getCellLayoutId(target); - boolean aboveShortcut = (v.getTag() instanceof WorkspaceItemInfo); - boolean willBecomeShortcut = (newView.getTag() instanceof WorkspaceItemInfo); + boolean aboveShortcut = Folder.willAccept(v.getTag()); + boolean willBecomeShortcut = Folder.willAccept(newView.getTag()); if (aboveShortcut && willBecomeShortcut) { - WorkspaceItemInfo sourceInfo = (WorkspaceItemInfo) newView.getTag(); - WorkspaceItemInfo destInfo = (WorkspaceItemInfo) v.getTag(); + ItemInfo sourceInfo = (ItemInfo) newView.getTag(); + ItemInfo destInfo = (ItemInfo) v.getTag(); // if the drag started here, we need to remove it from the workspace if (!external) { getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); @@ -3314,7 +3311,7 @@ public class Workspace extends PagedView } } else if (child instanceof FolderIcon) { FolderInfo folderInfo = (FolderInfo) info; - List matches = folderInfo.getContents().stream() + List matches = folderInfo.getContents().stream() .filter(matcher) .collect(Collectors.toList()); if (!matches.isEmpty()) { @@ -3381,7 +3378,7 @@ public class Workspace extends PagedView FolderInfo fi = (FolderInfo) info; if (fi.anyMatch(matcher)) { FolderDotInfo folderDotInfo = new FolderDotInfo(); - for (WorkspaceItemInfo si : fi.getContents()) { + for (ItemInfo si : fi.getContents()) { folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si)); } ((FolderIcon) v).setDotInfo(folderDotInfo); diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java index 52073cc77a..84d6a6fea5 100644 --- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java +++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java @@ -23,6 +23,7 @@ import android.view.View; import com.android.launcher3.CellLayout; import com.android.launcher3.R; import com.android.launcher3.accessibility.BaseAccessibilityDelegate.DragType; +import com.android.launcher3.folder.Folder; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -117,7 +118,7 @@ public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelega return mContext.getString(R.string.item_moved); } else { ItemInfo info = (ItemInfo) child.getTag(); - if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) { + if (Folder.willAccept(info)) { return mContext.getString(R.string.folder_created); } else if (info instanceof FolderInfo) { @@ -148,8 +149,8 @@ public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelega if (TextUtils.isEmpty(info.title)) { // Find the first item in the folder. FolderInfo folder = (FolderInfo) info; - WorkspaceItemInfo firstItem = null; - for (WorkspaceItemInfo shortcut : folder.getContents()) { + ItemInfo firstItem = null; + for (ItemInfo shortcut : folder.getContents()) { if (firstItem == null || firstItem.rank > shortcut.rank) { firstItem = shortcut; } diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java index 9010f8215d..8ce1c19c47 100644 --- a/src/com/android/launcher3/apppairs/AppPairIcon.java +++ b/src/com/android/launcher3/apppairs/AppPairIcon.java @@ -30,11 +30,13 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Reorderable; import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.data.AppPairInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.views.ActivityContext; @@ -179,10 +181,18 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab return mIconGraphic; } + /** + * Ensures that both app icons in the pair are loaded in high resolution. + */ + public void verifyHighRes() { + IconCache iconCache = LauncherAppState.getInstance(getContext()).getIconCache(); + getInfo().fetchHiResIconsIfNeeded(iconCache); + } + /** * Called when WorkspaceItemInfos get updated, and the app pair icon may need to be redrawn. */ - public void maybeRedrawForWorkspaceUpdate(Predicate itemCheck) { + public void maybeRedrawForWorkspaceUpdate(Predicate itemCheck) { // If either of the app pair icons return true on the predicate (i.e. in the list of // updated apps), redraw the icon graphic (icon background and both icons). if (getInfo().anyMatch(itemCheck)) { diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawable.java b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java index c0ac11a4a1..db83d91a4b 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconDrawable.java +++ b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java @@ -32,7 +32,7 @@ import com.android.launcher3.icons.FastBitmapDrawable; * A composed Drawable consisting of the two app pair icons and the background behind them (looks * like two rectangles). */ -class AppPairIconDrawable extends Drawable { +public class AppPairIconDrawable extends Drawable { private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final AppPairIconDrawingParams mP; private final FastBitmapDrawable mIcon1; @@ -102,6 +102,7 @@ class AppPairIconDrawable extends Drawable { } mIcon2.draw(canvas); + canvas.restore(); } /** @@ -205,4 +206,14 @@ class AppPairIconDrawable extends Drawable { public void setColorFilter(ColorFilter colorFilter) { mBackgroundPaint.setColorFilter(colorFilter); } + + @Override + public int getIntrinsicWidth() { + return mP.getIconSize(); + } + + @Override + public int getIntrinsicHeight() { + return mP.getIconSize(); + } } diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt index 62e5771776..e2c267044a 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt +++ b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt @@ -77,22 +77,29 @@ class AppPairIconDrawingParams(val context: Context, container: Int) { innerPadding = iconSize * INNER_PADDING_SCALE memberIconSize = iconSize * MEMBER_ICON_SCALE updateOrientation(dp) - if (container == DISPLAY_FOLDER) { - val ta = - context.theme.obtainStyledAttributes( - intArrayOf(R.attr.materialColorSurfaceContainerLowest) - ) - bgColor = ta.getColor(0, 0) - ta.recycle() - } else { - val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview) - bgColor = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0) - ta.recycle() - } + bgColor = getBgColorForContainer(container) } /** Checks the device orientation and updates isLeftRightSplit accordingly. */ fun updateOrientation(dp: DeviceProfile) { isLeftRightSplit = dp.isLeftRightSplit } + + private fun getBgColorForContainer(container: Int): Int { + val color: Int + if (container == DISPLAY_FOLDER) { + val ta = + context.theme.obtainStyledAttributes( + intArrayOf(R.attr.materialColorSurfaceContainerLowest) + ) + color = ta.getColor(0, 0) + ta.recycle() + } else { + val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview) + color = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0) + ta.recycle() + } + + return color + } } diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt index a3a1cfccde..86ee0c00ba 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt +++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt @@ -19,7 +19,6 @@ package com.android.launcher3.apppairs import android.content.Context import android.graphics.Canvas import android.graphics.Rect -import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.Gravity import android.widget.FrameLayout @@ -52,7 +51,10 @@ constructor(context: Context, attrs: AttributeSet? = null) : * 2) One of the member apps can't be launched due to screen size requirements. */ @JvmStatic - fun composeDrawable(appPairInfo: AppPairInfo, p: AppPairIconDrawingParams): Drawable { + fun composeDrawable( + appPairInfo: AppPairInfo, + p: AppPairIconDrawingParams + ): AppPairIconDrawable { // Generate new icons, using themed flag if needed. val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0 val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, flags) @@ -81,7 +83,7 @@ constructor(context: Context, attrs: AttributeSet? = null) : private lateinit var parentIcon: AppPairIcon private lateinit var drawParams: AppPairIconDrawingParams - private lateinit var drawable: Drawable + lateinit var drawable: AppPairIconDrawable fun init(icon: AppPairIcon, container: Int) { parentIcon = icon @@ -116,12 +118,6 @@ constructor(context: Context, attrs: AttributeSet? = null) : redraw() } - /** Updates the icon drawable and redraws it */ - fun redraw() { - drawable = composeDrawable(parentIcon.info, drawParams) - invalidate() - } - /** * Gets this icon graphic's visual bounds, with respect to the parent icon's coordinate system. */ @@ -136,6 +132,12 @@ constructor(context: Context, attrs: AttributeSet? = null) : ) } + /** Updates the icon drawable and redraws it */ + fun redraw() { + drawable = composeDrawable(parentIcon.info, drawParams) + invalidate() + } + override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) drawable.draw(canvas) diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index aa3c5ba824..f4afb4a136 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -19,6 +19,9 @@ package com.android.launcher3.folder; import static android.text.TextUtils.isEmpty; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; @@ -66,14 +69,12 @@ import androidx.core.content.res.ResourcesCompat; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Alarm; -import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherSettings; import com.android.launcher3.OnAlarmListener; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; @@ -166,6 +167,22 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo private static final Rect sTempRect = new Rect(); private static final int MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION = 10; + /** + * Checks if {@code o} is an {@link ItemInfo} type that can be placed in folders. + */ + public static boolean willAccept(Object o) { + return o instanceof ItemInfo info && willAcceptItemType(info.itemType); + } + + /** + * Checks if {@code itemType} is a type that can be placed in folders. + */ + public static boolean willAcceptItemType(int itemType) { + return itemType == ITEM_TYPE_APPLICATION + || itemType == ITEM_TYPE_DEEP_SHORTCUT + || itemType == ITEM_TYPE_APP_PAIR; + } + private final Alarm mReorderAlarm = new Alarm(Looper.getMainLooper()); private final Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper()); private final Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper()); @@ -313,9 +330,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo public boolean startDrag(View v, DragOptions options) { Object tag = v.getTag(); - if (tag instanceof WorkspaceItemInfo) { - WorkspaceItemInfo item = (WorkspaceItemInfo) tag; - + if (tag instanceof ItemInfo item) { mEmptyCellRank = item.rank; mCurrentDragView = v; @@ -346,14 +361,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } mContent.removeItem(mCurrentDragView); - if (dragObject.dragInfo instanceof WorkspaceItemInfo) { - mItemsInvalidated = true; + mItemsInvalidated = true; - // We do not want to get events for the item being removed, as they will get handled - // when the drop completes - try (SuppressInfoChanges s = new SuppressInfoChanges()) { - mInfo.remove((WorkspaceItemInfo) dragObject.dragInfo, true); - } + // We do not want to get events for the item being removed, as they will get handled + // when the drop completes + try (SuppressInfoChanges s = new SuppressInfoChanges()) { + mInfo.remove(dragObject.dragInfo, true); } mDragInProgress = true; mItemAddedBackToSelfViaIcon = false; @@ -493,7 +506,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mInfo = info; mFromTitle = info.title; mFromLabelState = info.getFromLabelState(); - ArrayList children = info.getContents(); + ArrayList children = info.getContents(); Collections.sort(children, ITEM_POS_COMPARATOR); updateItemLocationsInDatabaseBatch(true); @@ -626,7 +639,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo // onDropComplete. Perform cleanup once drag-n-drop ends. mDragController.addDragListener(this); - ArrayList items = new ArrayList<>(mInfo.getContents()); + ArrayList items = new ArrayList<>(mInfo.getContents()); mEmptyCellRank = items.size(); items.add(null); // Add an empty spot at the end @@ -647,7 +660,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo * is animated relative to the specified View. If the View is null, no animation * is played. */ - private void animateOpen(List items, int pageNo) { + private void animateOpen(List items, int pageNo) { if (items == null || items.size() <= 1) { Log.d(TAG, "Couldn't animate folder open because items is: " + items); return; @@ -896,8 +909,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo public boolean acceptDrop(DragObject d) { final ItemInfo item = d.dragInfo; final int itemType = item.itemType; - return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || - itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)); + return Folder.willAcceptItemType(itemType); } public void onDragEnter(DragObject d) { @@ -1050,7 +1062,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } } else { // The drag failed, we need to return the item to the folder - WorkspaceItemInfo info = (WorkspaceItemInfo) d.dragInfo; + ItemInfo info = d.dragInfo; View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info) ? mCurrentDragView : mContent.createNewView(info); ArrayList views = getIconsInReadingOrder(); @@ -1099,7 +1111,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo ArrayList items = new ArrayList<>(); int total = mInfo.getContents().size(); for (int i = 0; i < total; i++) { - WorkspaceItemInfo itemInfo = mInfo.getContents().get(i); + ItemInfo itemInfo = mInfo.getContents().get(i); if (verifier.updateRankAndPos(itemInfo, i)) { items.add(itemInfo); } @@ -1112,8 +1124,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo Executors.MODEL_EXECUTOR.post(() -> { FolderNameInfos nameInfos = new FolderNameInfos(); FolderNameProvider fnp = FolderNameProvider.newInstance(getContext()); - fnp.getSuggestedFolderName( - getContext(), mInfo.getContents(), nameInfos); + fnp.getSuggestedFolderName(getContext(), mInfo.getAppContents(), nameInfos); mInfo.suggestedFolderNames = nameInfos; }); } @@ -1298,15 +1309,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo d.deferDragViewCleanupPostAnimation = false; mRearrangeOnClose = true; } else { - final WorkspaceItemInfo si; + final ItemInfo si; if (pasiSi != null) { si = pasiSi; } else if (d.dragInfo instanceof WorkspaceItemFactory) { // Came from all apps -- make a copy. si = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(launcher); } else { - // WorkspaceItemInfo - si = (WorkspaceItemInfo) d.dragInfo; + // WorkspaceItemInfo or AppPairInfo + si = d.dragInfo; } View currentDragView; @@ -1314,7 +1325,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank); // Actually move the item in the database if it was an external drag. Call this - // before creating the view, so that WorkspaceItemInfo is updated appropriately. + // before creating the view, so that the ItemInfo is updated appropriately. mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase( si, mInfo.id, 0, si.cellX, si.cellY); mIsExternalDrag = false; @@ -1376,14 +1387,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo // This is used so the item doesn't immediately appear in the folder when added. In one case // we need to create the illusion that the item isn't added back to the folder yet, to // to correspond to the animation of the icon back into the folder. This is - public void hideItem(WorkspaceItemInfo info) { + public void hideItem(ItemInfo info) { View v = getViewForInfo(info); if (v != null) { v.setVisibility(INVISIBLE); } } - public void showItem(WorkspaceItemInfo info) { + public void showItem(ItemInfo info) { View v = getViewForInfo(info); if (v != null) { v.setVisibility(VISIBLE); @@ -1391,7 +1402,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } @Override - public void onAdd(WorkspaceItemInfo item, int rank) { + public void onAdd(ItemInfo item, int rank) { FolderGridOrganizer verifier = new FolderGridOrganizer( mActivityContext.getDeviceProfile()).setFolderInfo(mInfo); verifier.updateRankAndPos(item, rank); @@ -1406,7 +1417,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } @Override - public void onRemove(List items) { + public void onRemove(List items) { mItemsInvalidated = true; items.stream().map(this::getViewForInfo).forEach(mContent::removeItem); if (mState == STATE_ANIMATING) { @@ -1423,7 +1434,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } } - private View getViewForInfo(final WorkspaceItemInfo item) { + private View getViewForInfo(final ItemInfo item) { return mContent.iterateOverItems((info, view) -> info == item); } @@ -1451,7 +1462,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return mItemsInReadingOrder; } - public List getItemsOnPage(int page) { + public List getItemsOnPage(int page) { ArrayList allItems = getIconsInReadingOrder(); int lastPage = mContent.getPageCount() - 1; int totalItemsInFolder = allItems.size(); @@ -1463,9 +1474,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo int startIndex = page * itemsPerPage; int endIndex = Math.min(startIndex + numItemsOnCurrentPage, allItems.size()); - List itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage); + List itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage); for (int i = startIndex; i < endIndex; ++i) { - itemsOnCurrentPage.add((BubbleTextView) allItems.get(i)); + itemsOnCurrentPage.add(allItems.get(i)); } return itemsOnCurrentPage; } diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java index a91373ba49..7a2ec97f4d 100644 --- a/src/com/android/launcher3/folder/FolderAnimationManager.java +++ b/src/com/android/launcher3/folder/FolderAnimationManager.java @@ -43,6 +43,7 @@ import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PropertyResetListener; +import com.android.launcher3.apppairs.AppPairIcon; import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; @@ -127,7 +128,7 @@ public class FolderAnimationManager { (BaseDragLayer.LayoutParams) mFolder.getLayoutParams(); mFolderIcon.getPreviewItemManager().recomputePreviewDrawingParams(); ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule(); - final List itemsInPreview = getPreviewIconsOnPage(0); + final List itemsInPreview = getPreviewIconsOnPage(0); // Match position of the FolderIcon final Rect folderIconPos = new Rect(); @@ -139,8 +140,8 @@ public class FolderAnimationManager { // Match size/scale of icons in the preview float previewScale = rule.scaleForItem(itemsInPreview.size()); float previewSize = rule.getIconSize() * previewScale; - float initialScale = previewSize / itemsInPreview.get(0).getIconSize() - * scaleRelativeToDragLayer; + float baseIconSize = getBubbleTextView(itemsInPreview.get(0)).getIconSize(); + float initialScale = previewSize / baseIconSize * scaleRelativeToDragLayer; final float finalScale = 1f; float scale = mIsOpening ? initialScale : finalScale; mFolder.setPivotX(0); @@ -198,11 +199,12 @@ public class FolderAnimationManager { // Initialize the Folder items' text. PropertyResetListener colorResetListener = new PropertyResetListener<>(TEXT_ALPHA_PROPERTY, 1f); - for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) { + for (View icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) { + BubbleTextView titleText = getBubbleTextView(icon); if (mIsOpening) { - icon.setTextVisibility(false); + titleText.setTextVisibility(false); } - ObjectAnimator anim = icon.createTextAlphaAnimator(mIsOpening); + ObjectAnimator anim = titleText.createTextAlphaAnimator(mIsOpening); anim.addListener(colorResetListener); play(a, anim); } @@ -339,7 +341,7 @@ public class FolderAnimationManager { /** * Returns the list of "preview items" on {@param page}. */ - private List getPreviewIconsOnPage(int page) { + private List getPreviewIconsOnPage(int page) { return mPreviewVerifier.setFolderInfo(mFolder.mInfo) .previewItemsForPage(page, mFolder.getIconsInReadingOrder()); } @@ -351,7 +353,7 @@ public class FolderAnimationManager { int previewItemOffsetX, int previewItemOffsetY) { ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule(); boolean isOnFirstPage = mFolder.mContent.getCurrentPage() == 0; - final List itemsInPreview = getPreviewIconsOnPage( + final List itemsInPreview = getPreviewIconsOnPage( isOnFirstPage ? 0 : mFolder.mContent.getCurrentPage()); final int numItemsInPreview = itemsInPreview.size(); final int numItemsInFirstPagePreview = isOnFirstPage @@ -361,48 +363,49 @@ public class FolderAnimationManager { ShortcutAndWidgetContainer cwc = mContent.getPageAt(0).getShortcutsAndWidgets(); for (int i = 0; i < numItemsInPreview; ++i) { - final BubbleTextView btv = itemsInPreview.get(i); - CellLayoutLayoutParams btvLp = (CellLayoutLayoutParams) btv.getLayoutParams(); + final View v = itemsInPreview.get(i); + CellLayoutLayoutParams vLp = (CellLayoutLayoutParams) v.getLayoutParams(); // Calculate the final values in the LayoutParams. - btvLp.isLockedToGrid = true; - cwc.setupLp(btv); + vLp.isLockedToGrid = true; + cwc.setupLp(v); // Match scale of icons in the preview of the items on the first page. float previewScale = rule.scaleForItem(numItemsInFirstPagePreview); float previewSize = rule.getIconSize() * previewScale; - float iconScale = previewSize / itemsInPreview.get(i).getIconSize(); + float baseIconSize = getBubbleTextView(v).getIconSize(); + float iconScale = previewSize / baseIconSize; final float initialScale = iconScale / folderScale; final float finalScale = 1f; float scale = mIsOpening ? initialScale : finalScale; - btv.setScaleX(scale); - btv.setScaleY(scale); + v.setScaleX(scale); + v.setScaleY(scale); // Match positions of the icons in the folder with their positions in the preview rule.computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, mTmpParams); // The PreviewLayoutRule assumes that the icon size takes up the entire width so we // offset by the actual size. - int iconOffsetX = (int) ((btvLp.width - btv.getIconSize()) * iconScale) / 2; + int iconOffsetX = (int) ((vLp.width - baseIconSize) * iconScale) / 2; final int previewPosX = (int) ((mTmpParams.transX - iconOffsetX + previewItemOffsetX) / folderScale); - final float paddingTop = btv.getPaddingTop() * iconScale; + final float paddingTop = v.getPaddingTop() * iconScale; final int previewPosY = (int) ((mTmpParams.transY + previewItemOffsetY - paddingTop) / folderScale); - final float xDistance = previewPosX - btvLp.x; - final float yDistance = previewPosY - btvLp.y; + final float xDistance = previewPosX - vLp.x; + final float yDistance = previewPosY - vLp.y; - Animator translationX = getAnimator(btv, View.TRANSLATION_X, xDistance, 0f); + Animator translationX = getAnimator(v, View.TRANSLATION_X, xDistance, 0f); translationX.setInterpolator(previewItemInterpolator); play(animatorSet, translationX); - Animator translationY = getAnimator(btv, View.TRANSLATION_Y, yDistance, 0f); + Animator translationY = getAnimator(v, View.TRANSLATION_Y, yDistance, 0f); translationY.setInterpolator(previewItemInterpolator); play(animatorSet, translationY); - Animator scaleAnimator = getAnimator(btv, SCALE_PROPERTY, initialScale, finalScale); + Animator scaleAnimator = getAnimator(v, SCALE_PROPERTY, initialScale, finalScale); scaleAnimator.setInterpolator(previewItemInterpolator); play(animatorSet, scaleAnimator); @@ -426,20 +429,20 @@ public class FolderAnimationManager { super.onAnimationStart(animation); // Necessary to initialize values here because of the start delay. if (mIsOpening) { - btv.setTranslationX(xDistance); - btv.setTranslationY(yDistance); - btv.setScaleX(initialScale); - btv.setScaleY(initialScale); + v.setTranslationX(xDistance); + v.setTranslationY(yDistance); + v.setScaleX(initialScale); + v.setScaleY(initialScale); } } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - btv.setTranslationX(0.0f); - btv.setTranslationY(0.0f); - btv.setScaleX(1f); - btv.setScaleY(1f); + v.setTranslationX(0.0f); + v.setTranslationY(0.0f); + v.setScaleX(1f); + v.setScaleY(1f); } }); } @@ -482,4 +485,15 @@ public class FolderAnimationManager { ? ObjectAnimator.ofArgb(drawable, property, v1, v2) : ObjectAnimator.ofArgb(drawable, property, v2, v1); } + + /** + * Gets the {@link com.android.launcher3.BubbleTextView} from an icon. In some cases the + * BubbleTextView is the whole icon itself, while in others it is contained within the view and + * only serves to store the title text. + */ + private BubbleTextView getBubbleTextView(View v) { + return v instanceof AppPairIcon + ? ((AppPairIcon) v).getTitleTextView() + : (BubbleTextView) v; + } } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 62ce311c3b..6b30b95278 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -71,6 +71,7 @@ import com.android.launcher3.logger.LauncherAtom.FromState; import com.android.launcher3.logger.LauncherAtom.ToState; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.FolderInfo.FolderListener; import com.android.launcher3.model.data.FolderInfo.LabelState; @@ -118,7 +119,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel ClippedFolderIconLayoutRule mPreviewLayoutRule; private PreviewItemManager mPreviewItemManager; private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0); - private List mCurrentPreviewItems = new ArrayList<>(); + private List mCurrentPreviewItems = new ArrayList<>(); boolean mAnimating = false; @@ -215,7 +216,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel // Keep the notification dot up to date with the sum of all the content's dots. FolderDotInfo folderDotInfo = new FolderDotInfo(); - for (WorkspaceItemInfo si : folderInfo.getContents()) { + for (ItemInfo si : folderInfo.getContents()) { folderDotInfo.addDotInfo(activity.getDotInfoForItem(si)); } icon.setDotInfo(folderDotInfo); @@ -261,20 +262,18 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel private boolean willAcceptItem(ItemInfo item) { final int itemType = item.itemType; - return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || - itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) && - item != mInfo && !mFolder.isOpen()); + return (Folder.willAcceptItemType(itemType) && item != mInfo && !mFolder.isOpen()); } public boolean acceptDrop(ItemInfo dragInfo) { return !mFolder.isDestroyed() && willAcceptItem(dragInfo); } - public void addItem(WorkspaceItemInfo item) { + public void addItem(ItemInfo item) { mInfo.add(item, true); } - public void removeItem(WorkspaceItemInfo item, boolean animate) { + public void removeItem(ItemInfo item, boolean animate) { mInfo.remove(item, animate); } @@ -287,8 +286,8 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel mOpenAlarm.setOnAlarmListener(mOnOpenListener); if (SPRING_LOADING_ENABLED && ((dragInfo instanceof WorkspaceItemFactory) - || (dragInfo instanceof WorkspaceItemInfo) - || (dragInfo instanceof PendingAddShortcutInfo))) { + || (dragInfo instanceof PendingAddShortcutInfo) + || Folder.willAccept(dragInfo))) { mOpenAlarm.setAlarm(ON_OPEN_DELAY); } } @@ -303,8 +302,8 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel return mPreviewItemManager.prepareCreateAnimation(destView); } - public void performCreateAnimation(final WorkspaceItemInfo destInfo, final View destView, - final WorkspaceItemInfo srcInfo, final DragObject d, Rect dstRect, + public void performCreateAnimation(final ItemInfo destInfo, final View destView, + final ItemInfo srcInfo, final DragObject d, Rect dstRect, float scaleRelativeToDragLayer) { final DragView srcView = d.dragView; prepareCreateAnimation(destView); @@ -330,7 +329,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel mOpenAlarm.cancelAlarm(); } - private void onDrop(final WorkspaceItemInfo item, DragObject d, Rect finalRect, + private void onDrop(final ItemInfo item, DragObject d, Rect finalRect, float scaleRelativeToDragLayer, int index, boolean itemReturnedOnFailedDrop) { item.cellX = -1; item.cellY = -1; @@ -361,7 +360,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1); boolean itemAdded = false; if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) { - List oldPreviewItems = new ArrayList<>(mCurrentPreviewItems); + List oldPreviewItems = new ArrayList<>(mCurrentPreviewItems); mInfo.add(item, index, false); mCurrentPreviewItems.clear(); mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0)); @@ -422,7 +421,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel FolderNameInfos nameInfos = new FolderNameInfos(); Executors.MODEL_EXECUTOR.post(() -> { d.folderNameProvider.getSuggestedFolderName( - getContext(), mInfo.getContents(), nameInfos); + getContext(), mInfo.getAppContents(), nameInfos); postDelayed(() -> { setLabelSuggestion(nameInfos, d.logInstanceId); invalidate(); @@ -475,15 +474,21 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) { - WorkspaceItemInfo item; + ItemInfo item; if (d.dragInfo instanceof WorkspaceItemFactory) { // Came from all apps -- make a copy item = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(getContext()); } else if (d.dragSource instanceof BaseItemDragListener){ // Came from a different window -- make a copy - item = new WorkspaceItemInfo((WorkspaceItemInfo) d.dragInfo); + if (d.dragInfo instanceof AppPairInfo) { + // dragged item is app pair + item = new AppPairInfo((AppPairInfo) d.dragInfo); + } else { + // dragged item is WorkspaceItemInfo + item = new WorkspaceItemInfo((WorkspaceItemInfo) d.dragInfo); + } } else { - item = (WorkspaceItemInfo) d.dragInfo; + item = d.dragInfo; } mFolder.notifyDrop(); onDrop(item, d, null, 1.0f, @@ -665,7 +670,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel /** * Returns the list of items which should be visible in the preview */ - public List getPreviewItemsOnPage(int page) { + public List getPreviewItemsOnPage(int page) { return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.getContents()); } @@ -690,12 +695,12 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel /** * Updates the preview items which match the provided condition */ - public void updatePreviewItems(Predicate itemCheck) { + public void updatePreviewItems(Predicate itemCheck) { mPreviewItemManager.updatePreviewItems(itemCheck); } @Override - public void onAdd(WorkspaceItemInfo item, int rank) { + public void onAdd(ItemInfo item, int rank) { updatePreviewItems(false); boolean wasDotted = mDotInfo.hasDot(); mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item)); @@ -707,7 +712,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel } @Override - public void onRemove(List items) { + public void onRemove(List items) { updatePreviewItems(false); boolean wasDotted = mDotInfo.hasDot(); items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo); diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index f2bed925c1..8eaa0dceab 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -41,8 +41,10 @@ import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Utilities; +import com.android.launcher3.apppairs.AppPairIcon; import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.keyboard.ViewGroupFocusHelper; +import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pageindicators.PageIndicatorDots; @@ -148,7 +150,7 @@ public class FolderPagedView extends PagedView implements Cli /** * Binds items to the layout. */ - public void bindItems(List items) { + public void bindItems(List items) { if (mViewsBound) { unbindItems(); } @@ -164,8 +166,11 @@ public class FolderPagedView extends PagedView implements Cli CellLayout page = (CellLayout) getChildAt(i); ShortcutAndWidgetContainer container = page.getShortcutsAndWidgets(); for (int j = container.getChildCount() - 1; j >= 0; j--) { - container.getChildAt(j).setVisibility(View.VISIBLE); - mViewCache.recycleView(R.layout.folder_application, container.getChildAt(j)); + View iconView = container.getChildAt(j); + iconView.setVisibility(View.VISIBLE); + if (iconView instanceof BubbleTextView) { + mViewCache.recycleView(R.layout.folder_application, iconView); + } } page.removeAllViews(); mViewCache.recycleView(R.layout.folder_page, page); @@ -185,7 +190,7 @@ public class FolderPagedView extends PagedView implements Cli * Creates and adds an icon corresponding to the provided rank * @return the created icon */ - public View createAndAddViewForRank(WorkspaceItemInfo item, int rank) { + public View createAndAddViewForRank(ItemInfo item, int rank) { View icon = createNewView(item); if (!mViewsBound) { return icon; @@ -200,7 +205,7 @@ public class FolderPagedView extends PagedView implements Cli * Adds the {@param view} to the layout based on {@param rank} and updated the position * related attributes. It assumes that {@param item} is already attached to the view. */ - public void addViewForRank(View view, WorkspaceItemInfo item, int rank) { + public void addViewForRank(View view, ItemInfo item, int rank) { int pageNo = rank / mOrganizer.getMaxItemsPerPage(); CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams(); @@ -209,26 +214,36 @@ public class FolderPagedView extends PagedView implements Cli } @SuppressLint("InflateParams") - public View createNewView(WorkspaceItemInfo item) { + public View createNewView(ItemInfo item) { if (item == null) { return null; } - final BubbleTextView textView = mViewCache.getView( - R.layout.folder_application, getContext(), null); - textView.applyFromWorkspaceItem(item); - textView.setOnClickListener(mFolder.mActivityContext.getItemOnClickListener()); - textView.setOnLongClickListener(mFolder); - textView.setOnFocusChangeListener(mFocusIndicatorHelper); - CellLayoutLayoutParams lp = (CellLayoutLayoutParams) textView.getLayoutParams(); + + final View icon; + if (item instanceof AppPairInfo api) { + // TODO (b/332607759): Make view cache work with app pair icons + icon = AppPairIcon.inflateIcon(R.layout.folder_app_pair, ActivityContext.lookupContext( + getContext()), null , api, BubbleTextView.DISPLAY_FOLDER); + } else { + icon = mViewCache.getView(R.layout.folder_application, getContext(), null); + ((BubbleTextView) icon).applyFromWorkspaceItem((WorkspaceItemInfo) item); + } + + icon.setOnClickListener(mFolder.mActivityContext.getItemOnClickListener()); + icon.setOnLongClickListener(mFolder); + icon.setOnFocusChangeListener(mFocusIndicatorHelper); + + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) icon.getLayoutParams(); if (lp == null) { - textView.setLayoutParams(new CellLayoutLayoutParams( + icon.setLayoutParams(new CellLayoutLayoutParams( item.cellX, item.cellY, item.spanX, item.spanY)); } else { lp.setCellX(item.cellX); lp.setCellY(item.cellY); lp.cellHSpan = lp.cellVSpan = 1; } - return textView; + + return icon; } @Nullable @@ -497,13 +512,20 @@ public class FolderPagedView extends PagedView implements Cli if (page != null) { ShortcutAndWidgetContainer parent = page.getShortcutsAndWidgets(); for (int i = parent.getChildCount() - 1; i >= 0; i--) { - BubbleTextView icon = ((BubbleTextView) parent.getChildAt(i)); - icon.verifyHighRes(); + View iconView = parent.getChildAt(i); + Drawable d = null; + if (iconView instanceof BubbleTextView btv) { + btv.verifyHighRes(); + d = btv.getIcon(); + } else if (iconView instanceof AppPairIcon api) { + api.verifyHighRes(); + d = api.getIconDrawableArea().getDrawable(); + } + // Set the callback back to the actual icon, in case // it was captured by the FolderIcon - Drawable d = icon.getIcon(); if (d != null) { - d.setCallback(icon); + d.setCallback(iconView); } } } diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java index 33bcf217de..07215c4710 100644 --- a/src/com/android/launcher3/folder/LauncherDelegate.java +++ b/src/com/android/launcher3/folder/LauncherDelegate.java @@ -33,7 +33,7 @@ import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.data.FolderInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; @@ -86,7 +86,7 @@ public class LauncherDelegate { FolderInfo info = folder.mInfo; if (itemCount <= 1) { View newIcon = null; - WorkspaceItemInfo finalItem = null; + ItemInfo finalItem = null; if (itemCount == 1) { // Move the item from the folder to the workspace, in the position of the diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java index 58efdc12ce..0faa1c9a23 100644 --- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java +++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java @@ -17,7 +17,7 @@ package com.android.launcher3.folder; import android.graphics.drawable.Drawable; -import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.model.data.ItemInfo; /** * Manages the parameters used to draw a Folder preview item. @@ -30,7 +30,7 @@ class PreviewItemDrawingParams { public FolderPreviewItemAnim anim; public boolean hidden; public Drawable drawable; - public WorkspaceItemInfo item; + public ItemInfo item; PreviewItemDrawingParams(float transX, float transY, float scale) { this.transX = transX; diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 9001a0c271..63116384c3 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -16,6 +16,7 @@ package com.android.launcher3.folder; +import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW; @@ -41,7 +42,12 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Utilities; +import com.android.launcher3.apppairs.AppPairIcon; +import com.android.launcher3.apppairs.AppPairIconDrawingParams; +import com.android.launcher3.apppairs.AppPairIconGraphic; import com.android.launcher3.graphics.PreloadIconDrawable; +import com.android.launcher3.model.data.AppPairInfo; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.Themes; @@ -125,7 +131,9 @@ public class PreviewItemManager { } Drawable prepareCreateAnimation(final View destView) { - Drawable animateDrawable = ((BubbleTextView) destView).getIcon(); + Drawable animateDrawable = destView instanceof AppPairIcon + ? ((AppPairIcon) destView).getIconDrawableArea().getDrawable() + : ((BubbleTextView) destView).getIcon(); computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth()); mReferenceDrawable = animateDrawable; @@ -258,7 +266,7 @@ public class PreviewItemManager { } void buildParamsForPage(int page, ArrayList params, boolean animate) { - List items = mIcon.getPreviewItemsOnPage(page); + List items = mIcon.getPreviewItemsOnPage(page); // We adjust the size of the list to match the number of items in the preview. while (items.size() < params.size()) { @@ -328,16 +336,18 @@ public class PreviewItemManager { mNumOfPrevItems = numOfPrevItemsAux; } - void updatePreviewItems(Predicate itemCheck) { + void updatePreviewItems(Predicate itemCheck) { boolean modified = false; for (PreviewItemDrawingParams param : mFirstPageParams) { - if (itemCheck.test(param.item)) { + if (itemCheck.test(param.item) + || (param.item instanceof AppPairInfo api && api.anyMatch(itemCheck))) { setDrawable(param, param.item); modified = true; } } for (PreviewItemDrawingParams param : mCurrentPageParams) { - if (itemCheck.test(param.item)) { + if (itemCheck.test(param.item) + || (param.item instanceof AppPairInfo api && api.anyMatch(itemCheck))) { setDrawable(param, param.item); modified = true; } @@ -370,15 +380,14 @@ public class PreviewItemManager { * @param newItems The list of items in the new preview. * @param dropped The item that was dropped onto the FolderIcon. */ - public void onDrop(List oldItems, List newItems, - WorkspaceItemInfo dropped) { + public void onDrop(List oldItems, List newItems, ItemInfo dropped) { int numItems = newItems.size(); final ArrayList params = mFirstPageParams; buildParamsForPage(0, params, false); // New preview items for items that are moving in (except for the dropped item). - List moveIn = new ArrayList<>(); - for (WorkspaceItemInfo newItem : newItems) { + List moveIn = new ArrayList<>(); + for (ItemInfo newItem : newItems) { if (!oldItems.contains(newItem) && !newItem.equals(dropped)) { moveIn.add(newItem); } @@ -401,10 +410,10 @@ public class PreviewItemManager { } // Old preview items that need to be moved out. - List moveOut = new ArrayList<>(oldItems); + List moveOut = new ArrayList<>(oldItems); moveOut.removeAll(newItems); for (int i = 0; i < moveOut.size(); ++i) { - WorkspaceItemInfo item = moveOut.get(i); + ItemInfo item = moveOut.get(i); int oldIndex = oldItems.indexOf(item); PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null); updateTransitionParam(p, item, oldIndex, EXIT_INDEX, numItems); @@ -418,7 +427,7 @@ public class PreviewItemManager { } } - private void updateTransitionParam(final PreviewItemDrawingParams p, WorkspaceItemInfo item, + private void updateTransitionParam(final PreviewItemDrawingParams p, ItemInfo item, int prevIndex, int newIndex, int numItems) { setDrawable(p, item); @@ -431,16 +440,24 @@ public class PreviewItemManager { } @VisibleForTesting - public void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) { - if (item.hasPromiseIconUi() || (item.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { - PreloadIconDrawable drawable = newPendingIcon(mContext, item); - p.drawable = drawable; - } else { - p.drawable = item.newIcon(mContext, - Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0); + public void setDrawable(PreviewItemDrawingParams p, ItemInfo item) { + if (item instanceof WorkspaceItemInfo wii) { + if (wii.hasPromiseIconUi() || (wii.runtimeStatusFlags + & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { + PreloadIconDrawable drawable = newPendingIcon(mContext, wii); + p.drawable = drawable; + } else { + p.drawable = wii.newIcon(mContext, + Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0); + } + p.drawable.setBounds(0, 0, mIconSize, mIconSize); + } else if (item instanceof AppPairInfo api) { + AppPairIconDrawingParams appPairParams = + new AppPairIconDrawingParams(mContext, DISPLAY_FOLDER); + p.drawable = AppPairIconGraphic.composeDrawable(api, appPairParams); + p.drawable.setBounds(0, 0, mIconSize, mIconSize); } - p.drawable.setBounds(0, 0, mIconSize, mIconSize); + p.item = item; // Set the callback to FolderIcon as it is responsible to drawing the icon. The // callback will be released when the folder is opened. diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 44e45da7af..d5de4cee5e 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -44,6 +44,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.CollectionInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -259,10 +260,15 @@ public class BgDataModel { itemsIdMap.put(item.id, item); switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: - collections.put(item.id, (CollectionInfo) item); + collections.put(item.id, (FolderInfo) item); workspaceItems.add(item); break; + case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: + collections.put(item.id, (AppPairInfo) item); + // Fall through here. App pairs are both containers (like folders) and containable + // items (can be placed in folders). So we need to add app pairs to the folders + // array (above) but also verify the existence of their container, like regular + // apps (below). case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || @@ -277,7 +283,7 @@ public class BgDataModel { Log.e(TAG, msg); } } else { - findOrMakeFolder(item.container).add((WorkspaceItemInfo) item); + findOrMakeFolder(item.container).add(item); } } break; diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java index 1deb6657e1..cc20cd194c 100644 --- a/src/com/android/launcher3/model/FirstScreenBroadcast.java +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -115,7 +115,7 @@ public class FirstScreenBroadcast { for (ItemInfo info : firstScreenItems) { if (info instanceof CollectionInfo ci) { String collectionItemInfoPackage; - for (ItemInfo collectionItemInfo : cloneOnMainThread(ci.getContents())) { + for (ItemInfo collectionItemInfo : cloneOnMainThread(ci.getAppContents())) { collectionItemInfoPackage = getPackageName(collectionItemInfo); if (collectionItemInfoPackage != null && packages.contains(collectionItemInfoPackage)) { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 30cccd5f47..e0ced83855 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -81,7 +81,6 @@ import com.android.launcher3.model.data.CollectionInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.IconRequestInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; @@ -494,9 +493,7 @@ public class LoaderTask implements Runnable { } appPair.getContents().sort(Folder.ITEM_POS_COMPARATOR); - // Fetch hi-res icons if needed. - appPair.getContents().stream().filter(ItemInfoWithIcon::usingLowResIcon) - .forEach(member -> mIconCache.getTitleAndIcon(member, false)); + appPair.fetchHiResIconsIfNeeded(mIconCache); } } @@ -566,12 +563,16 @@ public class LoaderTask implements Runnable { // Ranks are the source of truth for folder items, so cellX and cellY can be // ignored for now. Database will be updated once user manually modifies folder. for (int rank = 0; rank < size; ++rank) { - WorkspaceItemInfo info = folder.getContents().get(rank); + ItemInfo info = folder.getContents().get(rank); info.rank = rank; - if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION + if (info instanceof WorkspaceItemInfo wii + && wii.usingLowResIcon() + && wii.itemType == Favorites.ITEM_TYPE_APPLICATION && verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) { - mIconCache.getTitleAndIcon(info, false); + mIconCache.getTitleAndIcon(wii, false); + } else if (info instanceof AppPairInfo api) { + api.fetchHiResIconsIfNeeded(mIconCache); } } } @@ -788,7 +789,7 @@ public class LoaderTask implements Runnable { FolderNameInfos suggestionInfos = new FolderNameInfos(); CollectionInfo info = mBgDataModel.collections.valueAt(i); if (info instanceof FolderInfo fi && fi.suggestedFolderNames == null) { - provider.getSuggestedFolderName(mApp.getContext(), fi.getContents(), + provider.getSuggestedFolderName(mApp.getContext(), fi.getAppContents(), suggestionInfos); fi.suggestedFolderNames = suggestionInfos; } diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt index aa2929096e..d27be727af 100644 --- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt +++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt @@ -375,7 +375,7 @@ class WorkspaceItemProcessor( val folderInfo: FolderInfo = collection val newAppPair = AppPairInfo() // Move the placeholder's contents over to the new app pair. - folderInfo.contents.forEach(newAppPair::add) + folderInfo.getContents().forEach(newAppPair::add) collection = newAppPair // Remove the placeholder and add the app pair into the data model. bgDataModel.collections.remove(c.id) diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt index 408131683e..a56ee8ed2a 100644 --- a/src/com/android/launcher3/model/data/AppPairInfo.kt +++ b/src/com/android/launcher3/model/data/AppPairInfo.kt @@ -18,11 +18,14 @@ package com.android.launcher3.model.data import android.content.Context import com.android.launcher3.LauncherSettings +import com.android.launcher3.icons.IconCache import com.android.launcher3.logger.LauncherAtom import com.android.launcher3.views.ActivityContext /** A type of app collection that launches multiple apps into split screen. */ class AppPairInfo() : CollectionInfo() { + private var contents: ArrayList = ArrayList() + init { itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR } @@ -33,11 +36,28 @@ class AppPairInfo() : CollectionInfo() { add(app2) } - /** Adds an element to the contents array. */ - override fun add(item: WorkspaceItemInfo) { + /** Creates a new AppPairInfo that is a copy of the provided one. */ + constructor(appPairInfo: AppPairInfo) : this() { + contents = appPairInfo.contents.clone() as ArrayList + copyFrom(appPairInfo) + } + + /** Adds an element to the contents ArrayList. */ + override fun add(item: ItemInfo) { + if (item !is WorkspaceItemInfo) { + throw RuntimeException("tried to add an illegal type into an app pair") + } + contents.add(item) } + /** Returns the app pair's member apps as an ArrayList of [ItemInfo]. */ + override fun getContents(): ArrayList = + ArrayList(contents.stream().map { it as ItemInfo }.toList()) + + /** Returns the app pair's member apps as an ArrayList of [WorkspaceItemInfo]. */ + override fun getAppContents(): ArrayList = contents + /** Returns the first app in the pair. */ fun getFirstApp() = contents[0] @@ -50,7 +70,9 @@ class AppPairInfo() : CollectionInfo() { /** Checks if the app pair is launchable at the current screen size. */ fun isLaunchable(context: Context) = (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet || - noneMatch { it.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) } + getAppContents().stream().noneMatch { + it.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) + } /** Generates an ItemInfo for logging. */ override fun buildProto(cInfo: CollectionInfo?): LauncherAtom.ItemInfo { @@ -62,4 +84,11 @@ class AppPairInfo() : CollectionInfo() { .setContainerInfo(getContainerInfo()) .build() } + + /** Fetches high-res icons for member apps if needed. */ + fun fetchHiResIconsIfNeeded(iconCache: IconCache) { + getAppContents().stream().filter(ItemInfoWithIcon::usingLowResIcon).forEach { member -> + iconCache.getTitleAndIcon(member, false) + } + } } diff --git a/src/com/android/launcher3/model/data/CollectionInfo.kt b/src/com/android/launcher3/model/data/CollectionInfo.kt index 2b865a574e..4f5e12fd30 100644 --- a/src/com/android/launcher3/model/data/CollectionInfo.kt +++ b/src/com/android/launcher3/model/data/CollectionInfo.kt @@ -22,19 +22,21 @@ import com.android.launcher3.util.ContentWriter import java.util.function.Predicate abstract class CollectionInfo : ItemInfo() { - var contents: ArrayList = ArrayList() + /** Adds an ItemInfo to the collection. Throws if given an illegal type. */ + abstract fun add(item: ItemInfo) - abstract fun add(item: WorkspaceItemInfo) + /** Returns the collection's contents as an ArrayList of [ItemInfo]. */ + abstract fun getContents(): ArrayList + + /** + * Returns the collection's contents as an ArrayList of [WorkspaceItemInfo]. Does not include + * other collection [ItemInfo]s that are inside this collection; rather, it should collect + * *their* contents and adds them to the ArrayList. + */ + abstract fun getAppContents(): ArrayList /** Convenience function. Checks contents to see if any match a given predicate. */ - fun anyMatch(matcher: Predicate): Boolean { - return contents.stream().anyMatch(matcher) - } - - /** Convenience function. Returns true if none of the contents match a given predicate. */ - fun noneMatch(matcher: Predicate): Boolean { - return contents.stream().noneMatch(matcher) - } + fun anyMatch(matcher: Predicate) = getContents().stream().anyMatch(matcher) override fun onAddToDatabase(writer: ContentWriter) { super.onAddToDatabase(writer) diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java index 1bbb2fe971..56996ef21c 100644 --- a/src/com/android/launcher3/model/data/FolderInfo.java +++ b/src/com/android/launcher3/model/data/FolderInfo.java @@ -29,6 +29,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; +import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderNameInfos; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom.Attribute; @@ -98,14 +99,20 @@ public class FolderInfo extends CollectionInfo { public FolderNameInfos suggestedFolderNames; + /** + * The apps and shortcuts + */ + private final ArrayList contents = new ArrayList<>(); + private ArrayList mListeners = new ArrayList<>(); public FolderInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER; } - /** Adds a app or shortcut to the contents array without animation. */ - public void add(@NonNull WorkspaceItemInfo item) { + /** Adds a app or shortcut to the contents ArrayList without animation. */ + @Override + public void add(@NonNull ItemInfo item) { add(item, false /* animate */); } @@ -114,14 +121,18 @@ public class FolderInfo extends CollectionInfo { * * @param item */ - public void add(WorkspaceItemInfo item, boolean animate) { + public void add(ItemInfo item, boolean animate) { add(item, getContents().size(), animate); } /** * Add an app or shortcut for a specified rank. */ - public void add(WorkspaceItemInfo item, int rank, boolean animate) { + public void add(ItemInfo item, int rank, boolean animate) { + if (!Folder.willAccept(item)) { + throw new RuntimeException("tried to add an illegal type into a folder"); + } + rank = Utilities.boundToRange(rank, 0, getContents().size()); getContents().add(rank, item); for (int i = 0; i < mListeners.size(); i++) { @@ -135,21 +146,49 @@ public class FolderInfo extends CollectionInfo { * * @param item */ - public void remove(WorkspaceItemInfo item, boolean animate) { + public void remove(ItemInfo item, boolean animate) { removeAll(Collections.singletonList(item), animate); } /** * Remove all matching app or shortcut. Does not change the DB. */ - public void removeAll(List items, boolean animate) { - getContents().removeAll(items); + public void removeAll(List items, boolean animate) { + contents.removeAll(items); for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onRemove(items); } itemsChanged(animate); } + /** + * Returns the folder's contents as an ArrayList of {@link ItemInfo}. Includes + * {@link WorkspaceItemInfo} and {@link AppPairInfo}s. + */ + @NonNull + @Override + public ArrayList getContents() { + return contents; + } + + /** + * Returns the folder's contents as an ArrayList of {@link WorkspaceItemInfo}. Note: Does not + * return any {@link AppPairInfo}s contained in the folder, instead collects *their* contents + * and adds them to the ArrayList. + */ + @Override + public ArrayList getAppContents() { + ArrayList workspaceItemInfos = new ArrayList<>(); + for (ItemInfo item : contents) { + if (item instanceof WorkspaceItemInfo wii) { + workspaceItemInfos.add(wii); + } else if (item instanceof AppPairInfo api) { + workspaceItemInfos.addAll(api.getAppContents()); + } + } + return workspaceItemInfos; + } + @Override public void onAddToDatabase(@NonNull ContentWriter writer) { super.onAddToDatabase(writer); @@ -171,8 +210,8 @@ public class FolderInfo extends CollectionInfo { } public interface FolderListener { - void onAdd(WorkspaceItemInfo item, int rank); - void onRemove(List item); + void onAdd(ItemInfo item, int rank); + void onRemove(List item); void onItemsChanged(boolean animate); } @@ -263,10 +302,17 @@ public class FolderInfo extends CollectionInfo { public ItemInfo makeShallowCopy() { FolderInfo folderInfo = new FolderInfo(); folderInfo.copyFrom(this); - folderInfo.setContents(this.getContents()); return folderInfo; } + @Override + public void copyFrom(@NonNull ItemInfo info) { + super.copyFrom(info); + if (info instanceof FolderInfo fi) { + contents.addAll(fi.getContents()); + } + } + /** * Returns index of the accepted suggestion. */ diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt index 3a1883cb02..da14425df0 100644 --- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt +++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt @@ -29,7 +29,7 @@ import com.android.launcher3.icons.BaseIconFactory import com.android.launcher3.icons.FastBitmapDrawable import com.android.launcher3.icons.UserBadgeDrawable import com.android.launcher3.model.data.FolderInfo -import com.android.launcher3.model.data.WorkspaceItemInfo +import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.util.ActivityContextWrapper import com.android.launcher3.util.FlagOp import com.android.launcher3.util.LauncherLayoutBuilder @@ -47,7 +47,7 @@ class PreviewItemManagerTest { private lateinit var previewItemManager: PreviewItemManager private lateinit var context: Context - private lateinit var folderItems: ArrayList + private lateinit var folderItems: ArrayList private lateinit var modelHelper: LauncherModelHelper private lateinit var folderIcon: FolderIcon @@ -72,15 +72,17 @@ class PreviewItemManagerTest { .build() ) .loadModelSync() - folderItems = modelHelper.bgDataModel.collections.valueAt(0).contents + folderItems = modelHelper.bgDataModel.collections.valueAt(0).getContents() folderIcon.mInfo = modelHelper.bgDataModel.collections.valueAt(0) as FolderInfo - folderIcon.mInfo.contents = folderItems + folderIcon.mInfo.getContents().addAll(folderItems) + // Use getAppContents() to "cast" contents to WorkspaceItemInfo so we can set bitmaps + val folderApps = modelHelper.bgDataModel.collections.valueAt(0).getAppContents() // Set first icon to be themed. - folderItems[0] + folderApps[0] .bitmap .setMonoIcon( - folderItems[0].bitmap.icon, + folderApps[0].bitmap.icon, BaseIconFactory( context, context.resources.configuration.densityDpi, @@ -89,7 +91,7 @@ class PreviewItemManagerTest { ) // Set second icon to be non-themed. - folderItems[1] + folderApps[1] .bitmap .setMonoIcon( null, @@ -101,23 +103,21 @@ class PreviewItemManagerTest { ) // Set third icon to be themed with badge. - folderItems[2] + folderApps[2] .bitmap .setMonoIcon( - folderItems[2].bitmap.icon, + folderApps[2].bitmap.icon, BaseIconFactory( context, context.resources.configuration.densityDpi, previewItemManager.mIconSize ) ) - folderItems[2].bitmap = - folderItems[2].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK)) + folderApps[2].bitmap = folderApps[2].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK)) // Set fourth icon to be non-themed with badge. - folderItems[3].bitmap = - folderItems[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK)) - folderItems[3] + folderApps[3].bitmap = folderApps[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK)) + folderApps[3] .bitmap .setMonoIcon( null, diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java index abb0c39d56..d3a63558d8 100644 --- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java +++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java @@ -160,6 +160,6 @@ public class CacheDataUpdatedTaskTest { } private List allItems() { - return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getContents(); + return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getAppContents(); } } diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt index ed587a1d33..2e209a48c4 100644 --- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt +++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt @@ -168,8 +168,8 @@ class FolderIconLoadTest { val collections = modelHelper.getBgDataModel().collections assertThat(collections.size()).isEqualTo(1) - assertThat(collections.valueAt(0).contents.size).isEqualTo(itemCount) - return collections.valueAt(0).contents + assertThat(collections.valueAt(0).getAppContents().size).isEqualTo(itemCount) + return collections.valueAt(0).getAppContents() } private fun verifyHighRes(items: ArrayList, vararg indices: Int) { diff --git a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt index 00655276b9..dae09bb595 100644 --- a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt +++ b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt @@ -139,9 +139,9 @@ class ItemInflaterTest { @Test fun test_folder_inflated_on_UI() { val itemInfo = FolderInfo() - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) val view = MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get() @@ -155,9 +155,9 @@ class ItemInflaterTest { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION) val itemInfo = FolderInfo() - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) val view = VIEW_PREINFLATION_EXECUTOR.submit( @@ -173,8 +173,8 @@ class ItemInflaterTest { fun test_app_pair_inflated_on_UI() { val itemInfo = AppPairInfo() itemInfo.itemType = ITEM_TYPE_APP_PAIR - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) val view = MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get() @@ -189,8 +189,8 @@ class ItemInflaterTest { val itemInfo = AppPairInfo() itemInfo.itemType = ITEM_TYPE_APP_PAIR - itemInfo.contents.add(workspaceItemInfo()) - itemInfo.contents.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) + itemInfo.add(workspaceItemInfo()) val view = VIEW_PREINFLATION_EXECUTOR.submit(