1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.model; 17 18 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY; 19 20 import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN; 21 import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED; 22 import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle; 23 import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET; 24 import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED; 25 26 import static java.util.stream.Collectors.groupingBy; 27 import static java.util.stream.Collectors.mapping; 28 29 import android.content.Context; 30 import android.content.pm.LauncherApps; 31 import android.content.pm.ShortcutInfo; 32 import android.os.UserHandle; 33 import android.text.TextUtils; 34 import android.util.ArraySet; 35 import android.util.Log; 36 import android.util.Pair; 37 import android.view.View; 38 39 import androidx.annotation.NonNull; 40 import androidx.annotation.Nullable; 41 42 import com.android.launcher3.LauncherSettings; 43 import com.android.launcher3.LauncherSettings.Favorites; 44 import com.android.launcher3.Workspace; 45 import com.android.launcher3.config.FeatureFlags; 46 import com.android.launcher3.model.data.AppInfo; 47 import com.android.launcher3.model.data.AppPairInfo; 48 import com.android.launcher3.model.data.CollectionInfo; 49 import com.android.launcher3.model.data.FolderInfo; 50 import com.android.launcher3.model.data.ItemInfo; 51 import com.android.launcher3.model.data.LauncherAppWidgetInfo; 52 import com.android.launcher3.model.data.WorkspaceItemInfo; 53 import com.android.launcher3.pm.UserCache; 54 import com.android.launcher3.shortcuts.ShortcutKey; 55 import com.android.launcher3.shortcuts.ShortcutRequest; 56 import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult; 57 import com.android.launcher3.util.ComponentKey; 58 import com.android.launcher3.util.IntArray; 59 import com.android.launcher3.util.IntSet; 60 import com.android.launcher3.util.IntSparseArrayMap; 61 import com.android.launcher3.util.ItemInflater; 62 import com.android.launcher3.util.PackageUserKey; 63 import com.android.launcher3.util.RunnableList; 64 import com.android.launcher3.widget.model.WidgetsListBaseEntry; 65 66 import java.io.FileDescriptor; 67 import java.io.PrintWriter; 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.Collections; 71 import java.util.HashMap; 72 import java.util.HashSet; 73 import java.util.Iterator; 74 import java.util.List; 75 import java.util.Map; 76 import java.util.Set; 77 import java.util.function.Consumer; 78 import java.util.function.Predicate; 79 import java.util.stream.Collectors; 80 import java.util.stream.Stream; 81 82 /** 83 * All the data stored in-memory and managed by the LauncherModel 84 */ 85 public class BgDataModel { 86 87 private static final String TAG = "BgDataModel"; 88 89 /** 90 * Map of all the ItemInfos (shortcuts, folders, and widgets) created by 91 * LauncherModel to their ids 92 */ 93 public final IntSparseArrayMap<ItemInfo> itemsIdMap = new IntSparseArrayMap<>(); 94 95 /** 96 * List of all the folders and shortcuts directly on the home screen (no widgets 97 * or shortcuts within folders). 98 */ 99 public final ArrayList<ItemInfo> workspaceItems = new ArrayList<>(); 100 101 /** 102 * All LauncherAppWidgetInfo created by LauncherModel. 103 */ 104 public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>(); 105 106 /** 107 * Map of id to CollectionInfos of all the folders or app pairs created by LauncherModel 108 */ 109 public final IntSparseArrayMap<CollectionInfo> collections = new IntSparseArrayMap<>(); 110 111 /** 112 * Extra container based items 113 */ 114 public final IntSparseArrayMap<FixedContainerItems> extraItems = new IntSparseArrayMap<>(); 115 116 /** 117 * Maps all launcher activities to counts of their shortcuts. 118 */ 119 public final HashMap<ComponentKey, Integer> deepShortcutMap = new HashMap<>(); 120 121 /** 122 * Entire list of widgets. 123 */ 124 public final WidgetsModel widgetsModel = new WidgetsModel(); 125 126 /** 127 * Cache for strings used in launcher 128 */ 129 public final StringCache stringCache = new StringCache(); 130 131 /** 132 * Id when the model was last bound 133 */ 134 public int lastBindId = 0; 135 136 /** 137 * Load id for which the callbacks were successfully bound 138 */ 139 public int lastLoadId = -1; 140 public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN 141 && !enableSmartspaceRemovalToggle(); 142 143 /** 144 * Clears all the data 145 */ clear()146 public synchronized void clear() { 147 workspaceItems.clear(); 148 appWidgets.clear(); 149 collections.clear(); 150 itemsIdMap.clear(); 151 deepShortcutMap.clear(); 152 extraItems.clear(); 153 } 154 155 /** 156 * Creates an array of valid workspace screens based on current items in the model. 157 */ collectWorkspaceScreens()158 public synchronized IntArray collectWorkspaceScreens() { 159 IntSet screenSet = new IntSet(); 160 for (ItemInfo item: itemsIdMap) { 161 if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { 162 screenSet.add(item.screenId); 163 } 164 } 165 if ((FeatureFlags.QSB_ON_FIRST_SCREEN 166 && !SHOULD_SHOW_FIRST_PAGE_WIDGET) 167 || screenSet.isEmpty()) { 168 screenSet.add(Workspace.FIRST_SCREEN_ID); 169 } 170 return screenSet.getArray(); 171 } 172 dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)173 public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer, 174 String[] args) { 175 writer.println(prefix + "Data Model:"); 176 writer.println(prefix + " ---- workspace items "); 177 for (int i = 0; i < workspaceItems.size(); i++) { 178 writer.println(prefix + '\t' + workspaceItems.get(i).toString()); 179 } 180 writer.println(prefix + " ---- appwidget items "); 181 for (int i = 0; i < appWidgets.size(); i++) { 182 writer.println(prefix + '\t' + appWidgets.get(i).toString()); 183 } 184 writer.println(prefix + " ---- collection items "); 185 for (int i = 0; i < collections.size(); i++) { 186 writer.println(prefix + '\t' + collections.valueAt(i).toString()); 187 } 188 writer.println(prefix + " ---- extra items "); 189 for (int i = 0; i < extraItems.size(); i++) { 190 writer.println(prefix + '\t' + extraItems.valueAt(i).toString()); 191 } 192 writer.println(prefix + " ---- items id map "); 193 for (int i = 0; i < itemsIdMap.size(); i++) { 194 writer.println(prefix + '\t' + itemsIdMap.valueAt(i).toString()); 195 } 196 197 if (args.length > 0 && TextUtils.equals(args[0], "--all")) { 198 writer.println(prefix + "shortcut counts "); 199 for (Integer count : deepShortcutMap.values()) { 200 writer.print(count + ", "); 201 } 202 writer.println(); 203 } 204 } 205 removeItem(Context context, ItemInfo... items)206 public synchronized void removeItem(Context context, ItemInfo... items) { 207 removeItem(context, Arrays.asList(items)); 208 } 209 removeItem(Context context, Iterable<? extends ItemInfo> items)210 public synchronized void removeItem(Context context, Iterable<? extends ItemInfo> items) { 211 ArraySet<UserHandle> updatedDeepShortcuts = new ArraySet<>(); 212 for (ItemInfo item : items) { 213 switch (item.itemType) { 214 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: 215 case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: 216 collections.remove(item.id); 217 if (FeatureFlags.IS_STUDIO_BUILD) { 218 for (ItemInfo info : itemsIdMap) { 219 if (info.container == item.id) { 220 // We are deleting a collection which still contains items that 221 // think they are contained by that collection. 222 String msg = "deleting a collection (" + item + ") which still " 223 + "contains items (" + info + ")"; 224 Log.e(TAG, msg); 225 } 226 } 227 } 228 workspaceItems.remove(item); 229 break; 230 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: { 231 updatedDeepShortcuts.add(item.user); 232 // Fall through. 233 } 234 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 235 workspaceItems.remove(item); 236 break; 237 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: 238 case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: 239 appWidgets.remove(item); 240 break; 241 } 242 itemsIdMap.remove(item.id); 243 } 244 updatedDeepShortcuts.forEach(user -> updateShortcutPinnedState(context, user)); 245 } 246 addItem(Context context, ItemInfo item, boolean newItem)247 public synchronized void addItem(Context context, ItemInfo item, boolean newItem) { 248 addItem(context, item, newItem, null); 249 } 250 addItem( Context context, ItemInfo item, boolean newItem, @Nullable LoaderMemoryLogger logger)251 public synchronized void addItem( 252 Context context, ItemInfo item, boolean newItem, @Nullable LoaderMemoryLogger logger) { 253 if (logger != null) { 254 logger.addLog( 255 Log.DEBUG, 256 TAG, 257 String.format("Adding item to ID map: %s", item.toString()), 258 /* stackTrace= */ null); 259 } 260 itemsIdMap.put(item.id, item); 261 switch (item.itemType) { 262 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: 263 collections.put(item.id, (FolderInfo) item); 264 workspaceItems.add(item); 265 break; 266 case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: 267 collections.put(item.id, (AppPairInfo) item); 268 // Fall through here. App pairs are both containers (like folders) and containable 269 // items (can be placed in folders). So we need to add app pairs to the folders 270 // array (above) but also verify the existence of their container, like regular 271 // apps (below). 272 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: 273 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 274 if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || 275 item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 276 workspaceItems.add(item); 277 } else { 278 if (newItem) { 279 if (!collections.containsKey(item.container)) { 280 // Adding an item to a nonexistent collection. 281 String msg = "attempted to add item: " + item + " to a nonexistent app" 282 + " collection"; 283 Log.e(TAG, msg); 284 } 285 } else { 286 findOrMakeFolder(item.container).add(item); 287 } 288 } 289 break; 290 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: 291 case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: 292 appWidgets.add((LauncherAppWidgetInfo) item); 293 break; 294 } 295 if (newItem && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { 296 updateShortcutPinnedState(context, item.user); 297 } 298 } 299 300 /** 301 * Updates the deep shortucts state in system to match out internal model, pinning any missing 302 * shortcuts and unpinning any extra shortcuts. 303 */ updateShortcutPinnedState(Context context)304 public void updateShortcutPinnedState(Context context) { 305 for (UserHandle user : UserCache.INSTANCE.get(context).getUserProfiles()) { 306 updateShortcutPinnedState(context, user); 307 } 308 } 309 310 /** 311 * Updates the deep shortucts state in system to match out internal model, pinning any missing 312 * shortcuts and unpinning any extra shortcuts. 313 */ updateShortcutPinnedState(Context context, UserHandle user)314 public synchronized void updateShortcutPinnedState(Context context, UserHandle user) { 315 if (!WIDGETS_ENABLED) { 316 return; 317 } 318 319 // Collect all system shortcuts 320 QueryResult result = new ShortcutRequest(context, user) 321 .query(PINNED | FLAG_GET_KEY_FIELDS_ONLY); 322 if (!result.wasSuccess()) { 323 return; 324 } 325 // Map of packageName to shortcutIds that are currently in the system 326 Map<String, Set<String>> systemMap = result.stream() 327 .collect(groupingBy(ShortcutInfo::getPackage, 328 mapping(ShortcutInfo::getId, Collectors.toSet()))); 329 330 // Collect all model shortcuts 331 Stream.Builder<WorkspaceItemInfo> itemStream = Stream.builder(); 332 forAllWorkspaceItemInfos(user, itemStream::accept); 333 // Map of packageName to shortcutIds that are currently in our model 334 Map<String, Set<String>> modelMap = Stream.concat( 335 // Model shortcuts 336 itemStream.build() 337 .filter(wi -> wi.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) 338 .map(ShortcutKey::fromItemInfo), 339 // Pending shortcuts 340 ItemInstallQueue.INSTANCE.get(context).getPendingShortcuts(user)) 341 .collect(groupingBy(ShortcutKey::getPackageName, 342 mapping(ShortcutKey::getId, Collectors.toSet()))); 343 344 // Check for diff 345 for (Map.Entry<String, Set<String>> entry : modelMap.entrySet()) { 346 Set<String> modelShortcuts = entry.getValue(); 347 Set<String> systemShortcuts = systemMap.remove(entry.getKey()); 348 if (systemShortcuts == null) { 349 systemShortcuts = Collections.emptySet(); 350 } 351 352 // Do not use .equals as it can vary based on the type of set 353 if (systemShortcuts.size() != modelShortcuts.size() 354 || !systemShortcuts.containsAll(modelShortcuts)) { 355 // Update system state for this package 356 try { 357 context.getSystemService(LauncherApps.class).pinShortcuts( 358 entry.getKey(), new ArrayList<>(modelShortcuts), user); 359 } catch (SecurityException | IllegalStateException e) { 360 Log.w(TAG, "Failed to pin shortcut", e); 361 } 362 } 363 } 364 365 // If there are any extra pinned shortcuts, remove them 366 systemMap.keySet().forEach(packageName -> { 367 // Update system state 368 try { 369 context.getSystemService(LauncherApps.class).pinShortcuts( 370 packageName, Collections.emptyList(), user); 371 } catch (SecurityException | IllegalStateException e) { 372 Log.w(TAG, "Failed to unpin shortcut", e); 373 } 374 }); 375 } 376 377 /** 378 * Return an existing FolderInfo object if we have encountered this ID previously, 379 * or make a new one. 380 */ findOrMakeFolder(int id)381 public synchronized CollectionInfo findOrMakeFolder(int id) { 382 // See if a placeholder was created for us already 383 CollectionInfo collectionInfo = collections.get(id); 384 if (collectionInfo == null) { 385 // No placeholder -- create a new blank folder instance. At this point, we don't know 386 // if the desired container is supposed to be a folder or an app pair. In the case that 387 // it is an app pair, the blank folder will be replaced by a blank app pair when the app 388 // pair is getting processed, in WorkspaceItemProcessor.processFolderOrAppPair(). 389 collectionInfo = new FolderInfo(); 390 collections.put(id, collectionInfo); 391 } 392 return collectionInfo; 393 } 394 395 /** 396 * Clear all the deep shortcut counts for the given package, and re-add the new shortcut counts. 397 */ updateDeepShortcutCounts( String packageName, UserHandle user, List<ShortcutInfo> shortcuts)398 public synchronized void updateDeepShortcutCounts( 399 String packageName, UserHandle user, List<ShortcutInfo> shortcuts) { 400 if (packageName != null) { 401 Iterator<ComponentKey> keysIter = deepShortcutMap.keySet().iterator(); 402 while (keysIter.hasNext()) { 403 ComponentKey next = keysIter.next(); 404 if (next.componentName.getPackageName().equals(packageName) 405 && next.user.equals(user)) { 406 keysIter.remove(); 407 } 408 } 409 } 410 411 // Now add the new shortcuts to the map. 412 for (ShortcutInfo shortcut : shortcuts) { 413 boolean shouldShowInContainer = shortcut.isEnabled() 414 && (shortcut.isDeclaredInManifest() || shortcut.isDynamic()) 415 && shortcut.getActivity() != null; 416 if (shouldShowInContainer) { 417 ComponentKey targetComponent 418 = new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle()); 419 420 Integer previousCount = deepShortcutMap.get(targetComponent); 421 deepShortcutMap.put(targetComponent, previousCount == null ? 1 : previousCount + 1); 422 } 423 } 424 } 425 426 /** 427 * Returns a list containing all workspace items including widgets. 428 */ getAllWorkspaceItems()429 public synchronized ArrayList<ItemInfo> getAllWorkspaceItems() { 430 ArrayList<ItemInfo> items = new ArrayList<>(workspaceItems.size() + appWidgets.size()); 431 items.addAll(workspaceItems); 432 items.addAll(appWidgets); 433 return items; 434 } 435 436 /** 437 * Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted 438 * items and dynamic/predicted items for the provided {@code userHandle}. 439 * Note the call is not synchronized over the model, that should be handled by the called. 440 */ forAllWorkspaceItemInfos(UserHandle userHandle, Consumer<WorkspaceItemInfo> op)441 public void forAllWorkspaceItemInfos(UserHandle userHandle, Consumer<WorkspaceItemInfo> op) { 442 for (ItemInfo info : itemsIdMap) { 443 if (info instanceof WorkspaceItemInfo && userHandle.equals(info.user)) { 444 op.accept((WorkspaceItemInfo) info); 445 } 446 } 447 448 for (int i = extraItems.size() - 1; i >= 0; i--) { 449 for (ItemInfo info : extraItems.valueAt(i).items) { 450 if (info instanceof WorkspaceItemInfo && userHandle.equals(info.user)) { 451 op.accept((WorkspaceItemInfo) info); 452 } 453 } 454 } 455 } 456 457 /** 458 * An object containing items corresponding to a fixed container 459 */ 460 public static class FixedContainerItems { 461 462 public final int containerId; 463 public final List<ItemInfo> items; 464 FixedContainerItems(int containerId, List<ItemInfo> items)465 public FixedContainerItems(int containerId, List<ItemInfo> items) { 466 this.containerId = containerId; 467 this.items = Collections.unmodifiableList(items); 468 } 469 470 @Override 471 @NonNull toString()472 public final String toString() { 473 StringBuilder s = new StringBuilder(); 474 s.append("FixedContainerItems:"); 475 s.append(" id=").append(containerId); 476 s.append(" itemCount=").append(items.size()); 477 for (int i = 0; i < items.size(); i++) { 478 s.append(" item #").append(i).append(": ").append(items.get(i).toString()); 479 } 480 return s.toString(); 481 } 482 483 } 484 485 486 public interface Callbacks { 487 // If the launcher has permission to access deep shortcuts. 488 int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0; 489 // If quiet mode is enabled for any user 490 int FLAG_QUIET_MODE_ENABLED = 1 << 1; 491 // If launcher can change quiet mode 492 int FLAG_QUIET_MODE_CHANGE_PERMISSION = 1 << 2; 493 // If quiet mode is enabled for work profile user 494 int FLAG_WORK_PROFILE_QUIET_MODE_ENABLED = 1 << 3; 495 // If quiet mode is enabled for private profile user 496 int FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED = 1 << 4; 497 498 /** 499 * Returns an IntSet of page ids to bind first, synchronously if possible 500 * or an empty IntSet 501 * @param orderedScreenIds All the page ids to be bound 502 */ 503 @NonNull getPagesToBindSynchronously(IntArray orderedScreenIds)504 default IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) { 505 return new IntSet(); 506 } 507 clearPendingBinds()508 default void clearPendingBinds() { } startBinding()509 default void startBinding() { } 510 511 @Nullable getItemInflater()512 default ItemInflater getItemInflater() { 513 return null; 514 } 515 bindItems(@onNull List<ItemInfo> shortcuts, boolean forceAnimateIcons)516 default void bindItems(@NonNull List<ItemInfo> shortcuts, boolean forceAnimateIcons) { } 517 /** Alternate method to bind preinflated views */ bindInflatedItems(@onNull List<Pair<ItemInfo, View>> items)518 default void bindInflatedItems(@NonNull List<Pair<ItemInfo, View>> items) { } 519 bindScreens(IntArray orderedScreenIds)520 default void bindScreens(IntArray orderedScreenIds) { } setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled)521 default void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) { } finishBindingItems(IntSet pagesBoundFirst)522 default void finishBindingItems(IntSet pagesBoundFirst) { } preAddApps()523 default void preAddApps() { } bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated)524 default void bindAppsAdded(IntArray newScreens, 525 ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated) { } 526 527 /** 528 * Called when some persistent property of an item is modified 529 */ bindItemsModified(List<ItemInfo> items)530 default void bindItemsModified(List<ItemInfo> items) { } 531 532 /** 533 * Binds updated incremental download progress 534 */ bindIncrementalDownloadProgressUpdated(AppInfo app)535 default void bindIncrementalDownloadProgressUpdated(AppInfo app) { } bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated)536 default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { } bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets)537 default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { } bindRestoreItemsChange(HashSet<ItemInfo> updates)538 default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { } bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher)539 default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { } bindAllWidgets(List<WidgetsListBaseEntry> widgets)540 default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { } bindSmartspaceWidget()541 default void bindSmartspaceWidget() { } 542 543 /** Called when workspace has been bound. */ onInitialBindComplete(@onNull IntSet boundPages, @NonNull RunnableList pendingTasks, @NonNull RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync)544 default void onInitialBindComplete(@NonNull IntSet boundPages, 545 @NonNull RunnableList pendingTasks, 546 @NonNull RunnableList onCompleteSignal, 547 int workspaceItemCount, boolean isBindSync) { 548 pendingTasks.executeAllAndDestroy(); 549 } 550 bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap)551 default void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap) { } 552 553 /** 554 * Binds extra item provided any external source 555 */ bindExtraContainerItems(FixedContainerItems item)556 default void bindExtraContainerItems(FixedContainerItems item) { } 557 bindAllApplications(AppInfo[] apps, int flags, Map<PackageUserKey, Integer> packageUserKeytoUidMap)558 default void bindAllApplications(AppInfo[] apps, int flags, 559 Map<PackageUserKey, Integer> packageUserKeytoUidMap) { 560 } 561 562 /** 563 * Binds the cache of string resources 564 */ bindStringCache(StringCache cache)565 default void bindStringCache(StringCache cache) { } 566 } 567 } 568