use of com.android.launcher3.util.IntSet in project android_packages_apps_Launcher3 by crdroidandroid.
the class ModelUtils method getMissingHotseatRanks.
/**
* Iterates though current workspace items and returns available hotseat ranks for prediction.
*/
public static IntArray getMissingHotseatRanks(List<ItemInfo> items, int len) {
IntSet seen = new IntSet();
items.stream().filter(info -> info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT).forEach(i -> seen.add(i.screenId));
IntArray result = new IntArray(len);
IntStream.range(0, len).filter(i -> !seen.contains(i)).forEach(result::add);
return result;
}
use of com.android.launcher3.util.IntSet in project android_packages_apps_Launcher3 by crdroidandroid.
the class RecentsView method updateGridProperties.
/**
* Updates TaskView and ClearAllButton scaling and translation required to turn into grid
* layout.
* This method only calculates the potential position and depends on {@link #setGridProgress} to
* apply the actual scaling and translation.
*
* @param isTaskDismissal indicates if update was called due to task dismissal
*/
private void updateGridProperties(boolean isTaskDismissal) {
int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
}
final int boxLength = Math.max(mLastComputedGridTaskSize.width(), mLastComputedGridTaskSize.height());
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
/*
* taskGridVerticalDiff is used to position the top of a task in the top row of the grid
* heightOffset is the vertical space one grid task takes + space between top and
* bottom row
* Summed together they provide the top position for bottom row of grid tasks
*/
final float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
final float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
int topRowWidth = 0;
int bottomRowWidth = 0;
float topAccumulatedTranslationX = 0;
float bottomAccumulatedTranslationX = 0;
// Contains whether the child index is in top or bottom of grid (for non-focused task)
// Different from mTopRowIdSet, which contains the taskId of what task is in top row
IntSet topSet = new IntSet();
IntSet bottomSet = new IntSet();
// Horizontal grid translation for each task
float[] gridTranslations = new float[taskCount];
int focusedTaskIndex = Integer.MAX_VALUE;
int focusedTaskShift = 0;
int focusedTaskWidthAndSpacing = 0;
int snappedTaskRowWidth = 0;
int snappedPage = getNextPage();
TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(snappedPage);
if (!isTaskDismissal) {
mTopRowIdSet.clear();
}
for (int i = 0; i < taskCount; i++) {
TaskView taskView = getTaskViewAt(i);
int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
// the grid.
if (taskView.isFocusedTask()) {
topRowWidth += taskWidthAndSpacing;
bottomRowWidth += taskWidthAndSpacing;
focusedTaskIndex = i;
focusedTaskWidthAndSpacing = taskWidthAndSpacing;
gridTranslations[i] += focusedTaskShift;
gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
// Center view vertically in case it's from different orientation.
taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin - taskView.getLayoutParams().height) / 2f);
if (taskView == snappedTaskView) {
// If focused task is snapped, the row width is just task width and spacing.
snappedTaskRowWidth = taskWidthAndSpacing;
}
} else {
if (i > focusedTaskIndex) {
// For tasks after the focused task, shift by focused task's width and spacing.
gridTranslations[i] += mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
} else {
// For task before the focused task, accumulate the width and spacing to
// calculate the distance focused task need to shift.
focusedTaskShift += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
}
int taskId = taskView.getTask().key.id;
boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId) : topRowWidth <= bottomRowWidth;
if (isTopRow) {
topRowWidth += taskWidthAndSpacing;
topSet.add(i);
mTopRowIdSet.add(taskId);
taskView.setGridTranslationY(taskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
if (j == focusedTaskIndex) {
continue;
}
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
topAccumulatedTranslationX += currentTaskTranslationX;
} else {
bottomRowWidth += taskWidthAndSpacing;
bottomSet.add(i);
// Move into bottom row.
taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
if (j == focusedTaskIndex) {
continue;
}
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
bottomAccumulatedTranslationX += currentTaskTranslationX;
}
if (taskView == snappedTaskView) {
snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
}
}
}
// We need to maintain snapped task's page scroll invariant between quick switch and
// overview, so we sure snapped task's grid translation is 0, and add a non-fullscreen
// translationX that is the same as snapped task's full scroll adjustment.
float snappedTaskFullscreenScrollAdjustment = 0;
float snappedTaskGridTranslationX = 0;
if (snappedTaskView != null) {
snappedTaskFullscreenScrollAdjustment = snappedTaskView.getScrollAdjustment(/*fullscreenEnabled=*/
true, /*gridEnabled=*/
false);
snappedTaskGridTranslationX = gridTranslations[snappedPage - mTaskViewStartIndex];
}
for (int i = 0; i < taskCount; i++) {
TaskView taskView = getTaskViewAt(i);
taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX);
taskView.getPrimaryNonFullscreenTranslationProperty().set(taskView, snappedTaskFullscreenScrollAdjustment);
taskView.getSecondaryNonFullscreenTranslationProperty().set(taskView, 0f);
}
// Use the accumulated translation of the row containing the last task.
float clearAllAccumulatedTranslation = topSet.contains(taskCount - 1) ? topAccumulatedTranslationX : bottomAccumulatedTranslationX;
// If the last task is on the shorter row, ClearAllButton will embed into the shorter row
// which is not what we want. Compensate the width difference of the 2 rows in that case.
float shorterRowCompensation = 0;
if (topRowWidth <= bottomRowWidth) {
if (topSet.contains(taskCount - 1)) {
shorterRowCompensation = bottomRowWidth - topRowWidth;
}
} else {
if (bottomSet.contains(taskCount - 1)) {
shorterRowCompensation = topRowWidth - bottomRowWidth;
}
}
float clearAllShorterRowCompensation = mIsRtl ? -shorterRowCompensation : shorterRowCompensation;
// If the total width is shorter than one grid's width, move ClearAllButton further away
// accordingly. Update longRowWidth if ClearAllButton has been moved.
float clearAllShortTotalCompensation = 0;
int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
if (longRowWidth < mLastComputedGridSize.width()) {
float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
clearAllShortTotalCompensation = mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
longRowWidth = mLastComputedGridSize.width();
}
float clearAllTotalTranslationX = clearAllAccumulatedTranslation + clearAllShorterRowCompensation + clearAllShortTotalCompensation + snappedTaskFullscreenScrollAdjustment;
if (focusedTaskIndex < taskCount) {
// Shift by focused task's width and spacing if a task is focused.
clearAllTotalTranslationX += mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
}
// of swiping up after quick switch.
if (snappedTaskView != null) {
int distanceFromClearAll = longRowWidth - snappedTaskRowWidth;
int minimumDistance = mLastComputedGridSize.width() - snappedTaskView.getLayoutParams().width;
if (distanceFromClearAll < minimumDistance) {
int distanceDifference = minimumDistance - distanceFromClearAll;
clearAllTotalTranslationX += mIsRtl ? -distanceDifference : distanceDifference;
}
}
setGridProgress(mGridProgress);
}
use of com.android.launcher3.util.IntSet in project android_packages_apps_Launcher3 by crdroidandroid.
the class ModelUtils method filterCurrentWorkspaceItems.
/**
* Filters the set of items who are directly or indirectly (via another container) on the
* specified screen.
*/
public static <T extends ItemInfo> void filterCurrentWorkspaceItems(int currentScreenId, ArrayList<T> allWorkspaceItems, ArrayList<T> currentScreenItems, ArrayList<T> otherScreenItems) {
// Purge any null ItemInfos
allWorkspaceItems.removeIf(Objects::isNull);
// Order the set of items by their containers first, this allows use to walk through the
// list sequentially, build up a list of containers that are in the specified screen,
// as well as all items in those containers.
IntSet itemsOnScreen = new IntSet();
Collections.sort(allWorkspaceItems, (lhs, rhs) -> Integer.compare(lhs.container, rhs.container));
for (T info : allWorkspaceItems) {
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (info.screenId == currentScreenId) {
currentScreenItems.add(info);
itemsOnScreen.add(info.id);
} else {
otherScreenItems.add(info);
}
} else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
currentScreenItems.add(info);
itemsOnScreen.add(info.id);
} else {
if (itemsOnScreen.contains(info.container)) {
currentScreenItems.add(info);
itemsOnScreen.add(info.id);
} else {
otherScreenItems.add(info);
}
}
}
}
use of com.android.launcher3.util.IntSet in project android_packages_apps_Launcher3 by crdroidandroid.
the class PackageUpdatedTask method execute.
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
final Context context = app.getContext();
final IconCache iconCache = app.getIconCache();
final String[] packages = mPackages;
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 ? // We want to update all packages for this user
ItemInfoMatcher.ofUser(mUser) : ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
final HashMap<String, List<LauncherActivityInfo>> activitiesLists = new HashMap<>();
boolean needsRestart = false;
switch(mOp) {
case OP_ADD:
{
for (int i = 0; i < N; i++) {
if (DEBUG)
Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
if (isTargetPackage(packages[i])) {
needsRestart = true;
}
iconCache.updateIconsForPkg(packages[i], mUser);
if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
appsList.removePackage(packages[i], mUser);
}
activitiesLists.put(packages[i], appsList.addPackage(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 (int i = 0; i < N; i++) {
if (DEBUG)
Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
iconCache.updateIconsForPkg(packages[i], mUser);
activitiesLists.put(packages[i], appsList.updatePackage(context, packages[i], mUser));
app.getWidgetCache().removePackage(packages[i], mUser);
// The update may have changed which shortcuts/widgets are available.
// Refresh the widgets for the package if we have an activity running.
Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
if (launcher != null) {
launcher.refreshAndBindWidgetsForPackageUser(new PackageUserKey(packages[i], 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 (int i = 0; i < N; i++) {
FileLog.d(TAG, "Removing app icon" + packages[i]);
iconCache.removeIconsForPkg(packages[i], mUser);
if (isTargetPackage(packages[i])) {
needsRestart = true;
}
}
// 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);
for (int i = 0; i < N; i++) {
if (isTargetPackage(packages[i])) {
needsRestart = true;
}
}
break;
case OP_USER_AVAILABILITY_CHANGE:
{
UserManagerState ums = new UserManagerState();
ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class));
flagOp = ums.isUserQuiet(mUser) ? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER) : FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER);
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 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) {
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) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
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;
}
}
if (si.isPromise() && isNewApkAvailable) {
boolean isTargetValid = !cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME);
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 (isTargetValid) {
isTargetValid = context.getSystemService(LauncherApps.class).isActivityEnabled(cn, mUser);
}
if (!isTargetValid && si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
} else if (si.hasPromiseIconUi()) {
removedShortcuts.add(si.id);
return;
}
} 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;
}
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
}
}
if (isNewApkAvailable) {
List<LauncherActivityInfo> activities = activitiesLists.get(packageName);
si.setProgressLevel(activities == null || activities.isEmpty() ? 100 : PackageManagerHelper.getLoadingProgress(activities.get(0)), PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
if (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 && 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));
}
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 LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
for (int i = 0; i < N; i++) {
if (!launcherApps.isPackageEnabled(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(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
ItemInstallQueue.INSTANCE.get(context).removeFromInstallQueue(removedPackages, mUser);
}
if (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);
}
if (needsRestart) {
Utilities.restart(context);
}
}
use of com.android.launcher3.util.IntSet in project android_packages_apps_Launcher3 by crdroidandroid.
the class InstallSessionHelper method getPromiseIconIds.
@WorkerThread
private IntSet getPromiseIconIds() {
Preconditions.assertWorkerThread();
if (mPromiseIconIds != null) {
return mPromiseIconIds;
}
mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString(getPrefs(mAppContext).getString(PROMISE_ICON_IDS, "")));
IntArray existingIds = new IntArray();
for (SessionInfo info : getActiveSessions().values()) {
existingIds.add(info.getSessionId());
}
IntArray idsToRemove = new IntArray();
for (int i = mPromiseIconIds.size() - 1; i >= 0; --i) {
if (!existingIds.contains(mPromiseIconIds.getArray().get(i))) {
idsToRemove.add(mPromiseIconIds.getArray().get(i));
}
}
for (int i = idsToRemove.size() - 1; i >= 0; --i) {
mPromiseIconIds.getArray().removeValue(idsToRemove.get(i));
}
return mPromiseIconIds;
}
Aggregations