Lazily binding folder pages and icons
Folders are bound before they are opened and unbound on close. This allows us to recycle the views in folders Bug: 139051851 Change-Id: Ic1ed3265c0f583af54d73dab6f2751bc95266ea9
This commit is contained in:
parent
72fddba837
commit
ac6f69f78d
|
@ -20,4 +20,5 @@
|
|||
style="@style/BaseIcon"
|
||||
android:textColor="?attr/folderTextColor"
|
||||
android:includeFontPadding="false"
|
||||
android:hapticFeedbackEnabled="false"
|
||||
launcher:iconDisplay="folder" />
|
||||
|
|
|
@ -93,13 +93,6 @@ public class FolderInfo extends ItemInfo {
|
|||
itemsChanged(animate);
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
this.title = title;
|
||||
for (int i = 0; i < mListeners.size(); i++) {
|
||||
mListeners.get(i).onTitleChanged(title);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddToDatabase(ContentWriter writer) {
|
||||
super.onAddToDatabase(writer);
|
||||
|
@ -121,18 +114,10 @@ public class FolderInfo extends ItemInfo {
|
|||
}
|
||||
}
|
||||
|
||||
public void prepareAutoUpdate() {
|
||||
for (int i = 0; i < mListeners.size(); i++) {
|
||||
mListeners.get(i).prepareAutoUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public interface FolderListener {
|
||||
public void onAdd(WorkspaceItemInfo item, int rank);
|
||||
public void onRemove(WorkspaceItemInfo item);
|
||||
public void onTitleChanged(CharSequence title);
|
||||
public void onItemsChanged(boolean animate);
|
||||
public void prepareAutoUpdate();
|
||||
}
|
||||
|
||||
public boolean hasOption(int optionFlag) {
|
||||
|
|
|
@ -2340,6 +2340,11 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||
// override the previous page so we don't log the page switch.
|
||||
mWorkspace.setCurrentPage(pageBoundFirst, pageBoundFirst /* overridePrevPage */);
|
||||
|
||||
// Cache one page worth of icons
|
||||
getViewCache().setCacheSize(R.layout.folder_application,
|
||||
mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
|
||||
getViewCache().setCacheSize(R.layout.folder_page, 2);
|
||||
|
||||
TraceHelper.endSection("finishBindingItems");
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,6 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
|||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
@ -134,9 +133,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
|
||||
private static final int DEFAULT_PAGE = 0;
|
||||
|
||||
public static final boolean MAP_NO_RECURSE = false;
|
||||
public static final boolean MAP_RECURSE = true;
|
||||
|
||||
private LayoutTransition mLayoutTransition;
|
||||
@Thunk final WallpaperManager mWallpaperManager;
|
||||
|
||||
|
@ -2809,7 +2805,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
* Removes all folder listeners
|
||||
*/
|
||||
public void removeFolderListeners() {
|
||||
mapOverItems(false, new ItemOperator() {
|
||||
mapOverItems(new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View view) {
|
||||
if (view instanceof FolderIcon) {
|
||||
|
@ -2961,7 +2957,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
|
||||
public View getFirstMatch(final ItemOperator operator) {
|
||||
final View[] value = new View[1];
|
||||
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
|
||||
mapOverItems(new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (operator.evaluate(info, v)) {
|
||||
|
@ -2984,7 +2980,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
final View[] matches = new View[operators.length];
|
||||
// For efficiency, the outer loop should be CellLayout.
|
||||
for (CellLayout cellLayout : cellLayouts) {
|
||||
mapOverCellLayout(MAP_NO_RECURSE, cellLayout, (info, v) -> {
|
||||
mapOverCellLayout(cellLayout, (info, v) -> {
|
||||
for (int i = 0; i < operators.length; ++i) {
|
||||
if (matches[i] == null && operators[i].evaluate(info, v)) {
|
||||
matches[i] = v;
|
||||
|
@ -3009,7 +3005,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
}
|
||||
|
||||
void clearDropTargets() {
|
||||
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
|
||||
mapOverItems(new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (v instanceof DropTarget) {
|
||||
|
@ -3054,10 +3050,12 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
} else if (itemToRemove.container >= 0) {
|
||||
// The item may belong to a folder.
|
||||
View parent = idToViewMap.get(itemToRemove.container);
|
||||
if (parent != null) {
|
||||
if (parent instanceof FolderIcon) {
|
||||
FolderInfo folderInfo = (FolderInfo) parent.getTag();
|
||||
folderInfo.prepareAutoUpdate();
|
||||
folderInfo.remove((WorkspaceItemInfo) itemToRemove, false);
|
||||
if (((FolderIcon) parent).getFolder().isOpen()) {
|
||||
((FolderIcon) parent).getFolder().close(false /* animate */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3081,18 +3079,17 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
/**
|
||||
* Map the operator over the shortcuts and widgets, return the first-non-null value.
|
||||
*
|
||||
* @param recurse true: iterate over folder children. false: op get the folders themselves.
|
||||
* @param op the operator to map over the shortcuts
|
||||
*/
|
||||
public void mapOverItems(boolean recurse, ItemOperator op) {
|
||||
public void mapOverItems(ItemOperator op) {
|
||||
for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
|
||||
if (mapOverCellLayout(recurse, layout, op)) {
|
||||
if (mapOverCellLayout(layout, op)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mapOverCellLayout(boolean recurse, CellLayout layout, ItemOperator op) {
|
||||
private boolean mapOverCellLayout(CellLayout layout, ItemOperator op) {
|
||||
// TODO(b/128460496) Potential race condition where layout is not yet loaded
|
||||
if (layout == null) {
|
||||
return false;
|
||||
|
@ -3102,103 +3099,68 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
final int itemCount = container.getChildCount();
|
||||
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
|
||||
View item = container.getChildAt(itemIdx);
|
||||
ItemInfo info = (ItemInfo) item.getTag();
|
||||
if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) {
|
||||
FolderIcon folder = (FolderIcon) item;
|
||||
ArrayList<View> folderChildren = folder.getFolder().getIconsInReadingOrder();
|
||||
// map over all the children in the folder
|
||||
final int childCount = folderChildren.size();
|
||||
for (int childIdx = 0; childIdx < childCount; childIdx++) {
|
||||
View child = folderChildren.get(childIdx);
|
||||
info = (ItemInfo) child.getTag();
|
||||
if (op.evaluate(info, child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (op.evaluate(info, item)) {
|
||||
return true;
|
||||
}
|
||||
if (op.evaluate((ItemInfo) item.getTag(), item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateShortcuts(ArrayList<WorkspaceItemInfo> shortcuts) {
|
||||
int total = shortcuts.size();
|
||||
final HashSet<WorkspaceItemInfo> updates = new HashSet<>(total);
|
||||
final IntSet folderIds = new IntSet();
|
||||
final HashSet<WorkspaceItemInfo> updates = new HashSet<>(shortcuts);
|
||||
ItemOperator op = (info, v) -> {
|
||||
if (v instanceof BubbleTextView && updates.contains(info)) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
BubbleTextView shortcut = (BubbleTextView) v;
|
||||
Drawable oldIcon = shortcut.getIcon();
|
||||
boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
|
||||
&& ((PreloadIconDrawable) oldIcon).hasNotCompleted();
|
||||
shortcut.applyFromWorkspaceItem(si, si.isPromise() != oldPromiseState);
|
||||
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
|
||||
((FolderIcon) v).updatePreviewItems(updates::contains);
|
||||
}
|
||||
|
||||
for (int i = 0; i < total; i++) {
|
||||
WorkspaceItemInfo s = shortcuts.get(i);
|
||||
updates.add(s);
|
||||
folderIds.add(s.container);
|
||||
// Iterate all items
|
||||
return false;
|
||||
};
|
||||
|
||||
mapOverItems(op);
|
||||
Folder openFolder = Folder.getOpen(mLauncher);
|
||||
if (openFolder != null) {
|
||||
openFolder.iterateOverItems(op);
|
||||
}
|
||||
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView &&
|
||||
updates.contains(info)) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
BubbleTextView shortcut = (BubbleTextView) v;
|
||||
Drawable oldIcon = shortcut.getIcon();
|
||||
boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
|
||||
&& ((PreloadIconDrawable) oldIcon).hasNotCompleted();
|
||||
shortcut.applyFromWorkspaceItem(si, si.isPromise() != oldPromiseState);
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Update folder icons
|
||||
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (info instanceof FolderInfo && folderIds.contains(info.id)) {
|
||||
((FolderInfo) info).itemsChanged(false);
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
|
||||
final PackageUserKey packageUserKey = new PackageUserKey(null, null);
|
||||
final IntSet folderIds = new IntSet();
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView) {
|
||||
if (!packageUserKey.updateFromItemInfo(info)
|
||||
|| updatedDots.test(packageUserKey)) {
|
||||
((BubbleTextView) v).applyDotState(info, true /* animate */);
|
||||
folderIds.add(info.container);
|
||||
}
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Predicate<ItemInfo> matcher = info -> !packageUserKey.updateFromItemInfo(info)
|
||||
|| updatedDots.test(packageUserKey);
|
||||
|
||||
// Update folder icons
|
||||
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (info instanceof FolderInfo && folderIds.contains(info.id)
|
||||
&& v instanceof FolderIcon) {
|
||||
ItemOperator op = (info, v) -> {
|
||||
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView) {
|
||||
if (matcher.test(info)) {
|
||||
((BubbleTextView) v).applyDotState(info, true /* animate */);
|
||||
}
|
||||
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
|
||||
FolderInfo fi = (FolderInfo) info;
|
||||
if (fi.contents.stream().anyMatch(matcher)) {
|
||||
FolderDotInfo folderDotInfo = new FolderDotInfo();
|
||||
for (WorkspaceItemInfo si : ((FolderInfo) info).contents) {
|
||||
for (WorkspaceItemInfo si : fi.contents) {
|
||||
folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
|
||||
}
|
||||
((FolderIcon) v).setDotInfo(folderDotInfo);
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
};
|
||||
|
||||
mapOverItems(op);
|
||||
Folder folder = Folder.getOpen(mLauncher);
|
||||
if (folder != null) {
|
||||
folder.iterateOverItems(op);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAbandonedPromise(String packageName, UserHandle user) {
|
||||
|
@ -3210,21 +3172,25 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
}
|
||||
|
||||
public void updateRestoreItems(final HashSet<ItemInfo> updates) {
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v) {
|
||||
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
|
||||
&& updates.contains(info)) {
|
||||
((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */);
|
||||
} else if (v instanceof PendingAppWidgetHostView
|
||||
&& info instanceof LauncherAppWidgetInfo
|
||||
&& updates.contains(info)) {
|
||||
((PendingAppWidgetHostView) v).applyState();
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
ItemOperator op = (info, v) -> {
|
||||
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
|
||||
&& updates.contains(info)) {
|
||||
((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */);
|
||||
} else if (v instanceof PendingAppWidgetHostView
|
||||
&& info instanceof LauncherAppWidgetInfo
|
||||
&& updates.contains(info)) {
|
||||
((PendingAppWidgetHostView) v).applyState();
|
||||
} else if (v instanceof FolderIcon && info instanceof FolderInfo) {
|
||||
((FolderIcon) v).updatePreviewItems(updates::contains);
|
||||
}
|
||||
});
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
};
|
||||
mapOverItems(op);
|
||||
Folder folder = Folder.getOpen(mLauncher);
|
||||
if (folder != null) {
|
||||
folder.iterateOverItems(op);
|
||||
}
|
||||
}
|
||||
|
||||
public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
|
||||
|
@ -3248,7 +3214,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
} else {
|
||||
// widgetRefresh will automatically run when the packages are updated.
|
||||
// For now just update the progress bars
|
||||
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
|
||||
mapOverItems(new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View view) {
|
||||
if (view instanceof PendingAppWidgetHostView
|
||||
|
@ -3372,7 +3338,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
mRefreshPending = false;
|
||||
|
||||
ArrayList<PendingAppWidgetHostView> views = new ArrayList<>(mInfos.size());
|
||||
mapOverItems(MAP_NO_RECURSE, (info, view) -> {
|
||||
mapOverItems((info, view) -> {
|
||||
if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
|
||||
views.add((PendingAppWidgetHostView) view);
|
||||
}
|
||||
|
|
|
@ -170,8 +170,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
private boolean mDeleteFolderOnDropCompleted = false;
|
||||
private boolean mSuppressFolderDeletion = false;
|
||||
private boolean mItemAddedBackToSelfViaIcon = false;
|
||||
@Thunk float mFolderIconPivotX;
|
||||
@Thunk float mFolderIconPivotY;
|
||||
private boolean mIsEditingName = false;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
|
@ -310,7 +308,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
// Convert to a string here to ensure that no other state associated with the text field
|
||||
// gets saved.
|
||||
String newTitle = mFolderName.getText().toString();
|
||||
mInfo.setTitle(newTitle);
|
||||
mInfo.title = newTitle;
|
||||
mFolderIcon.onTitleChanged(newTitle);
|
||||
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
||||
|
||||
if (TextUtils.isEmpty(mInfo.title)) {
|
||||
|
@ -385,7 +384,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
ArrayList<WorkspaceItemInfo> children = info.contents;
|
||||
Collections.sort(children, ITEM_POS_COMPARATOR);
|
||||
updateItemLocationsInDatabaseBatch();
|
||||
mContent.bindItems(children);
|
||||
|
||||
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
|
||||
if (lp == null) {
|
||||
|
@ -393,13 +391,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
lp.customPosition = true;
|
||||
setLayoutParams(lp);
|
||||
}
|
||||
centerAboutIcon();
|
||||
|
||||
mItemsInvalidated = true;
|
||||
updateTextViewFocus();
|
||||
mInfo.addListener(this);
|
||||
|
||||
if (TextUtils.isEmpty(mInfo.title)) {
|
||||
if (!TextUtils.isEmpty(mInfo.title)) {
|
||||
mFolderName.setText(mInfo.title);
|
||||
mFolderName.setHint(null);
|
||||
} else {
|
||||
|
@ -408,11 +403,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
}
|
||||
|
||||
// In case any children didn't come across during loading, clean up the folder accordingly
|
||||
mFolderIcon.post(new Runnable() {
|
||||
public void run() {
|
||||
if (getItemCount() <= 1) {
|
||||
replaceFolderWithFinalItem();
|
||||
}
|
||||
mFolderIcon.post(() -> {
|
||||
if (getItemCount() <= 1) {
|
||||
replaceFolderWithFinalItem();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -472,18 +465,50 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
return folderCount >= MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the folder as part of a drag operation
|
||||
*/
|
||||
public void beginExternalDrag() {
|
||||
mIsExternalDrag = true;
|
||||
mDragInProgress = true;
|
||||
|
||||
// Since this folder opened by another controller, it might not get onDrop or
|
||||
// onDropComplete. Perform cleanup once drag-n-drop ends.
|
||||
mDragController.addDragListener(this);
|
||||
|
||||
ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.contents);
|
||||
mEmptyCellRank = items.size();
|
||||
items.add(null); // Add an empty spot at the end
|
||||
|
||||
animateOpen(items, mEmptyCellRank / mContent.itemsPerPage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the user folder described by the specified tag. The opening of the folder
|
||||
* is animated relative to the specified View. If the View is null, no animation
|
||||
* is played.
|
||||
*/
|
||||
public void animateOpen() {
|
||||
animateOpen(mInfo.contents, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the user folder described by the specified tag. The opening of the folder
|
||||
* is animated relative to the specified View. If the View is null, no animation
|
||||
* is played.
|
||||
*/
|
||||
private void animateOpen(List<WorkspaceItemInfo> items, int pageNo) {
|
||||
Folder openFolder = getOpen(mLauncher);
|
||||
if (openFolder != null && openFolder != this) {
|
||||
// Close any open folder before opening a folder.
|
||||
openFolder.close(true);
|
||||
}
|
||||
|
||||
mContent.bindItems(items);
|
||||
centerAboutIcon();
|
||||
mItemsInvalidated = true;
|
||||
updateTextViewFocus();
|
||||
|
||||
mIsOpen = true;
|
||||
|
||||
DragLayer dragLayer = mLauncher.getDragLayer();
|
||||
|
@ -500,10 +525,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
}
|
||||
|
||||
mContent.completePendingPageChanges();
|
||||
if (!mDragInProgress) {
|
||||
// Open on the first page.
|
||||
mContent.snapToPageImmediately(0);
|
||||
}
|
||||
mContent.snapToPageImmediately(pageNo);
|
||||
|
||||
// This is set to true in close(), but isn't reset to false until onDropCompleted(). This
|
||||
// leads to an inconsistent state if you drag out of the folder and drag back in without
|
||||
|
@ -574,16 +596,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
mContent.verifyVisibleHighResIcons(mContent.getNextPage());
|
||||
}
|
||||
|
||||
public void beginExternalDrag() {
|
||||
mEmptyCellRank = mContent.allocateRankForNewItem();
|
||||
mIsExternalDrag = true;
|
||||
mDragInProgress = true;
|
||||
|
||||
// Since this folder opened by another controller, it might not get onDrop or
|
||||
// onDropComplete. Perform cleanup once drag-n-drop ends.
|
||||
mDragController.addDragListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOfType(int type) {
|
||||
return (type & TYPE_FOLDER) != 0;
|
||||
|
@ -668,6 +680,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
} else if (mDragInProgress) {
|
||||
mDeleteFolderOnDropCompleted = true;
|
||||
}
|
||||
} else if (!mDragInProgress) {
|
||||
mContent.unbindItems();
|
||||
}
|
||||
mSuppressFolderDeletion = false;
|
||||
clearDragInfo();
|
||||
|
@ -953,24 +967,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
setPivotX(folderPivotX);
|
||||
setPivotY(folderPivotY);
|
||||
|
||||
mFolderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
|
||||
(1.0f * folderPivotX / width));
|
||||
mFolderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
|
||||
(1.0f * folderPivotY / height));
|
||||
|
||||
lp.width = width;
|
||||
lp.height = height;
|
||||
lp.x = left;
|
||||
lp.y = top;
|
||||
}
|
||||
|
||||
public float getPivotXForIconAnimation() {
|
||||
return mFolderIconPivotX;
|
||||
}
|
||||
public float getPivotYForIconAnimation() {
|
||||
return mFolderIconPivotY;
|
||||
}
|
||||
|
||||
private int getContentAreaHeight() {
|
||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
||||
int maxContentAreaHeight = grid.availableHeightPx
|
||||
|
@ -1031,7 +1033,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return mContent.getItemCount();
|
||||
return mInfo.contents.size();
|
||||
}
|
||||
|
||||
@Thunk void replaceFolderWithFinalItem() {
|
||||
|
@ -1039,7 +1041,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
Runnable onCompleteRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int itemCount = mInfo.contents.size();
|
||||
int itemCount = getItemCount();
|
||||
if (itemCount <= 1) {
|
||||
View newIcon = null;
|
||||
|
||||
|
@ -1116,6 +1118,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setOnKeyListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1242,9 +1246,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
item.cellY);
|
||||
updateItemLocationsInDatabaseBatch();
|
||||
|
||||
ArrayList<View> items = new ArrayList<>(getIconsInReadingOrder());
|
||||
items.add(rank, mContent.createAndAddViewForRank(item, rank));
|
||||
mContent.arrangeChildren(items);
|
||||
if (mContent.areViewsBound()) {
|
||||
mContent.createAndAddViewForRank(item, rank);
|
||||
}
|
||||
mItemsInvalidated = true;
|
||||
}
|
||||
|
||||
|
@ -1275,12 +1279,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
updateTextViewFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAutoUpdate() {
|
||||
close(false);
|
||||
}
|
||||
|
||||
public void onTitleChanged(CharSequence title) {
|
||||
/**
|
||||
* Utility methods to iterate over items of the view
|
||||
*/
|
||||
public void iterateOverItems(ItemOperator op) {
|
||||
mContent.iterateOverItems(op);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1289,14 +1292,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||
public ArrayList<View> getIconsInReadingOrder() {
|
||||
if (mItemsInvalidated) {
|
||||
mItemsInReadingOrder.clear();
|
||||
mContent.iterateOverItems(new ItemOperator() {
|
||||
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View view) {
|
||||
mItemsInReadingOrder.add(view);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
mContent.iterateOverItems((i, v) -> !mItemsInReadingOrder.add(v));
|
||||
mItemsInvalidated = false;
|
||||
}
|
||||
return mItemsInReadingOrder;
|
||||
|
|
|
@ -69,6 +69,7 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* An icon that can appear on in the workspace representing an {@link Folder}.
|
||||
|
@ -99,7 +100,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
ClippedFolderIconLayoutRule mPreviewLayoutRule;
|
||||
private PreviewItemManager mPreviewItemManager;
|
||||
private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
|
||||
private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
|
||||
private List<WorkspaceItemInfo> mCurrentPreviewItems = new ArrayList<>();
|
||||
|
||||
boolean mAnimating = false;
|
||||
|
||||
|
@ -255,7 +256,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
OnAlarmListener mOnOpenListener = new OnAlarmListener() {
|
||||
public void onAlarm(Alarm alarm) {
|
||||
mFolder.beginExternalDrag();
|
||||
mFolder.animateOpen();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -321,18 +321,17 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1);
|
||||
boolean itemAdded = false;
|
||||
if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
|
||||
List<BubbleTextView> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
|
||||
List<WorkspaceItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
|
||||
mInfo.add(item, index, false);
|
||||
mCurrentPreviewItems.clear();
|
||||
mCurrentPreviewItems.addAll(getPreviewIconsOnPage(0));
|
||||
mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
|
||||
|
||||
if (!oldPreviewItems.equals(mCurrentPreviewItems)) {
|
||||
for (int i = 0; i < mCurrentPreviewItems.size(); ++i) {
|
||||
if (mCurrentPreviewItems.get(i).getTag().equals(item)) {
|
||||
// If the item dropped is going to be in the preview, we update the
|
||||
// index here to reflect its position in the preview.
|
||||
index = i;
|
||||
}
|
||||
int newIndex = mCurrentPreviewItems.indexOf(item);
|
||||
if (newIndex >= 0) {
|
||||
// If the item dropped is going to be in the preview, we update the
|
||||
// index here to reflect its position in the preview.
|
||||
index = newIndex;
|
||||
}
|
||||
|
||||
mPreviewItemManager.hidePreviewItem(index, true);
|
||||
|
@ -531,11 +530,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the list of "preview items" on {@param page}.
|
||||
* Returns the list of items which should be visible in the preview
|
||||
*/
|
||||
public List<BubbleTextView> getPreviewIconsOnPage(int page) {
|
||||
return mPreviewVerifier.setFolderInfo(mFolder.mInfo)
|
||||
.previewItemsForPage(page, mFolder.getIconsInReadingOrder());
|
||||
public List<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
|
||||
return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.contents);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -553,11 +551,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
private void updatePreviewItems(boolean animate) {
|
||||
mPreviewItemManager.updatePreviewItems(animate);
|
||||
mCurrentPreviewItems.clear();
|
||||
mCurrentPreviewItems.addAll(getPreviewIconsOnPage(0));
|
||||
mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAutoUpdate() {
|
||||
/**
|
||||
* Updates the preview items which match the provided condition
|
||||
*/
|
||||
public void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
|
||||
mPreviewItemManager.updatePreviewItems(itemCheck);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -580,7 +581,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTitleChanged(CharSequence title) {
|
||||
mFolderName.setText(title);
|
||||
setContentDescription(getContext().getString(R.string.folder_name_format, title));
|
||||
|
|
|
@ -24,10 +24,10 @@ import android.util.ArrayMap;
|
|||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
|
@ -46,11 +46,14 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
|||
import com.android.launcher3.pageindicators.PageIndicatorDots;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
||||
|
||||
|
@ -69,12 +72,12 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
|
||||
public final boolean mIsRtl;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final ViewGroupFocusHelper mFocusIndicatorHelper;
|
||||
|
||||
@Thunk final ArrayMap<View, Runnable> mPendingAnimations = new ArrayMap<>();
|
||||
|
||||
private final FolderGridOrganizer mOrganizer;
|
||||
private final ViewCache mViewCache;
|
||||
|
||||
private int mAllocatedContentSize;
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
|
@ -84,17 +87,20 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
|
||||
private Folder mFolder;
|
||||
|
||||
// If the views are attached to the folder or not. A folder should be bound when its
|
||||
// animating or is open.
|
||||
private boolean mViewsBound = false;
|
||||
|
||||
public FolderPagedView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
|
||||
mOrganizer = new FolderGridOrganizer(profile);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
|
||||
mIsRtl = Utilities.isRtl(getResources());
|
||||
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||
|
||||
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
|
||||
mViewCache = BaseActivity.fromContext(context).getViewCache();
|
||||
}
|
||||
|
||||
public void setFolder(Folder folder) {
|
||||
|
@ -127,35 +133,50 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
/**
|
||||
* Binds items to the layout.
|
||||
*/
|
||||
public void bindItems(ArrayList<WorkspaceItemInfo> items) {
|
||||
ArrayList<View> icons = new ArrayList<>();
|
||||
for (WorkspaceItemInfo item : items) {
|
||||
icons.add(createNewView(item));
|
||||
public void bindItems(List<WorkspaceItemInfo> items) {
|
||||
if (mViewsBound) {
|
||||
unbindItems();
|
||||
}
|
||||
arrangeChildren(icons);
|
||||
}
|
||||
|
||||
public void allocateSpaceForRank(int rank) {
|
||||
ArrayList<View> views = new ArrayList<>(mFolder.getIconsInReadingOrder());
|
||||
views.add(rank, null);
|
||||
arrangeChildren(views);
|
||||
arrangeChildren(items.stream().map(this::createNewView).collect(Collectors.toList()));
|
||||
mViewsBound = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create space for a new item at the end, and returns the rank for that item.
|
||||
* Also sets the current page to the last page.
|
||||
* Removes all the icons from the folder
|
||||
*/
|
||||
public int allocateRankForNewItem() {
|
||||
int rank = getItemCount();
|
||||
allocateSpaceForRank(rank);
|
||||
setCurrentPage(rank / mOrganizer.getMaxItemsPerPage());
|
||||
return rank;
|
||||
public void unbindItems() {
|
||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||
CellLayout page = (CellLayout) getChildAt(i);
|
||||
ShortcutAndWidgetContainer container = page.getShortcutsAndWidgets();
|
||||
for (int j = container.getChildCount() - 1; j >= 0; j--) {
|
||||
mViewCache.recycleView(R.layout.folder_application, container.getChildAt(j));
|
||||
}
|
||||
page.removeAllViews();
|
||||
mViewCache.recycleView(R.layout.folder_page, page);
|
||||
}
|
||||
removeAllViews();
|
||||
mViewsBound = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the icons are bound to the folder
|
||||
*/
|
||||
public boolean areViewsBound() {
|
||||
return mViewsBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds an icon corresponding to the provided rank
|
||||
* @return the created icon
|
||||
*/
|
||||
public View createAndAddViewForRank(WorkspaceItemInfo item, int rank) {
|
||||
View icon = createNewView(item);
|
||||
allocateSpaceForRank(rank);
|
||||
addViewForRank(icon, item, rank);
|
||||
if (!mViewsBound) {
|
||||
return icon;
|
||||
}
|
||||
ArrayList<View> views = new ArrayList<>(mFolder.getIconsInReadingOrder());
|
||||
views.add(rank, icon);
|
||||
arrangeChildren(views);
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
@ -173,16 +194,24 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
|
||||
@SuppressLint("InflateParams")
|
||||
public View createNewView(WorkspaceItemInfo item) {
|
||||
final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
|
||||
R.layout.folder_application, null, false);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
final BubbleTextView textView = mViewCache.getView(
|
||||
R.layout.folder_application, getContext(), null);
|
||||
textView.applyFromWorkspaceItem(item);
|
||||
textView.setHapticFeedbackEnabled(false);
|
||||
textView.setOnClickListener(ItemClickHandler.INSTANCE);
|
||||
textView.setOnLongClickListener(mFolder);
|
||||
textView.setOnFocusChangeListener(mFocusIndicatorHelper);
|
||||
|
||||
textView.setLayoutParams(new CellLayout.LayoutParams(
|
||||
item.cellX, item.cellY, item.spanX, item.spanY));
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) textView.getLayoutParams();
|
||||
if (lp == null) {
|
||||
textView.setLayoutParams(new CellLayout.LayoutParams(
|
||||
item.cellX, item.cellY, item.spanX, item.spanY));
|
||||
} else {
|
||||
lp.cellX = item.cellX;
|
||||
lp.cellY = item.cellY;
|
||||
lp.cellHSpan = lp.cellVSpan = 1;
|
||||
}
|
||||
return textView;
|
||||
}
|
||||
|
||||
|
@ -197,7 +226,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
|
||||
private CellLayout createAndAddNewPage() {
|
||||
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
|
||||
CellLayout page = (CellLayout) mInflater.inflate(R.layout.folder_page, this, false);
|
||||
CellLayout page = mViewCache.getView(R.layout.folder_page, getContext(), this);
|
||||
page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
|
||||
page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
|
||||
page.setInvertIfRtl(true);
|
||||
|
@ -240,7 +269,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
* @param list the ordered list of children.
|
||||
*/
|
||||
@SuppressLint("RtlHardcoded")
|
||||
public void arrangeChildren(ArrayList<View> list) {
|
||||
public void arrangeChildren(List<View> list) {
|
||||
int itemCount = list.size();
|
||||
ArrayList<CellLayout> pages = new ArrayList<>();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
|
@ -313,16 +342,6 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
|||
(getPageAt(0).getDesiredHeight() + getPaddingTop() + getPaddingBottom()) : 0;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
int lastPageIndex = getChildCount() - 1;
|
||||
if (lastPageIndex < 0) {
|
||||
// If there are no pages, nothing has yet been added to the folder.
|
||||
return 0;
|
||||
}
|
||||
return getPageAt(lastPageIndex).getShortcutsAndWidgets().getChildCount()
|
||||
+ lastPageIndex * mOrganizer.getMaxItemsPerPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rank of the cell nearest to the provided pixel position.
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,8 @@ package com.android.launcher3.folder;
|
|||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
|
||||
/**
|
||||
* Manages the parameters used to draw a Folder preview item.
|
||||
*/
|
||||
|
@ -25,9 +27,10 @@ class PreviewItemDrawingParams {
|
|||
float transY;
|
||||
float scale;
|
||||
float overlayAlpha;
|
||||
FolderPreviewItemAnim anim;
|
||||
public FolderPreviewItemAnim anim;
|
||||
public boolean hidden;
|
||||
Drawable drawable;
|
||||
public Drawable drawable;
|
||||
public WorkspaceItemInfo item;
|
||||
|
||||
PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
|
||||
this.transX = transX;
|
||||
|
|
|
@ -23,28 +23,51 @@ import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION
|
|||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
|
||||
*/
|
||||
public class PreviewItemManager {
|
||||
|
||||
private FolderIcon mIcon;
|
||||
private static final FloatProperty<PreviewItemManager> CURRENT_PAGE_ITEMS_TRANS_X =
|
||||
new FloatProperty<PreviewItemManager>("currentPageItemsTransX") {
|
||||
@Override
|
||||
public void setValue(PreviewItemManager manager, float v) {
|
||||
manager.mCurrentPageItemsTransX = v;
|
||||
manager.onParamsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(PreviewItemManager manager) {
|
||||
return manager.mCurrentPageItemsTransX;
|
||||
}
|
||||
};
|
||||
|
||||
private final Context mContext;
|
||||
private final FolderIcon mIcon;
|
||||
private final DrawableFactory mDrawableFactory;
|
||||
private final int mIconSize;
|
||||
|
||||
// These variables are all associated with the drawing of the preview; they are stored
|
||||
// as member variables for shared usage and to avoid computation on each frame
|
||||
|
@ -69,7 +92,10 @@ public class PreviewItemManager {
|
|||
private static final int ITEM_SLIDE_IN_OUT_DISTANCE_PX = 200;
|
||||
|
||||
public PreviewItemManager(FolderIcon icon) {
|
||||
mContext = icon.getContext();
|
||||
mIcon = icon;
|
||||
mDrawableFactory = DrawableFactory.INSTANCE.get(mContext);
|
||||
mIconSize = Launcher.getLauncher(mContext).getDeviceProfile().folderChildIconSizePx;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,7 +226,7 @@ public class PreviewItemManager {
|
|||
}
|
||||
|
||||
void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
|
||||
List<BubbleTextView> items = mIcon.getPreviewIconsOnPage(page);
|
||||
List<WorkspaceItemInfo> items = mIcon.getPreviewItemsOnPage(page);
|
||||
int prevNumItems = params.size();
|
||||
|
||||
// We adjust the size of the list to match the number of items in the preview.
|
||||
|
@ -214,13 +240,7 @@ public class PreviewItemManager {
|
|||
int numItemsInFirstPagePreview = page == 0 ? items.size() : MAX_NUM_ITEMS_IN_PREVIEW;
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
PreviewItemDrawingParams p = params.get(i);
|
||||
p.drawable = items.get(i).getCompoundDrawables()[1];
|
||||
|
||||
if (p.drawable != null && !mIcon.mFolder.isOpen()) {
|
||||
// Set the callback to FolderIcon as it is responsible to drawing the icon. The
|
||||
// callback will be released when the folder is opened.
|
||||
p.drawable.setCallback(mIcon);
|
||||
}
|
||||
setDrawable(p, items.get(i));
|
||||
|
||||
if (!animate) {
|
||||
computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, p);
|
||||
|
@ -253,14 +273,8 @@ public class PreviewItemManager {
|
|||
buildParamsForPage(currentPage, mCurrentPageParams, false);
|
||||
onParamsChanged();
|
||||
|
||||
ValueAnimator slideAnimator = ValueAnimator.ofFloat(0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
|
||||
slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
mCurrentPageItemsTransX = (float) valueAnimator.getAnimatedValue();
|
||||
onParamsChanged();
|
||||
}
|
||||
});
|
||||
ValueAnimator slideAnimator = ObjectAnimator
|
||||
.ofFloat(this, CURRENT_PAGE_ITEMS_TRANS_X, 0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
|
||||
slideAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -277,6 +291,25 @@ public class PreviewItemManager {
|
|||
buildParamsForPage(0, mFirstPageParams, animate);
|
||||
}
|
||||
|
||||
void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
|
||||
boolean modified = false;
|
||||
for (PreviewItemDrawingParams param : mFirstPageParams) {
|
||||
if (itemCheck.test(param.item)) {
|
||||
setDrawable(param, param.item);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
for (PreviewItemDrawingParams param : mCurrentPageParams) {
|
||||
if (itemCheck.test(param.item)) {
|
||||
setDrawable(param, param.item);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
mIcon.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
boolean verifyDrawable(@NonNull Drawable who) {
|
||||
for (int i = 0; i < mFirstPageParams.size(); i++) {
|
||||
if (mFirstPageParams.get(i).drawable == who) {
|
||||
|
@ -296,46 +329,46 @@ public class PreviewItemManager {
|
|||
* - Moving into a new position
|
||||
* - Moving out of the preview
|
||||
*
|
||||
* @param oldParams The list of items in the old preview.
|
||||
* @param newParams The list of items in the new preview.
|
||||
* @param oldItems The list of items in the old preview.
|
||||
* @param newItems The list of items in the new preview.
|
||||
* @param dropped The item that was dropped onto the FolderIcon.
|
||||
*/
|
||||
public void onDrop(List<BubbleTextView> oldParams, List<BubbleTextView> newParams,
|
||||
public void onDrop(List<WorkspaceItemInfo> oldItems, List<WorkspaceItemInfo> newItems,
|
||||
WorkspaceItemInfo dropped) {
|
||||
int numItems = newParams.size();
|
||||
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<BubbleTextView> moveIn = new ArrayList<>();
|
||||
for (BubbleTextView btv : newParams) {
|
||||
if (!oldParams.contains(btv) && !btv.getTag().equals(dropped)) {
|
||||
moveIn.add(btv);
|
||||
List<WorkspaceItemInfo> moveIn = new ArrayList<>();
|
||||
for (WorkspaceItemInfo newItem : newItems) {
|
||||
if (!oldItems.contains(newItem) && !newItem.equals(dropped)) {
|
||||
moveIn.add(newItem);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < moveIn.size(); ++i) {
|
||||
int prevIndex = newParams.indexOf(moveIn.get(i));
|
||||
int prevIndex = newItems.indexOf(moveIn.get(i));
|
||||
PreviewItemDrawingParams p = params.get(prevIndex);
|
||||
computePreviewItemDrawingParams(prevIndex, numItems, p);
|
||||
updateTransitionParam(p, moveIn.get(i), ENTER_INDEX, newParams.indexOf(moveIn.get(i)),
|
||||
updateTransitionParam(p, moveIn.get(i), ENTER_INDEX, newItems.indexOf(moveIn.get(i)),
|
||||
numItems);
|
||||
}
|
||||
|
||||
// Items that are moving into new positions within the preview.
|
||||
for (int newIndex = 0; newIndex < newParams.size(); ++newIndex) {
|
||||
int oldIndex = oldParams.indexOf(newParams.get(newIndex));
|
||||
for (int newIndex = 0; newIndex < newItems.size(); ++newIndex) {
|
||||
int oldIndex = oldItems.indexOf(newItems.get(newIndex));
|
||||
if (oldIndex >= 0 && newIndex != oldIndex) {
|
||||
PreviewItemDrawingParams p = params.get(newIndex);
|
||||
updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex, numItems);
|
||||
updateTransitionParam(p, newItems.get(newIndex), oldIndex, newIndex, numItems);
|
||||
}
|
||||
}
|
||||
|
||||
// Old preview items that need to be moved out.
|
||||
List<BubbleTextView> moveOut = new ArrayList<>(oldParams);
|
||||
moveOut.removeAll(newParams);
|
||||
List<WorkspaceItemInfo> moveOut = new ArrayList<>(oldItems);
|
||||
moveOut.removeAll(newItems);
|
||||
for (int i = 0; i < moveOut.size(); ++i) {
|
||||
BubbleTextView item = moveOut.get(i);
|
||||
int oldIndex = oldParams.indexOf(item);
|
||||
WorkspaceItemInfo item = moveOut.get(i);
|
||||
int oldIndex = oldItems.indexOf(item);
|
||||
PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
|
||||
updateTransitionParam(p, item, oldIndex, EXIT_INDEX, numItems);
|
||||
params.add(0, p); // We want these items first so that they are on drawn last.
|
||||
|
@ -348,14 +381,9 @@ public class PreviewItemManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
|
||||
private void updateTransitionParam(final PreviewItemDrawingParams p, WorkspaceItemInfo item,
|
||||
int prevIndex, int newIndex, int numItems) {
|
||||
p.drawable = btv.getCompoundDrawables()[1];
|
||||
if (!mIcon.mFolder.isOpen()) {
|
||||
// Set the callback to FolderIcon as it is responsible to drawing the icon. The
|
||||
// callback will be released when the folder is opened.
|
||||
p.drawable.setCallback(mIcon);
|
||||
}
|
||||
setDrawable(p, item);
|
||||
|
||||
FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex, numItems,
|
||||
newIndex, numItems, DROP_IN_ANIMATION_DURATION, null);
|
||||
|
@ -364,4 +392,20 @@ public class PreviewItemManager {
|
|||
}
|
||||
p.anim = anim;
|
||||
}
|
||||
|
||||
private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
|
||||
if (item.hasPromiseIconUi()) {
|
||||
PreloadIconDrawable drawable = mDrawableFactory.newPendingIcon(mContext, item);
|
||||
drawable.setLevel(item.getInstallProgress());
|
||||
p.drawable = drawable;
|
||||
} else {
|
||||
p.drawable = mDrawableFactory.newIcon(mContext, item);
|
||||
}
|
||||
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.
|
||||
p.drawable.setCallback(mIcon);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue