Merge "Creating a common method to iterate over all model items." into ub-launcher3-master

This commit is contained in:
TreeHugger Robot
2020-07-10 19:18:48 +00:00
committed by Android (Google) Code Review
9 changed files with 170 additions and 167 deletions
+4 -4
View File
@@ -58,7 +58,7 @@ import com.android.launcher3.pm.InstallSessionTracker;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageUserKey;
@@ -410,7 +410,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
enqueueModelUpdateTask(new BaseModelUpdateTask() {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
final IntSparseArrayMap<Boolean> removedIds = new IntSparseArrayMap<>();
final IntSet removedIds = new IntSet();
synchronized (dataModel) {
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo
@@ -418,13 +418,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
&& user.equals(info.user)
&& info.getIntent() != null
&& TextUtils.equals(packageName, info.getIntent().getPackage())) {
removedIds.put(info.id, true /* remove */);
removedIds.add(info.id);
}
}
}
if (!removedIds.isEmpty()) {
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false));
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds));
}
}
});
@@ -83,7 +83,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
protected final BaseDraggingActivity mLauncher;
protected final AdapterHolder[] mAH;
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
private final ItemInfoMatcher mWorkMatcher = mPersonalMatcher.negate();
private final AllAppsStore mAllAppsStore = new AllAppsStore();
private final Paint mNavBarScrimPaint;
@@ -56,6 +56,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -348,6 +349,19 @@ public class BgDataModel {
}
}
/**
* Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted
* items and dynamic/predicted items for the provided {@code userHandle}.
* Note the call is not synchronized over the model, that should be handled by the called.
*/
public void forAllWorkspaceItemInfos(UserHandle userHandle, Consumer<WorkspaceItemInfo> op) {
for (ItemInfo info : itemsIdMap) {
if (info instanceof WorkspaceItemInfo && userHandle.equals(info.user)) {
op.accept((WorkspaceItemInfo) info);
}
}
}
public interface Callbacks {
// If the launcher has permission to access deep shortcuts.
int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0;
@@ -21,7 +21,6 @@ import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import java.util.ArrayList;
@@ -48,23 +47,18 @@ public class CacheDataUpdatedTask extends BaseModelUpdateTask {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
IconCache iconCache = app.getIconCache();
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
synchronized (dataModel) {
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
ComponentName cn = si.getTargetComponent();
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
updatedShortcuts.add(si);
}
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
ComponentName cn = si.getTargetComponent();
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
updatedShortcuts.add(si);
}
}
});
apps.updateIconsAndLabels(mPackages, mUser);
}
bindUpdatedWorkspaceItems(updatedShortcuts);
@@ -20,8 +20,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
@@ -70,21 +68,18 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
synchronized (dataModel) {
final HashSet<ItemInfo> updates = new HashSet<>();
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo) {
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
ComponentName cn = si.getTargetComponent();
if (si.hasPromiseIconUi() && (cn != null)
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
si.setInstallProgress(mInstallInfo.progress);
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
// Mark this info as broken.
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
}
updates.add(si);
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
ComponentName cn = si.getTargetComponent();
if (si.hasPromiseIconUi() && (cn != null)
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
si.setInstallProgress(mInstallInfo.progress);
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
// Mark this info as broken.
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
}
updates.add(si);
}
}
});
for (LauncherAppWidgetInfo widget : dataModel.appWidgets) {
if (widget.providerName.getPackageName().equals(mInstallInfo.packageName)) {
@@ -94,12 +89,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
}
if (!updates.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
callbacks.bindRestoreItemsChange(updates);
}
});
scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
}
}
}
@@ -45,7 +45,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -92,9 +92,11 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
final String[] packages = mPackages;
final int N = packages.length;
FlagOp flagOp = FlagOp.NO_OP;
final FlagOp flagOp;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
final ItemInfoMatcher 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<>();
switch (mOp) {
@@ -158,19 +160,22 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
flagOp = ums.isUserQuiet(mUser)
? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
: FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER);
// We want to update all packages for this user.
matcher = ItemInfoMatcher.ofUser(mUser);
appsList.updateDisabledFlags(matcher, flagOp);
// We are not synchronizing here, as int operations are atomic
appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
break;
}
default:
flagOp = FlagOp.NO_OP;
break;
}
bindApplicationsIfNeeded();
final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
final IntSet removedShortcuts = new IntSet();
// Shortcuts to keep even if the corresponding app was removed
final IntSet forceKeepShortcuts = new IntSet();
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
@@ -180,118 +185,118 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
// For system apps, package manager send OP_UPDATE when an app is enabled.
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
synchronized (dataModel) {
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
boolean infoUpdated = false;
boolean shortcutUpdated = false;
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
// Update shortcuts which use iconResource.
if ((si.iconResource != null)
&& packageSet.contains(si.iconResource.packageName)) {
LauncherIcons li = LauncherIcons.obtain(context);
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
li.recycle();
if (iconInfo != null) {
si.bitmap = iconInfo;
infoUpdated = true;
boolean infoUpdated = false;
boolean shortcutUpdated = false;
// Update shortcuts which use iconResource.
if ((si.iconResource != null)
&& packageSet.contains(si.iconResource.packageName)) {
LauncherIcons li = LauncherIcons.obtain(context);
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
li.recycle();
if (iconInfo != null) {
si.bitmap = iconInfo;
infoUpdated = true;
}
}
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.matches(si, cn)) {
String packageName = cn.getPackageName();
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
forceKeepShortcuts.add(si.id);
if (mOp == OP_REMOVE) {
return;
}
}
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.matches(si, cn)) {
String packageName = cn.getPackageName();
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
removedShortcuts.put(si.id, false);
if (mOp == OP_REMOVE) {
continue;
}
}
if (si.isPromise() && isNewApkAvailable) {
boolean isTargetValid = true;
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
List<ShortcutInfo> shortcut =
new ShortcutRequest(context, mUser)
.forPackage(cn.getPackageName(),
si.getDeepShortcutId())
.query(ShortcutRequest.PINNED);
if (shortcut.isEmpty()) {
isTargetValid = false;
} else {
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
infoUpdated = true;
}
} else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
isTargetValid = context.getSystemService(LauncherApps.class)
.isActivityEnabled(cn, mUser);
}
if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
} else if (si.hasPromiseIconUi()) {
removedShortcuts.put(si.id, true);
continue;
}
} else if (!isTargetValid) {
removedShortcuts.put(si.id, true);
FileLog.e(TAG, "Restored shortcut no longer valid "
+ si.getIntent());
continue;
if (si.isPromise() && isNewApkAvailable) {
boolean isTargetValid = true;
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
List<ShortcutInfo> shortcut =
new ShortcutRequest(context, mUser)
.forPackage(cn.getPackageName(),
si.getDeepShortcutId())
.query(ShortcutRequest.PINNED);
if (shortcut.isEmpty()) {
isTargetValid = false;
} else {
si.status = WorkspaceItemInfo.DEFAULT;
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
infoUpdated = true;
}
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
} else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
isTargetValid = context.getSystemService(LauncherApps.class)
.isActivityEnabled(cn, mUser);
}
if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
} else if (si.hasPromiseIconUi()) {
removedShortcuts.add(si.id);
return;
}
}
if (isNewApkAvailable &&
si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
} else if (!isTargetValid) {
removedShortcuts.add(si.id);
FileLog.e(TAG, "Restored shortcut no longer valid "
+ si.getIntent());
return;
} else {
si.status = WorkspaceItemInfo.DEFAULT;
infoUpdated = true;
}
int oldRuntimeFlags = si.runtimeStatusFlags;
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
if (si.runtimeStatusFlags != oldRuntimeFlags) {
shortcutUpdated = true;
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
}
}
if (infoUpdated || shortcutUpdated) {
updatedWorkspaceItems.add(si);
if (isNewApkAvailable
&& si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
infoUpdated = true;
}
if (infoUpdated) {
getModelWriter().updateItemInDatabase(si);
}
} else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) {
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
if (mUser.equals(widgetInfo.user)
&& widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
&& packageSet.contains(widgetInfo.providerName.getPackageName())) {
widgetInfo.restoreStatus &=
~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY &
~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
// adding this flag ensures that launcher shows 'click to setup'
// if the widget has a config activity. In case there is no config
// activity, it will be marked as 'restored' during bind.
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
widgets.add(widgetInfo);
getModelWriter().updateItemInDatabase(widgetInfo);
int oldRuntimeFlags = si.runtimeStatusFlags;
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
if (si.runtimeStatusFlags != oldRuntimeFlags) {
shortcutUpdated = true;
}
}
if (infoUpdated || shortcutUpdated) {
updatedWorkspaceItems.add(si);
}
if (infoUpdated && si.id != ItemInfo.NO_ID) {
getModelWriter().updateItemInDatabase(si);
}
});
for (LauncherAppWidgetInfo widgetInfo : dataModel.appWidgets) {
if (mUser.equals(widgetInfo.user)
&& widgetInfo.hasRestoreFlag(
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
&& packageSet.contains(widgetInfo.providerName.getPackageName())) {
widgetInfo.restoreStatus &=
~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY
& ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
// adding this flag ensures that launcher shows 'click to setup'
// if the widget has a config activity. In case there is no config
// activity, it will be marked as 'restored' during bind.
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
widgets.add(widgetInfo);
getModelWriter().updateItemInDatabase(widgetInfo);
}
}
}
bindUpdatedWorkspaceItems(updatedWorkspaceItems);
if (!removedShortcuts.isEmpty()) {
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts));
}
if (!widgets.isEmpty()) {
@@ -319,7 +324,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
@@ -21,7 +21,6 @@ import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
@@ -58,14 +57,14 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
HashSet<String> allIds = new HashSet<>();
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
if (mPackageName.equals(si.getIntent().getPackage()) && si.user.equals(mUser)) {
synchronized (dataModel) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& mPackageName.equals(si.getIntent().getPackage())) {
keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
allIds.add(si.getDeepShortcutId());
}
}
});
}
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
@@ -23,7 +23,6 @@ import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
@@ -73,27 +72,27 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
HashSet<ShortcutKey> removedKeys = new HashSet<>();
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& mUser.equals(itemInfo.user)) {
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
if (mIsUserUnlocked) {
ShortcutKey key = ShortcutKey.fromItemInfo(si);
ShortcutInfo shortcut = pinnedShortcuts.get(key);
// We couldn't verify the shortcut during loader. If its no longer available
// (probably due to clear data), delete the workspace item as well
if (shortcut == null) {
removedKeys.add(key);
continue;
synchronized (dataModel) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
if (mIsUserUnlocked) {
ShortcutKey key = ShortcutKey.fromItemInfo(si);
ShortcutInfo shortcut = pinnedShortcuts.get(key);
// We couldn't verify the shortcut during loader. If its no longer available
// (probably due to clear data), delete the workspace item as well
if (shortcut == null) {
removedKeys.add(key);
return;
}
si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
si.updateFromDeepShortcutInfo(shortcut, context);
app.getIconCache().getShortcutIcon(si, shortcut);
} else {
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
}
si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
si.updateFromDeepShortcutInfo(shortcut, context);
app.getIconCache().getShortcutIcon(si, shortcut);
} else {
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
updatedWorkspaceItemInfos.add(si);
}
updatedWorkspaceItemInfos.add(si);
}
});
}
bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
if (!removedKeys.isEmpty()) {
@@ -81,11 +81,10 @@ public interface ItemInfoMatcher {
}
/**
* Returns a new matcher which returns the opposite boolean value of the provided
* {@param matcher}.
* Returns a new matcher with returns the opposite value of this.
*/
static ItemInfoMatcher not(ItemInfoMatcher matcher) {
return (info, cn) -> !matcher.matches(info, cn);
default ItemInfoMatcher negate() {
return (info, cn) -> !matches(info, cn);
}
static ItemInfoMatcher ofUser(UserHandle user) {
@@ -105,7 +104,10 @@ public interface ItemInfoMatcher {
keys.contains(ShortcutKey.fromItemInfo(info));
}
static ItemInfoMatcher ofItemIds(IntSparseArrayMap<Boolean> ids, Boolean matchDefault) {
return (info, cn) -> ids.get(info.id, matchDefault);
/**
* Returns a matcher for items with provided ids
*/
static ItemInfoMatcher ofItemIds(IntSet ids) {
return (info, cn) -> ids.contains(info.id);
}
}