use of com.android.launcher3.util.IntSparseArrayMap in project android_packages_apps_Trebuchet by LineageOS.
the class Workspace method removeItemsByMatcher.
/**
* Removes items that match the {@param matcher}. When applications are removed
* 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) {
for (final CellLayout layoutParent : getWorkspaceAndHotseatCellLayouts()) {
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
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 (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);
}
}
}
}
}
// Strip all the empty screens
stripEmptyScreens();
}
use of com.android.launcher3.util.IntSparseArrayMap in project android_packages_apps_Trebuchet by LineageOS.
the class ImportDataTask method importWorkspaceItems.
/**
* 1) Imports all the workspace entries from the source provider.
* 2) For home screen entries, maps the screen id based on {@param screenIdMap}
* 3) In the end fills any holes in hotseat with items from default hotseat layout.
*/
private void importWorkspaceItems() throws Exception {
String profileId = Long.toString(UserCache.INSTANCE.get(mContext).getSerialNumberForUser(Process.myUserHandle()));
boolean createEmptyRowOnFirstScreen;
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null, // get items on the first row of the first screen (min screen id)
"profileId = ? AND container = -100 AND cellY = 0 AND screen = " + "(SELECT MIN(screen) FROM favorites WHERE container = -100)", new String[] { profileId }, null)) {
// First row of first screen is not empty
createEmptyRowOnFirstScreen = c.moveToNext();
}
} else {
createEmptyRowOnFirstScreen = false;
}
ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE);
// Set of package names present in hotseat
final HashSet<String> hotseatTargetApps = new HashSet<>();
int maxId = 0;
// Number of imported items on workspace and hotseat
int totalItemsOnWorkspace = 0;
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null, // Only migrate the primary user
Favorites.PROFILE_ID + " = ?", new String[] { profileId }, // before the corresponding items.
Favorites.CONTAINER + " , " + Favorites.SCREEN)) {
// various columns we expect to exist.
final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
final int titleIndex = c.getColumnIndexOrThrow(Favorites.TITLE);
final int containerIndex = c.getColumnIndexOrThrow(Favorites.CONTAINER);
final int itemTypeIndex = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE);
final int widgetProviderIndex = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
final int screenIndex = c.getColumnIndexOrThrow(Favorites.SCREEN);
final int cellXIndex = c.getColumnIndexOrThrow(Favorites.CELLX);
final int cellYIndex = c.getColumnIndexOrThrow(Favorites.CELLY);
final int spanXIndex = c.getColumnIndexOrThrow(Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(Favorites.SPANY);
final int rankIndex = c.getColumnIndexOrThrow(Favorites.RANK);
final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
final int iconPackageIndex = c.getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
final int iconResourceIndex = c.getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
SparseBooleanArray mValidFolders = new SparseBooleanArray();
ContentValues values = new ContentValues();
Integer firstScreenId = null;
while (c.moveToNext()) {
values.clear();
int id = c.getInt(idIndex);
maxId = Math.max(maxId, id);
int type = c.getInt(itemTypeIndex);
int container = c.getInt(containerIndex);
int screen = c.getInt(screenIndex);
int cellX = c.getInt(cellXIndex);
int cellY = c.getInt(cellYIndex);
int spanX = c.getInt(spanXIndex);
int spanY = c.getInt(spanYIndex);
switch(container) {
case Favorites.CONTAINER_DESKTOP:
{
if (screen < Workspace.FIRST_SCREEN_ID) {
FileLog.d(TAG, String.format("Skipping item %d, type %d not on a valid screen %d", id, type, screen));
continue;
}
if (firstScreenId == null) {
firstScreenId = screen;
}
// Reset the screen to 0-index value
if (createEmptyRowOnFirstScreen && firstScreenId.equals(screen)) {
// Shift items by 1.
cellY++;
// Change the screen id to first screen
screen = Workspace.FIRST_SCREEN_ID;
}
mMaxGridSizeX = Math.max(mMaxGridSizeX, cellX + spanX);
mMaxGridSizeY = Math.max(mMaxGridSizeY, cellY + spanY);
break;
}
case Favorites.CONTAINER_HOTSEAT:
{
mHotseatSize = Math.max(mHotseatSize, screen + 1);
break;
}
default:
if (!mValidFolders.get(container)) {
FileLog.d(TAG, String.format("Skipping item %d, type %d not in a valid folder %d", id, type, container));
continue;
}
}
Intent intent = null;
switch(type) {
case Favorites.ITEM_TYPE_FOLDER:
{
mValidFolders.put(id, true);
// Use a empty intent to indicate a folder.
intent = new Intent();
break;
}
case Favorites.ITEM_TYPE_APPWIDGET:
{
values.put(Favorites.RESTORED, LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
values.put(Favorites.APPWIDGET_PROVIDER, c.getString(widgetProviderIndex));
break;
}
case Favorites.ITEM_TYPE_SHORTCUT:
case Favorites.ITEM_TYPE_APPLICATION:
{
intent = Intent.parseUri(c.getString(intentIndex), 0);
if (PackageManagerHelper.isLauncherAppTarget(intent)) {
type = Favorites.ITEM_TYPE_APPLICATION;
} else {
values.put(Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
values.put(Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
}
values.put(Favorites.ICON, c.getBlob(iconIndex));
values.put(Favorites.INTENT, intent.toUri(0));
values.put(Favorites.RANK, c.getInt(rankIndex));
values.put(Favorites.RESTORED, 1);
break;
}
default:
FileLog.d(TAG, String.format("Skipping item %d, not a valid type %d", id, type));
continue;
}
if (container == Favorites.CONTAINER_HOTSEAT) {
if (intent == null) {
FileLog.d(TAG, String.format("Skipping item %d, null intent on hotseat", id));
continue;
}
if (intent.getComponent() != null) {
intent.setPackage(intent.getComponent().getPackageName());
}
hotseatTargetApps.add(getPackage(intent));
}
values.put(Favorites._ID, id);
values.put(Favorites.ITEM_TYPE, type);
values.put(Favorites.CONTAINER, container);
values.put(Favorites.SCREEN, screen);
values.put(Favorites.CELLX, cellX);
values.put(Favorites.CELLY, cellY);
values.put(Favorites.SPANX, spanX);
values.put(Favorites.SPANY, spanY);
values.put(Favorites.TITLE, c.getString(titleIndex));
insertOperations.add(ContentProviderOperation.newInsert(Favorites.CONTENT_URI).withValues(values).build());
if (container < 0) {
totalItemsOnWorkspace++;
}
if (insertOperations.size() >= BATCH_INSERT_SIZE) {
mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
insertOperations.clear();
}
}
}
FileLog.d(TAG, totalItemsOnWorkspace + " items imported from external source");
if (totalItemsOnWorkspace < MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION) {
throw new Exception("Insufficient data");
}
if (!insertOperations.isEmpty()) {
mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
insertOperations.clear();
}
IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
if (hotseatItems.size() < myHotseatCount) {
// Insufficient hotseat items. Add a few more.
HotseatParserCallback parserCallback = new HotseatParserCallback(hotseatTargetApps, hotseatItems, insertOperations, maxId + 1, myHotseatCount);
new HotseatLayoutParser(mContext, parserCallback).loadLayout(null, new IntArray());
mHotseatSize = hotseatItems.keyAt(hotseatItems.size() - 1) + 1;
if (!insertOperations.isEmpty()) {
mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, insertOperations);
}
}
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class AddWorkspaceItemsTaskTest method initData.
@Before
public void initData() throws Exception {
existingScreens = new IntArray();
screenOccupancy = new IntSparseArrayMap<>();
newScreens = new IntArray();
idp.numColumns = 5;
idp.numRows = 5;
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class Workspace method removeItemsByMatcher.
/**
* Removes items that match the {@param matcher}. When applications are removed
* 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) {
for (final CellLayout layoutParent : getWorkspaceAndHotseatCellLayouts()) {
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
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 (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);
}
}
}
}
}
// Strip all the empty screens
stripEmptyScreens();
}
use of com.android.launcher3.util.IntSparseArrayMap in project Neo-Launcher by NeoApplications.
the class PackageUpdatedTask method execute.
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.APP_NOT_DISABLED, "PackageUpdatedTask: " + mOp + ", " + Arrays.toString(mPackages));
}
final Context context = app.getContext();
final IconCache iconCache = app.getIconCache();
final String[] packages = mPackages;
final int N = packages.length;
FlagOp flagOp = FlagOp.NO_OP;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
switch(mOp) {
case OP_ADD:
{
for (int i = 0; i < N; i++) {
if (DEBUG)
Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
iconCache.updateIconsForPkg(packages[i], mUser);
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
appsList.removePackage(packages[i], mUser);
}
appsList.addPackage(context, packages[i], mUser);
OmegaPreferences prefs = Utilities.getOmegaPrefs(context);
// Automatically add homescreen icon for work profile apps for below O device.
if (Utilities.ATLEAST_OREO && prefs.getAutoAddInstalled() && !OmegaUtilsKt.workspaceContains(dataModel, packages[i])) {
SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
} else if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) {
SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
}
}
flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
}
case OP_UPDATE:
try (SafeCloseable t = appsList.trackRemoves(a -> removedComponents.add(a.componentName))) {
for (String aPackage : packages) {
if (DEBUG)
Log.d(TAG, "mAllAppsList.updatePackage " + aPackage);
iconCache.updateIconsForPkg(aPackage, mUser);
appsList.updatePackage(context, aPackage, mUser);
app.getWidgetCache().removePackage(aPackage, mUser);
}
}
// Since package was just updated, the target must be available now.
flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
case OP_REMOVE:
{
for (String aPackage : packages) {
FileLog.d(TAG, "Removing app icon" + aPackage);
iconCache.removeIconsForPkg(aPackage, mUser);
}
// Fall through
}
case OP_UNAVAILABLE:
for (int i = 0; i < N; i++) {
if (DEBUG)
Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
appsList.removePackage(packages[i], mUser);
app.getWidgetCache().removePackage(packages[i], mUser);
}
flagOp = FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
case OP_SUSPEND:
case OP_UNSUSPEND:
flagOp = mOp == OP_SUSPEND ? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED) : FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED);
if (DEBUG)
Log.d(TAG, "mAllAppsList.(un)suspend " + N);
appsList.updateDisabledFlags(matcher, flagOp);
break;
case OP_USER_AVAILABILITY_CHANGE:
flagOp = UserManagerCompat.getInstance(context).isQuietModeEnabled(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);
break;
case OP_RELOAD:
if (DEBUG)
Log.d(TAG, "mAllAppsList.reloadPackages");
appsList.reloadPackages(context, mUser);
break;
}
bindApplicationsIfNeeded();
final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
// 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;
// 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.applyFrom(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)) {
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 = DeepShortcutManager.getInstance(context).queryForPinnedShortcuts(cn.getPackageName(), Arrays.asList(si.getDeepShortcutId()), mUser);
if (shortcut.isEmpty()) {
isTargetValid = false;
} else {
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
infoUpdated = true;
}
} else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
isTargetValid = LauncherAppsCompat.getInstance(context).isActivityEnabledForProfile(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.intent);
continue;
} else {
si.status = WorkspaceItemInfo.DEFAULT;
infoUpdated = true;
}
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
}
}
if (isNewApkAvailable && si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
infoUpdated = true;
}
int oldRuntimeFlags = si.runtimeStatusFlags;
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
if (si.runtimeStatusFlags != oldRuntimeFlags) {
shortcutUpdated = true;
}
}
if (infoUpdated || shortcutUpdated) {
updatedWorkspaceItems.add(si);
}
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);
}
}
}
}
bindUpdatedWorkspaceItems(updatedWorkspaceItems);
if (!removedShortcuts.isEmpty()) {
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
}
if (!widgets.isEmpty()) {
scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
}
}
final HashSet<String> removedPackages = new HashSet<>();
if (mOp == OP_REMOVE) {
// Mark all packages in the broadcast to be removed
Collections.addAll(removedPackages, packages);
// No need to update the removedComponents as
// removedPackages is a super-set of removedComponents
} else if (mOp == OP_UPDATE) {
// Mark disabled packages in the broadcast to be removed
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
for (int i = 0; i < N; i++) {
if (!launcherApps.isPackageEnabledForProfile(packages[i], mUser)) {
removedPackages.add(packages[i]);
}
}
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser).or(ItemInfoMatcher.ofComponents(removedComponents, mUser)).and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
}
if (Utilities.ATLEAST_OREO && mOp == OP_ADD) {
// AppWidgetHost events, this is just to initialize the long-press options.
for (int i = 0; i < N; i++) {
dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
}
bindUpdatedWidgets(dataModel);
}
}
Aggregations