blob: 2c3e74d335f6a7de7b24da834e0984450a99be6c [file] [log] [blame]
Sebastian Francobd7919c2023-09-19 10:55:37 -07001package com.android.launcher3
2
3import androidx.annotation.UiThread
4import com.android.launcher3.model.BgDataModel
5import com.android.launcher3.model.data.AppInfo
6import com.android.launcher3.model.data.ItemInfo
7import com.android.launcher3.model.data.LauncherAppWidgetInfo
8import com.android.launcher3.model.data.WorkspaceItemInfo
9import com.android.launcher3.popup.PopupContainerWithArrow
10import com.android.launcher3.util.ComponentKey
Sebastian Franco69fd7422023-10-06 16:48:58 -070011import com.android.launcher3.util.IntArray as LIntArray
12import com.android.launcher3.util.IntSet as LIntSet
Sebastian Francobd7919c2023-09-19 10:55:37 -070013import com.android.launcher3.util.PackageUserKey
14import com.android.launcher3.util.Preconditions
Sebastian Franco50b74c32023-11-16 11:36:49 -060015import com.android.launcher3.widget.PendingAddWidgetInfo
Sebastian Francobd7919c2023-09-19 10:55:37 -070016import com.android.launcher3.widget.model.WidgetsListBaseEntry
17import java.util.function.Predicate
18
19class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks {
Sebastian Franco69fd7422023-10-06 16:48:58 -070020
21 var synchronouslyBoundPages = LIntSet()
22 var pagesToBindSynchronously = LIntSet()
23
Sebastian Francobd7919c2023-09-19 10:55:37 -070024 override fun preAddApps() {
25 // If there's an undo snackbar, force it to complete to ensure empty screens are removed
26 // before trying to add new items.
27 launcher.modelWriter.commitDelete()
28 val snackbar =
29 AbstractFloatingView.getOpenView<AbstractFloatingView>(
30 launcher,
31 AbstractFloatingView.TYPE_SNACKBAR
32 )
33 snackbar?.post { snackbar.close(true) }
34 }
35
36 @UiThread
37 override fun bindAllApplications(
38 apps: Array<AppInfo?>?,
39 flags: Int,
40 packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?
41 ) {
42 Preconditions.assertUIThread()
43 val hadWorkApps = launcher.appsView.shouldShowTabs()
44 launcher.appsView.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
45 PopupContainerWithArrow.dismissInvalidPopup(launcher)
46 if (hadWorkApps != launcher.appsView.shouldShowTabs()) {
47 launcher.stateManager.goToState(LauncherState.NORMAL)
48 }
49 }
50
51 /**
52 * Copies LauncherModel's map of activities to shortcut counts to Launcher's. This is necessary
53 * because LauncherModel's map is updated in the background, while Launcher runs on the UI.
54 */
55 override fun bindDeepShortcutMap(deepShortcutMapCopy: HashMap<ComponentKey?, Int?>?) {
56 launcher.popupDataProvider.setDeepShortcutMap(deepShortcutMapCopy)
57 }
58
59 override fun bindIncrementalDownloadProgressUpdated(app: AppInfo?) {
60 launcher.appsView.appsStore.updateProgressBar(app)
61 }
62
63 override fun bindWidgetsRestored(widgets: ArrayList<LauncherAppWidgetInfo?>?) {
64 launcher.workspace.widgetsRestored(widgets)
65 }
66
67 /**
68 * Some shortcuts were updated in the background. Implementation of the method from
69 * LauncherModel.Callbacks.
70 *
71 * @param updated list of shortcuts which have changed.
72 */
73 override fun bindWorkspaceItemsChanged(updated: List<WorkspaceItemInfo?>) {
74 if (updated.isNotEmpty()) {
75 launcher.workspace.updateWorkspaceItems(updated, launcher)
76 PopupContainerWithArrow.dismissInvalidPopup(launcher)
77 }
78 }
79
80 /**
81 * Update the state of a package, typically related to install state. Implementation of the
82 * method from LauncherModel.Callbacks.
83 */
84 override fun bindRestoreItemsChange(updates: HashSet<ItemInfo?>?) {
85 launcher.workspace.updateRestoreItems(updates, launcher)
86 }
87
88 /**
89 * A package was uninstalled/updated. We take both the super set of packageNames in addition to
90 * specific applications to remove, the reason being that this can be called when a package is
91 * updated as well. In that scenario, we only remove specific components from the workspace and
92 * hotseat, where as package-removal should clear all items by package name.
93 */
94 override fun bindWorkspaceComponentsRemoved(matcher: Predicate<ItemInfo?>?) {
95 launcher.workspace.removeItemsByMatcher(matcher)
96 launcher.dragController.onAppsRemoved(matcher)
97 PopupContainerWithArrow.dismissInvalidPopup(launcher)
98 }
99
100 override fun bindAllWidgets(allWidgets: List<WidgetsListBaseEntry?>?) {
101 launcher.popupDataProvider.allWidgets = allWidgets
102 }
Sebastian Franco69fd7422023-10-06 16:48:58 -0700103
104 /** Returns the ids of the workspaces to bind. */
105 override fun getPagesToBindSynchronously(orderedScreenIds: LIntArray): LIntSet {
106 // If workspace binding is still in progress, getCurrentPageScreenIds won't be
107 // accurate, and we should use mSynchronouslyBoundPages that's set during initial binding.
108 val visibleIds =
109 when {
110 !pagesToBindSynchronously.isEmpty -> pagesToBindSynchronously
111 !launcher.isWorkspaceLoading -> launcher.workspace.currentPageScreenIds
112 else -> synchronouslyBoundPages
113 }
114 // Launcher IntArray has the same name as Kotlin IntArray
115 val result = LIntSet()
116 if (visibleIds.isEmpty) {
117 return result
118 }
119 val actualIds = orderedScreenIds.clone()
120 val firstId = visibleIds.first()
121 val pairId = launcher.workspace.getScreenPair(firstId)
122 // Double check that actual screenIds contains the visibleId, as empty screens are hidden
123 // in single panel.
124 if (actualIds.contains(firstId)) {
125 result.add(firstId)
126 if (launcher.deviceProfile.isTwoPanels && actualIds.contains(pairId)) {
127 result.add(pairId)
128 }
129 } else if (
130 LauncherAppState.getIDP(launcher).supportedProfiles.any(DeviceProfile::isTwoPanels) &&
131 actualIds.contains(pairId)
132 ) {
133 // Add the right panel if left panel is hidden when switching display, due to empty
134 // pages being hidden in single panel.
135 result.add(pairId)
136 }
137 return result
138 }
Sebastian Franco50b74c32023-11-16 11:36:49 -0600139
140 override fun bindSmartspaceWidget() {
141 val cl: CellLayout? =
142 launcher.workspace.getScreenWithId(WorkspaceLayoutManager.FIRST_SCREEN_ID)
143 val spanX = InvariantDeviceProfile.INSTANCE.get(launcher).numSearchContainerColumns
144
145 if (cl?.isRegionVacant(0, 0, spanX, 1) != true) {
146 return
147 }
148
149 val widgetsListBaseEntry: WidgetsListBaseEntry =
150 launcher.popupDataProvider.allWidgets.firstOrNull { item: WidgetsListBaseEntry ->
151 item.mPkgItem.packageName == BuildConfig.APPLICATION_ID
152 }
153 ?: return
154
155 val info =
156 PendingAddWidgetInfo(
157 widgetsListBaseEntry.mWidgets[0].widgetInfo,
158 LauncherSettings.Favorites.CONTAINER_DESKTOP
159 )
160 launcher.addPendingItem(
161 info,
162 info.container,
163 WorkspaceLayoutManager.FIRST_SCREEN_ID,
164 intArrayOf(0, 0),
165 info.spanX,
166 info.spanY
167 )
168 }
Sebastian Francobd7919c2023-09-19 10:55:37 -0700169}