Merge "Replacing ItemInfoMatcher with predicate" into tm-dev am: f76524151d am: 8bd54c120a

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/18124001

Change-Id: I57469be18c8b91f396dd964a102bd5ff5019ad89
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sunny Goyal
2022-05-03 20:32:33 +00:00
committed by Automerger Merge Worker
18 changed files with 106 additions and 147 deletions
@@ -55,13 +55,13 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -480,8 +480,8 @@ public class HotseatPredictionController implements DragController.DragListener,
*
* @param matcher filter matching items that have been removed
*/
public void onModelItemsRemoved(ItemInfoMatcher matcher) {
if (mPredictedItems.removeIf(matcher::matchesInfo)) {
public void onModelItemsRemoved(Predicate<ItemInfo> matcher) {
if (mPredictedItems.removeIf(matcher)) {
fillGapsWithPrediction(true);
}
}
@@ -73,6 +73,7 @@ import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Predicate;
/**
* Handles long click on Taskbar items to start a system drag and drop operation.
@@ -439,12 +440,12 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
target = taskbarViewController.getAllAppsButtonView();
} else if (item.container >= 0) {
// Since folders close when the drag starts, target the folder icon instead.
ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
target = taskbarViewController.getFirstIconMatch(matcher);
} else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
// Find first icon with same package/user as the deep shortcut.
ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
Collections.singleton(item.getTargetPackage()), item.user);
target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
}
@@ -36,6 +36,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
/**
* Launcher model Callbacks for rendering taskbar.
@@ -126,16 +127,16 @@ public class TaskbarModelCallbacks implements
}
@Override
public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
if (handleItemsRemoved(matcher)) {
commitItemsToUI();
}
}
private boolean handleItemsRemoved(ItemInfoMatcher matcher) {
private boolean handleItemsRemoved(Predicate<ItemInfo> matcher) {
boolean modified = false;
for (int i = mHotseatItems.size() - 1; i >= 0; i--) {
if (matcher.matchesInfo(mHotseatItems.valueAt(i))) {
if (matcher.test(mHotseatItems.valueAt(i))) {
modified = true;
mHotseatItems.removeAt(i);
}
@@ -41,12 +41,13 @@ import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.AllAppsButton;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
import java.util.function.Predicate;
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
@@ -424,8 +425,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
* Finds the first icon to match one of the given matchers, from highest to lowest priority.
* @return The first match, or All Apps button if no match was found.
*/
public View getFirstMatch(ItemInfoMatcher... matchers) {
for (ItemInfoMatcher matcher : matchers) {
public View getFirstMatch(Predicate<ItemInfo>... matchers) {
for (Predicate<ItemInfo> matcher : matchers) {
for (int i = 0; i < getChildCount(); i++) {
View item = getChildAt(i);
if (!(item.getTag() instanceof ItemInfo)) {
@@ -433,7 +434,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
continue;
}
ItemInfo info = (ItemInfo) item.getTag();
if (matcher.matchesInfo(info)) {
if (matcher.test(info)) {
return item;
}
}
@@ -47,6 +47,7 @@ import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.AnimatedFloat;
import java.io.PrintWriter;
import java.util.function.Predicate;
/**
* Handles properties/data collection, then passes the results to TaskbarView to render.
@@ -317,8 +318,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
* 2) FolderIcon of the Folder containing the given icon
* 3) All Apps button
*/
public View getFirstIconMatch(ItemInfoMatcher matcher) {
ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
return mTaskbarView.getFirstMatch(matcher, folderMatcher);
}
@@ -70,7 +70,6 @@ import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchT
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.NavigationMode;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -86,6 +85,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -245,7 +245,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
}
@Override
public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
super.bindWorkspaceComponentsRemoved(matcher);
mHotseatPredictionController.onModelItemsRemoved(matcher);
}
+7 -8
View File
@@ -182,7 +182,6 @@ import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -2739,9 +2738,9 @@ public class Launcher extends StatefulActivity<LauncherState>
*/
public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user,
boolean supportsAllAppsState) {
final ItemInfoMatcher preferredItem = (info, cn) ->
final Predicate<ItemInfo> preferredItem = info ->
info != null && info.id == preferredItemId;
final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
final Predicate<ItemInfo> packageAndUserAndApp = info ->
info != null
&& info.itemType == ITEM_TYPE_APPLICATION
&& info.user.equals(user)
@@ -2770,8 +2769,8 @@ public class Launcher extends StatefulActivity<LauncherState>
* @param operators List of operators, in order starting from best matching operator.
*/
private static View getFirstMatch(Iterable<ViewGroup> containers,
final ItemInfoMatcher... operators) {
for (ItemInfoMatcher operator : operators) {
final Predicate<ItemInfo>... operators) {
for (Predicate<ItemInfo> operator : operators) {
for (ViewGroup container : containers) {
View match = mapOverViewGroup(container, operator);
if (match != null) {
@@ -2786,11 +2785,11 @@ public class Launcher extends StatefulActivity<LauncherState>
* Returns the first view matching the operator in the given ViewGroups, or null if none.
* Forward iteration matters.
*/
private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
private static View mapOverViewGroup(ViewGroup container, Predicate<ItemInfo> op) {
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
if (op.matchesInfo((ItemInfo) item.getTag())) {
if (op.test((ItemInfo) item.getTag())) {
return item;
}
}
@@ -2887,7 +2886,7 @@ public class Launcher extends StatefulActivity<LauncherState>
* package-removal should clear all items by package name.
*/
@Override
public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
mWorkspace.removeItemsByMatcher(matcher);
mDragController.onAppsRemoved(matcher);
PopupContainerWithArrow.dismissInvalidPopup(this);
+4 -5
View File
@@ -102,7 +102,6 @@ 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.LauncherBindableItemsContainer;
import com.android.launcher3.util.OverlayEdgeEffect;
import com.android.launcher3.util.PackageUserKey;
@@ -3235,7 +3234,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
* as a part of an update, this is called to ensure that other widgets and application
* shortcuts are not removed.
*/
public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
public void removeItemsByMatcher(final Predicate<ItemInfo> matcher) {
for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
// Iterate in reverse order as we are removing items
@@ -3243,7 +3242,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
View child = container.getChildAt(i);
ItemInfo info = (ItemInfo) child.getTag();
if (matcher.matchesInfo(info)) {
if (matcher.test(info)) {
layout.removeViewInLayout(child);
if (child instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) child);
@@ -3251,7 +3250,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
} else if (child instanceof FolderIcon) {
FolderInfo folderInfo = (FolderInfo) info;
List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
.filter(matcher::matchesInfo)
.filter(matcher)
.collect(Collectors.toList());
if (!matches.isEmpty()) {
folderInfo.removeAll(matches, false);
@@ -3330,7 +3329,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
*
* @param matcher the matcher generated by the caller.
*/
public void persistRemoveItemsByMatcher(ItemInfoMatcher matcher) {
public void persistRemoveItemsByMatcher(Predicate<ItemInfo> matcher) {
mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
removeItemsByMatcher(matcher);
}
@@ -21,17 +21,18 @@ import android.content.Context;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.LabelComparator;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* The alphabetically sorted list of applications.
@@ -82,7 +83,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
private AppInfoComparator mAppNameComparator;
private final int mNumAppsPerRowAllApps;
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
private Predicate<ItemInfo> mItemFilter;
public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
WorkAdapterProvider adapterProvider) {
@@ -94,7 +95,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
mAllAppsStore.addUpdateListener(this);
}
public void updateItemFilter(ItemInfoMatcher itemFilter) {
public void updateItemFilter(Predicate<ItemInfo> itemFilter) {
this.mItemFilter = itemFilter;
onAppsUpdated();
}
@@ -200,13 +201,11 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
// Sort the list of apps
mApps.clear();
for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
Stream<AppInfo> appSteam = Stream.of(mAllAppsStore.getApps());
if (!hasFilter() && mItemFilter != null) {
appSteam = appSteam.filter(mItemFilter);
}
Collections.sort(mApps, mAppNameComparator);
appSteam = appSteam.sorted(mAppNameComparator);
// As a special case for some languages (currently only Simplified Chinese), we may need to
// coalesce sections
@@ -215,27 +214,16 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
if (localeRequiresSectionSorting) {
// Compute the section headers. We use a TreeMap with the section name comparator to
// ensure that the sections are ordered when we iterate over it later
TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
for (AppInfo info : mApps) {
// Add the section to the cache
String sectionName = info.sectionName;
// Add it to the mapping
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
if (sectionApps == null) {
sectionApps = new ArrayList<>();
sectionMap.put(sectionName, sectionApps);
}
sectionApps.add(info);
}
// Add each of the section apps to the list in order
mApps.clear();
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
mApps.addAll(entry.getValue());
}
appSteam = appSteam.collect(Collectors.groupingBy(
info -> info.sectionName,
() -> new TreeMap<>(new LabelComparator()),
Collectors.toCollection(ArrayList::new)))
.values()
.stream()
.flatMap(ArrayList::stream);
}
appSteam.forEachOrdered(mApps::add);
// Recompose the set of adapter items from the current set of apps
if (mSearchResults.isEmpty()) {
updateAdapterItems();
@@ -58,7 +58,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -69,6 +69,8 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Base all apps view container.
@@ -91,7 +93,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
/** Context of an activity or window that is inflating this container. */
protected final T mActivityContext;
protected final List<AdapterHolder> mAH;
protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
Process.myUserHandle());
private final SearchAdapterProvider<?> mMainAdapterProvider;
private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -229,17 +231,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
}
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
if (mWorkManager.getMatcher().matches(app, null)) {
hasWorkApps = true;
break;
}
}
mHasWorkApps = hasWorkApps;
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
rebindAdapters();
if (hasWorkApps) {
if (mHasWorkApps) {
mWorkManager.reset();
}
}
@@ -731,7 +726,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
mLayoutManager = adapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
@@ -27,7 +27,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.ViewGroup;
import android.view.WindowInsets;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -35,11 +34,12 @@ import androidx.annotation.RequiresApi;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Predicate;
/**
* Companion class for {@link BaseAllAppsContainerView} to manage work tab and personal tab
@@ -70,7 +70,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
private final BaseAllAppsContainerView<?> mAllApps;
private final WorkAdapterProvider mAdapterProvider;
private final ItemInfoMatcher mMatcher;
private final Predicate<ItemInfo> mMatcher;
private WorkModeSwitch mWorkModeSwitch;
@@ -176,7 +176,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
return mAdapterProvider;
}
public ItemInfoMatcher getMatcher() {
public Predicate<ItemInfo> getMatcher() {
return mMatcher;
}
@@ -18,7 +18,6 @@ package com.android.launcher3.dragndrop;
import static com.android.launcher3.Utilities.ATLEAST_Q;
import android.content.ComponentName;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -36,12 +35,12 @@ import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;
/**
* Class for initiating a drag within a view or across multiple views.
@@ -275,15 +274,12 @@ public abstract class DragController<T extends ActivityContext>
protected abstract void exitDrag();
public void onAppsRemoved(ItemInfoMatcher matcher) {
public void onAppsRemoved(Predicate<ItemInfo> matcher) {
// Cancel the current drag if we are removing an app that we are dragging
if (mDragObject != null) {
ItemInfo dragInfo = mDragObject.dragInfo;
if (dragInfo instanceof WorkspaceItemInfo) {
ComponentName cn = dragInfo.getTargetComponent();
if (cn != null && matcher.matches(dragInfo, cn)) {
cancelDrag();
}
if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
cancelDrag();
}
}
}
@@ -36,9 +36,9 @@ import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SafeCloseable;
@@ -47,6 +47,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -257,11 +258,11 @@ public class AllAppsList {
/**
* Updates the disabled flags of apps matching {@param matcher} based on {@param op}.
*/
public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) {
public void updateDisabledFlags(Predicate<ItemInfo> matcher, FlagOp op) {
final List<AppInfo> data = this.data;
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
if (matcher.matches(info, info.componentName)) {
if (matcher.test(info)) {
info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags);
mDataChanged = true;
}
@@ -27,7 +27,6 @@ import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import java.util.ArrayList;
@@ -35,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -128,7 +128,7 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask {
scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
}
public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher) {
getModelWriter().deleteItemsFromDatabase(matcher);
// Call the components-removed callback
@@ -50,7 +50,6 @@ import com.android.launcher3.util.ComponentKey;
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.RunnableList;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -66,6 +65,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -495,7 +495,7 @@ public class BgDataModel {
default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
default void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { }
default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
@@ -53,6 +53,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -278,10 +279,9 @@ public class ModelWriter {
/**
* Removes all the items from the database matching {@param matcher}.
*/
public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
public void deleteItemsFromDatabase(Predicate<ItemInfo> matcher) {
deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
.filter(matcher::matchesInfo)
.collect(Collectors.toList()));
.filter(matcher).collect(Collectors.toList()));
}
/**
@@ -57,6 +57,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
/**
* Handles updates due to changes in package manager (app installed/updated/removed)
@@ -95,7 +96,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
final int N = packages.length;
final FlagOp flagOp;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
final Predicate<ItemInfo> matcher = mOp == OP_USER_AVAILABILITY_CHANGE
? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
: ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
@@ -206,7 +207,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.matches(si, cn)) {
if (cn != null && matcher.test(si)) {
String packageName = cn.getPackageName();
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
@@ -336,7 +337,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
Predicate<ItemInfo> removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch);
@@ -19,6 +19,8 @@ package com.android.launcher3.util;
import android.content.ComponentName;
import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -27,90 +29,64 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
/**
* A utility class to check for {@link ItemInfo}
*/
public interface ItemInfoMatcher {
public abstract class ItemInfoMatcher {
/**
* Empty component used for match testing
*/
ComponentName EMPTY_COMPONENT = new ComponentName("", "");
private static final ComponentName EMPTY_COMPONENT = new ComponentName("", "");
boolean matches(ItemInfo info, ComponentName cn);
/**
* Returns true if the itemInfo matches this check
*/
default boolean matchesInfo(ItemInfo info) {
if (info != null) {
ComponentName cn = info.getTargetComponent();
return matches(info, cn != null ? cn : EMPTY_COMPONENT);
} else {
return false;
}
public static Predicate<ItemInfo> ofUser(UserHandle user) {
return info -> info != null && info.user.equals(user);
}
/**
* Returns a new matcher with returns true if either this or {@param matcher} returns true.
*/
default ItemInfoMatcher or(ItemInfoMatcher matcher) {
return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
public static Predicate<ItemInfo> ofComponents(
HashSet<ComponentName> components, UserHandle user) {
return info -> info != null && info.user.equals(user)
&& components.contains(getNonNullComponent(info));
}
/**
* Returns a new matcher with returns true if both this and {@param matcher} returns true.
*/
default ItemInfoMatcher and(ItemInfoMatcher matcher) {
return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
public static Predicate<ItemInfo> ofPackages(Set<String> packageNames, UserHandle user) {
return info -> info != null && info.user.equals(user)
&& packageNames.contains(getNonNullComponent(info).getPackageName());
}
/**
* Returns a new matcher with returns the opposite value of this.
*/
default ItemInfoMatcher negate() {
return (info, cn) -> !matches(info, cn);
}
static ItemInfoMatcher ofUser(UserHandle user) {
return (info, cn) -> info.user.equals(user);
}
static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
return (info, cn) -> components.contains(cn) && info.user.equals(user);
}
static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
public static Predicate<ItemInfo> ofShortcutKeys(Set<ShortcutKey> keys) {
return info -> info != null && info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& keys.contains(ShortcutKey.fromItemInfo(info));
}
/**
* Returns a matcher for items within folders.
*/
static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
.anyMatch(childOperator::matchesInfo);
public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
.anyMatch(childOperator);
}
/**
* Returns a matcher for items with provided ids
*/
static ItemInfoMatcher ofItemIds(IntSet ids) {
return (info, cn) -> ids.contains(info.id);
public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
return info -> info != null && ids.contains(info.id);
}
/**
* Returns a matcher for items with provided items
*/
static ItemInfoMatcher ofItems(Collection<? extends ItemInfo> items) {
public static Predicate<ItemInfo> ofItems(Collection<? extends ItemInfo> items) {
IntSet ids = new IntSet();
items.forEach(item -> ids.add(item.id));
return ofItemIds(ids);
}
private static ComponentName getNonNullComponent(@NonNull ItemInfo info) {
ComponentName cn = info.getTargetComponent();
return cn != null ? cn : EMPTY_COMPONENT;
}
}