• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2025 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 android.content.pm.ShortcutInfo
19 import android.os.UserHandle
20 import com.android.launcher3.Flags
21 import com.android.launcher3.LauncherModel.ModelUpdateTask
22 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
23 import com.android.launcher3.icons.CacheableShortcutInfo
24 import com.android.launcher3.model.data.WorkspaceItemInfo
25 import com.android.launcher3.shortcuts.ShortcutKey
26 import com.android.launcher3.shortcuts.ShortcutRequest
27 import com.android.launcher3.util.ApplicationInfoWrapper
28 import com.android.launcher3.util.ItemInfoMatcher
29 
30 /** Handles changes due to shortcut manager updates (deep shortcut changes) */
31 class ShortcutsChangedTask(
32     private val packageName: String,
33     private val shortcuts: List<ShortcutInfo>,
34     private val user: UserHandle,
35     private val shouldUpdateIdMap: Boolean,
36 ) : ModelUpdateTask {
37 
38     override fun execute(
39         taskController: ModelTaskController,
40         dataModel: BgDataModel,
41         apps: AllAppsList,
42     ) {
43         val context = taskController.context
44         // Find WorkspaceItemInfo's that have changed on the workspace.
45         val matchingWorkspaceItems = ArrayList<WorkspaceItemInfo>()
46 
47         synchronized(dataModel) {
48             dataModel.forAllWorkspaceItemInfos(user) { wai: WorkspaceItemInfo ->
49                 if (
50                     (wai.itemType == ITEM_TYPE_DEEP_SHORTCUT) &&
51                         packageName == wai.getIntent().getPackage()
52                 ) {
53                     matchingWorkspaceItems.add(wai)
54                 }
55             }
56         }
57 
58         if (matchingWorkspaceItems.isNotEmpty()) {
59             val infoWrapper = ApplicationInfoWrapper(context, packageName, user)
60             if (shortcuts.isEmpty()) {
61                 // Verify that the app is indeed installed.
62                 if (
63                     (!infoWrapper.isInstalled() && !infoWrapper.isArchived()) ||
64                         (Flags.restoreArchivedShortcuts() && infoWrapper.isArchived())
65                 ) {
66                     // App is not installed or is archived, ignoring package events
67                     return
68                 }
69             }
70             // Update the workspace to reflect the changes to updated shortcuts residing on it.
71             val allLauncherKnownIds =
72                 matchingWorkspaceItems.map { item -> item.deepShortcutId }.distinct()
73             val shortcuts: List<ShortcutInfo> =
74                 ShortcutRequest(context, user)
75                     .forPackage(packageName, allLauncherKnownIds)
76                     .query(ShortcutRequest.ALL)
77 
78             val nonPinnedIds: MutableSet<String> = HashSet(allLauncherKnownIds)
79             val updatedWorkspaceItemInfos = ArrayList<WorkspaceItemInfo>()
80             for (fullDetails in shortcuts) {
81                 if (!fullDetails.isPinned && !Flags.restoreArchivedShortcuts()) {
82                     continue
83                 }
84                 val shortcutId = fullDetails.id
85                 nonPinnedIds.remove(shortcutId)
86                 matchingWorkspaceItems
87                     .filter { itemInfo: WorkspaceItemInfo -> shortcutId == itemInfo.deepShortcutId }
88                     .forEach { workspaceItemInfo: WorkspaceItemInfo ->
89                         workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context)
90                         taskController.iconCache.getShortcutIcon(
91                             workspaceItemInfo,
92                             CacheableShortcutInfo(fullDetails, infoWrapper),
93                         )
94                         updatedWorkspaceItemInfos.add(workspaceItemInfo)
95                     }
96             }
97 
98             taskController.bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos)
99             if (nonPinnedIds.isNotEmpty()) {
100                 taskController.deleteAndBindComponentsRemoved(
101                     ItemInfoMatcher.ofShortcutKeys(
102                         nonPinnedIds
103                             .map { id: String? -> ShortcutKey(packageName, user, id) }
104                             .toSet()
105                     ),
106                     "removed because the shortcut is no longer available in shortcut service",
107                 )
108             }
109         }
110 
111         if (shouldUpdateIdMap) {
112             // Update the deep shortcut map if the list of ids has changed for an activity.
113             dataModel.updateDeepShortcutCounts(packageName, user, shortcuts)
114             taskController.bindDeepShortcuts(dataModel)
115         }
116     }
117 }
118