Merge "Allow app pairs in folders" into 24D1-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (C) 2024 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<com.android.launcher3.apppairs.AppPairIcon
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:focusable="true"
|
||||
launcher:iconDisplay="folder" >
|
||||
<com.android.launcher3.apppairs.AppPairIconGraphic
|
||||
android:id="@+id/app_pair_icon_graphic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false" />
|
||||
<com.android.launcher3.BubbleTextView
|
||||
style="@style/BaseIcon"
|
||||
android:id="@+id/app_pair_icon_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false"
|
||||
android:layout_gravity="top"
|
||||
android:textColor="?attr/folderTextColor"
|
||||
launcher:iconDisplay="folder" />
|
||||
</com.android.launcher3.apppairs.AppPairIcon>
|
||||
@@ -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<T extends View & PageIndicator> extends PagedView<T>
|
||||
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<T extends View & PageIndicator> extends PagedView<T>
|
||||
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<T extends View & PageIndicator> extends PagedView<T>
|
||||
}
|
||||
} else if (child instanceof FolderIcon) {
|
||||
FolderInfo folderInfo = (FolderInfo) info;
|
||||
List<WorkspaceItemInfo> matches = folderInfo.getContents().stream()
|
||||
List<ItemInfo> matches = folderInfo.getContents().stream()
|
||||
.filter(matcher)
|
||||
.collect(Collectors.toList());
|
||||
if (!matches.isEmpty()) {
|
||||
@@ -3381,7 +3378,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<WorkspaceItemInfo> itemCheck) {
|
||||
public void maybeRedrawForWorkspaceUpdate(Predicate<ItemInfo> 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)) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
@@ -310,9 +327,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;
|
||||
|
||||
@@ -343,14 +358,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;
|
||||
@@ -490,7 +503,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mInfo = info;
|
||||
mFromTitle = info.title;
|
||||
mFromLabelState = info.getFromLabelState();
|
||||
ArrayList<WorkspaceItemInfo> children = info.getContents();
|
||||
ArrayList<ItemInfo> children = info.getContents();
|
||||
Collections.sort(children, ITEM_POS_COMPARATOR);
|
||||
updateItemLocationsInDatabaseBatch(true);
|
||||
|
||||
@@ -623,7 +636,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
// onDropComplete. Perform cleanup once drag-n-drop ends.
|
||||
mDragController.addDragListener(this);
|
||||
|
||||
ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.getContents());
|
||||
ArrayList<ItemInfo> items = new ArrayList<>(mInfo.getContents());
|
||||
mEmptyCellRank = items.size();
|
||||
items.add(null); // Add an empty spot at the end
|
||||
|
||||
@@ -644,7 +657,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<WorkspaceItemInfo> items, int pageNo) {
|
||||
private void animateOpen(List<ItemInfo> items, int pageNo) {
|
||||
if (items == null || items.size() <= 1) {
|
||||
Log.d(TAG, "Couldn't animate folder open because items is: " + items);
|
||||
return;
|
||||
@@ -893,8 +906,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) {
|
||||
@@ -1047,7 +1059,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<View> views = getIconsInReadingOrder();
|
||||
@@ -1096,7 +1108,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
ArrayList<ItemInfo> 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);
|
||||
}
|
||||
@@ -1109,8 +1121,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;
|
||||
});
|
||||
}
|
||||
@@ -1295,15 +1306,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;
|
||||
@@ -1311,7 +1322,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;
|
||||
@@ -1373,14 +1384,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);
|
||||
@@ -1388,7 +1399,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);
|
||||
@@ -1403,7 +1414,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(List<WorkspaceItemInfo> items) {
|
||||
public void onRemove(List<ItemInfo> items) {
|
||||
mItemsInvalidated = true;
|
||||
items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
|
||||
if (mState == STATE_ANIMATING) {
|
||||
@@ -1420,7 +1431,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);
|
||||
}
|
||||
|
||||
@@ -1448,7 +1459,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
return mItemsInReadingOrder;
|
||||
}
|
||||
|
||||
public List<BubbleTextView> getItemsOnPage(int page) {
|
||||
public List<View> getItemsOnPage(int page) {
|
||||
ArrayList<View> allItems = getIconsInReadingOrder();
|
||||
int lastPage = mContent.getPageCount() - 1;
|
||||
int totalItemsInFolder = allItems.size();
|
||||
@@ -1460,9 +1471,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
int startIndex = page * itemsPerPage;
|
||||
int endIndex = Math.min(startIndex + numItemsOnCurrentPage, allItems.size());
|
||||
|
||||
List<BubbleTextView> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
|
||||
List<View> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
|
||||
for (int i = startIndex; i < endIndex; ++i) {
|
||||
itemsOnCurrentPage.add((BubbleTextView) allItems.get(i));
|
||||
itemsOnCurrentPage.add(allItems.get(i));
|
||||
}
|
||||
return itemsOnCurrentPage;
|
||||
}
|
||||
|
||||
@@ -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<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(0);
|
||||
final List<View> 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<BubbleTextView> getPreviewIconsOnPage(int page) {
|
||||
private List<View> 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<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(
|
||||
final List<View> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WorkspaceItemInfo> mCurrentPreviewItems = new ArrayList<>();
|
||||
private List<ItemInfo> 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<WorkspaceItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
|
||||
List<ItemInfo> 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<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
|
||||
public List<ItemInfo> 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<WorkspaceItemInfo> itemCheck) {
|
||||
public void updatePreviewItems(Predicate<ItemInfo> 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<WorkspaceItemInfo> items) {
|
||||
public void onRemove(List<ItemInfo> items) {
|
||||
updatePreviewItems(false);
|
||||
boolean wasDotted = mDotInfo.hasDot();
|
||||
items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
|
||||
|
||||
@@ -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<PageIndicatorDots> implements Cli
|
||||
/**
|
||||
* Binds items to the layout.
|
||||
*/
|
||||
public void bindItems(List<WorkspaceItemInfo> items) {
|
||||
public void bindItems(List<ItemInfo> items) {
|
||||
if (mViewsBound) {
|
||||
unbindItems();
|
||||
}
|
||||
@@ -164,8 +166,11 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> 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<PageIndicatorDots> 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<PageIndicatorDots> 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<PageIndicatorDots> 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<PageIndicatorDots> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<PreviewItemDrawingParams> params, boolean animate) {
|
||||
List<WorkspaceItemInfo> items = mIcon.getPreviewItemsOnPage(page);
|
||||
List<ItemInfo> 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<WorkspaceItemInfo> itemCheck) {
|
||||
void updatePreviewItems(Predicate<ItemInfo> 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<WorkspaceItemInfo> oldItems, List<WorkspaceItemInfo> newItems,
|
||||
WorkspaceItemInfo dropped) {
|
||||
public void onDrop(List<ItemInfo> oldItems, List<ItemInfo> newItems, ItemInfo dropped) {
|
||||
int numItems = newItems.size();
|
||||
final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
|
||||
buildParamsForPage(0, params, false);
|
||||
|
||||
// New preview items for items that are moving in (except for the dropped item).
|
||||
List<WorkspaceItemInfo> moveIn = new ArrayList<>();
|
||||
for (WorkspaceItemInfo newItem : newItems) {
|
||||
List<ItemInfo> 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<WorkspaceItemInfo> moveOut = new ArrayList<>(oldItems);
|
||||
List<ItemInfo> 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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -376,7 +376,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)
|
||||
|
||||
@@ -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<WorkspaceItemInfo> = 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<WorkspaceItemInfo>
|
||||
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<ItemInfo> =
|
||||
ArrayList(contents.stream().map { it as ItemInfo }.toList())
|
||||
|
||||
/** Returns the app pair's member apps as an ArrayList of [WorkspaceItemInfo]. */
|
||||
override fun getAppContents(): ArrayList<WorkspaceItemInfo> = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,21 @@ import com.android.launcher3.util.ContentWriter
|
||||
import java.util.function.Predicate
|
||||
|
||||
abstract class CollectionInfo : ItemInfo() {
|
||||
var contents: ArrayList<WorkspaceItemInfo> = 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<ItemInfo>
|
||||
|
||||
/**
|
||||
* 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<WorkspaceItemInfo>
|
||||
|
||||
/** Convenience function. Checks contents to see if any match a given predicate. */
|
||||
fun anyMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
|
||||
return contents.stream().anyMatch(matcher)
|
||||
}
|
||||
|
||||
/** Convenience function. Returns true if none of the contents match a given predicate. */
|
||||
fun noneMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
|
||||
return contents.stream().noneMatch(matcher)
|
||||
}
|
||||
fun anyMatch(matcher: Predicate<ItemInfo>) = getContents().stream().anyMatch(matcher)
|
||||
|
||||
override fun onAddToDatabase(writer: ContentWriter) {
|
||||
super.onAddToDatabase(writer)
|
||||
|
||||
@@ -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<ItemInfo> contents = new ArrayList<>();
|
||||
|
||||
private ArrayList<FolderListener> 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<WorkspaceItemInfo> items, boolean animate) {
|
||||
getContents().removeAll(items);
|
||||
public void removeAll(List<ItemInfo> 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<ItemInfo> 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<WorkspaceItemInfo> getAppContents() {
|
||||
ArrayList<WorkspaceItemInfo> 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<WorkspaceItemInfo> item);
|
||||
void onAdd(ItemInfo item, int rank);
|
||||
void onRemove(List<ItemInfo> 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.
|
||||
*/
|
||||
|
||||
@@ -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<WorkspaceItemInfo>
|
||||
private lateinit var folderItems: ArrayList<ItemInfo>
|
||||
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,
|
||||
|
||||
@@ -160,6 +160,6 @@ public class CacheDataUpdatedTaskTest {
|
||||
}
|
||||
|
||||
private List<WorkspaceItemInfo> allItems() {
|
||||
return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getContents();
|
||||
return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getAppContents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WorkspaceItemInfo>, vararg indices: Int) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user