mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 18:58:19 +00:00
Updating ItemInfoMatcher to work with java streams
Adding support for bulk removing items from a folder icon. This fixes workspace item removal when a folder gets replaced to an icon during the delete operation. - Lets say user has a folder with the same app twice. - User disables that app. - Launcher removes all shorcuts of that app However, because we call "replaceFolderWithFinalItem" during this removal, we end up creating a new shortcut that does not get tracked by the removal, so the user is left with an enabled icon of the disabled app. Bug: 162378169 Test: manual test, repo steps in bug Change-Id: Iaf6550894c156b3b5ec2a5aa58bab76a4a28819e
This commit is contained in:
@@ -111,9 +111,11 @@ import com.android.launcher3.widget.WidgetManagerHelper;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The workspace is a wide area with a wallpaper and a finite number of pages.
|
||||
@@ -3002,38 +3004,27 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
* shortcuts are not removed.
|
||||
*/
|
||||
public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
|
||||
for (final CellLayout layoutParent: getWorkspaceAndHotseatCellLayouts()) {
|
||||
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
|
||||
for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
|
||||
ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
|
||||
// Iterate in reverse order as we are removing items
|
||||
for (int i = container.getChildCount() - 1; i >= 0; i--) {
|
||||
View child = container.getChildAt(i);
|
||||
ItemInfo info = (ItemInfo) child.getTag();
|
||||
|
||||
IntSparseArrayMap<View> idToViewMap = new IntSparseArrayMap<>();
|
||||
ArrayList<ItemInfo> items = new ArrayList<>();
|
||||
for (int j = 0; j < layout.getChildCount(); j++) {
|
||||
final View view = layout.getChildAt(j);
|
||||
if (view.getTag() instanceof ItemInfo) {
|
||||
ItemInfo item = (ItemInfo) view.getTag();
|
||||
items.add(item);
|
||||
idToViewMap.put(item.id, view);
|
||||
}
|
||||
}
|
||||
|
||||
for (ItemInfo itemToRemove : matcher.filterItemInfos(items)) {
|
||||
View child = idToViewMap.get(itemToRemove.id);
|
||||
|
||||
if (child != null) {
|
||||
// Note: We can not remove the view directly from CellLayoutChildren as this
|
||||
// does not re-mark the spaces as unoccupied.
|
||||
layoutParent.removeViewInLayout(child);
|
||||
if (matcher.matchesInfo(info)) {
|
||||
layout.removeViewInLayout(child);
|
||||
if (child instanceof DropTarget) {
|
||||
mDragController.removeDropTarget((DropTarget) child);
|
||||
}
|
||||
} else if (itemToRemove.container >= 0) {
|
||||
// The item may belong to a folder.
|
||||
View parent = idToViewMap.get(itemToRemove.container);
|
||||
if (parent instanceof FolderIcon) {
|
||||
FolderInfo folderInfo = (FolderInfo) parent.getTag();
|
||||
folderInfo.remove((WorkspaceItemInfo) itemToRemove, false);
|
||||
if (((FolderIcon) parent).getFolder().isOpen()) {
|
||||
((FolderIcon) parent).getFolder().close(false /* animate */);
|
||||
} else if (child instanceof FolderIcon) {
|
||||
FolderInfo folderInfo = (FolderInfo) info;
|
||||
List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
|
||||
.filter(matcher::matchesInfo)
|
||||
.collect(Collectors.toList());
|
||||
if (!matches.isEmpty()) {
|
||||
folderInfo.removeAll(matches, false);
|
||||
if (((FolderIcon) child).getFolder().isOpen()) {
|
||||
((FolderIcon) child).getFolder().close(false /* animate */);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3143,9 +3134,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
|
||||
public void removeAbandonedPromise(String packageName, UserHandle user) {
|
||||
HashSet<String> packages = new HashSet<>(1);
|
||||
packages.add(packageName);
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packages, user);
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(
|
||||
Collections.singleton(packageName), user);
|
||||
mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
|
||||
removeItemsByMatcher(matcher);
|
||||
}
|
||||
|
||||
@@ -1394,10 +1394,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mItemsInvalidated = true;
|
||||
}
|
||||
|
||||
public void onRemove(WorkspaceItemInfo item) {
|
||||
@Override
|
||||
public void onRemove(List<WorkspaceItemInfo> items) {
|
||||
mItemsInvalidated = true;
|
||||
View v = getViewForInfo(item);
|
||||
mContent.removeItem(v);
|
||||
items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
|
||||
if (mState == STATE_ANIMATING) {
|
||||
mRearrangeOnClose = true;
|
||||
} else {
|
||||
|
||||
@@ -695,9 +695,9 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(WorkspaceItemInfo item) {
|
||||
public void onRemove(List<WorkspaceItemInfo> items) {
|
||||
boolean wasDotted = mDotInfo.hasDot();
|
||||
mDotInfo.subtractDotInfo(mActivity.getDotInfoForItem(item));
|
||||
items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
|
||||
boolean isDotted = mDotInfo.hasDot();
|
||||
updateDotScale(wasDotted, isDotted);
|
||||
setContentDescription(getAccessiblityTitle(mInfo.title));
|
||||
|
||||
@@ -51,6 +51,7 @@ import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* Class for handling model updates.
|
||||
@@ -259,7 +260,9 @@ public class ModelWriter {
|
||||
* Removes all the items from the database matching {@param matcher}.
|
||||
*/
|
||||
public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
|
||||
deleteItemsFromDatabase(matcher.filterItemInfos(mBgDataModel.itemsIdMap));
|
||||
deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
|
||||
.filter(matcher::matchesInfo)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,8 @@ import com.android.launcher3.model.ModelWriter;
|
||||
import com.android.launcher3.util.ContentWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
@@ -137,9 +139,16 @@ public class FolderInfo extends ItemInfo {
|
||||
* @param item
|
||||
*/
|
||||
public void remove(WorkspaceItemInfo item, boolean animate) {
|
||||
contents.remove(item);
|
||||
removeAll(Collections.singletonList(item), animate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all matching app or shortcut. Does not change the DB.
|
||||
*/
|
||||
public void removeAll(List<WorkspaceItemInfo> items, boolean animate) {
|
||||
contents.removeAll(items);
|
||||
for (int i = 0; i < mListeners.size(); i++) {
|
||||
mListeners.get(i).onRemove(item);
|
||||
mListeners.get(i).onRemove(items);
|
||||
}
|
||||
itemsChanged(animate);
|
||||
}
|
||||
@@ -166,9 +175,9 @@ public class FolderInfo extends ItemInfo {
|
||||
}
|
||||
|
||||
public interface FolderListener {
|
||||
public void onAdd(WorkspaceItemInfo item, int rank);
|
||||
public void onRemove(WorkspaceItemInfo item);
|
||||
public void onItemsChanged(boolean animate);
|
||||
void onAdd(WorkspaceItemInfo item, int rank);
|
||||
void onRemove(List<WorkspaceItemInfo> item);
|
||||
void onItemsChanged(boolean animate);
|
||||
}
|
||||
|
||||
public boolean hasOption(int optionFlag) {
|
||||
|
||||
@@ -20,10 +20,7 @@ import android.content.ComponentName;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -37,34 +34,15 @@ public interface ItemInfoMatcher {
|
||||
boolean matches(ItemInfo info, ComponentName cn);
|
||||
|
||||
/**
|
||||
* Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
|
||||
* Returns true if the itemInfo matches this check
|
||||
*/
|
||||
default HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
|
||||
HashSet<ItemInfo> filtered = new HashSet<>();
|
||||
for (ItemInfo i : infos) {
|
||||
if (i instanceof WorkspaceItemInfo) {
|
||||
WorkspaceItemInfo info = (WorkspaceItemInfo) i;
|
||||
ComponentName cn = info.getTargetComponent();
|
||||
if (cn != null && matches(info, cn)) {
|
||||
filtered.add(info);
|
||||
}
|
||||
} else if (i instanceof FolderInfo) {
|
||||
FolderInfo info = (FolderInfo) i;
|
||||
for (WorkspaceItemInfo s : info.contents) {
|
||||
ComponentName cn = s.getTargetComponent();
|
||||
if (cn != null && matches(s, cn)) {
|
||||
filtered.add(s);
|
||||
}
|
||||
}
|
||||
} else if (i instanceof LauncherAppWidgetInfo) {
|
||||
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
|
||||
ComponentName cn = info.providerName;
|
||||
if (cn != null && matches(info, cn)) {
|
||||
filtered.add(info);
|
||||
}
|
||||
}
|
||||
default boolean matchesInfo(ItemInfo info) {
|
||||
if (info != null) {
|
||||
ComponentName cn = info.getTargetComponent();
|
||||
return cn != null && matches(info, cn);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +74,7 @@ public interface ItemInfoMatcher {
|
||||
return (info, cn) -> components.contains(cn) && info.user.equals(user);
|
||||
}
|
||||
|
||||
static ItemInfoMatcher ofPackages(HashSet<String> packageNames, UserHandle user) {
|
||||
static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
|
||||
return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user