blob: 8304e9698aa6ab77efe806669ac27ea075fee3aa [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
15import com.android.launcher3.widget.model.WidgetsListBaseEntry
16import java.util.function.Predicate
17
18class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks {
Sebastian Franco69fd7422023-10-06 16:48:58 -070019
20 var synchronouslyBoundPages = LIntSet()
21 var pagesToBindSynchronously = LIntSet()
22
Sebastian Francobd7919c2023-09-19 10:55:37 -070023 override fun preAddApps() {
24 // If there's an undo snackbar, force it to complete to ensure empty screens are removed
25 // before trying to add new items.
26 launcher.modelWriter.commitDelete()
27 val snackbar =
28 AbstractFloatingView.getOpenView<AbstractFloatingView>(
29 launcher,
30 AbstractFloatingView.TYPE_SNACKBAR
31 )
32 snackbar?.post { snackbar.close(true) }
33 }
34
35 @UiThread
36 override fun bindAllApplications(
37 apps: Array<AppInfo?>?,
38 flags: Int,
39 packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?
40 ) {
41 Preconditions.assertUIThread()
42 val hadWorkApps = launcher.appsView.shouldShowTabs()
43 launcher.appsView.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
44 PopupContainerWithArrow.dismissInvalidPopup(launcher)
45 if (hadWorkApps != launcher.appsView.shouldShowTabs()) {
46 launcher.stateManager.goToState(LauncherState.NORMAL)
47 }
48 }
49
50 /**
51 * Copies LauncherModel's map of activities to shortcut counts to Launcher's. This is necessary
52 * because LauncherModel's map is updated in the background, while Launcher runs on the UI.
53 */
54 override fun bindDeepShortcutMap(deepShortcutMapCopy: HashMap<ComponentKey?, Int?>?) {
55 launcher.popupDataProvider.setDeepShortcutMap(deepShortcutMapCopy)
56 }
57
58 override fun bindIncrementalDownloadProgressUpdated(app: AppInfo?) {
59 launcher.appsView.appsStore.updateProgressBar(app)
60 }
61
62 override fun bindWidgetsRestored(widgets: ArrayList<LauncherAppWidgetInfo?>?) {
63 launcher.workspace.widgetsRestored(widgets)
64 }
65
66 /**
67 * Some shortcuts were updated in the background. Implementation of the method from
68 * LauncherModel.Callbacks.
69 *
70 * @param updated list of shortcuts which have changed.
71 */
72 override fun bindWorkspaceItemsChanged(updated: List<WorkspaceItemInfo?>) {
73 if (updated.isNotEmpty()) {
74 launcher.workspace.updateWorkspaceItems(updated, launcher)
75 PopupContainerWithArrow.dismissInvalidPopup(launcher)
76 }
77 }
78
79 /**
80 * Update the state of a package, typically related to install state. Implementation of the
81 * method from LauncherModel.Callbacks.
82 */
83 override fun bindRestoreItemsChange(updates: HashSet<ItemInfo?>?) {
84 launcher.workspace.updateRestoreItems(updates, launcher)
85 }
86
87 /**
88 * A package was uninstalled/updated. We take both the super set of packageNames in addition to
89 * specific applications to remove, the reason being that this can be called when a package is
90 * updated as well. In that scenario, we only remove specific components from the workspace and
91 * hotseat, where as package-removal should clear all items by package name.
92 */
93 override fun bindWorkspaceComponentsRemoved(matcher: Predicate<ItemInfo?>?) {
94 launcher.workspace.removeItemsByMatcher(matcher)
95 launcher.dragController.onAppsRemoved(matcher)
96 PopupContainerWithArrow.dismissInvalidPopup(launcher)
97 }
98
99 override fun bindAllWidgets(allWidgets: List<WidgetsListBaseEntry?>?) {
100 launcher.popupDataProvider.allWidgets = allWidgets
101 }
Sebastian Franco69fd7422023-10-06 16:48:58 -0700102
103 /** Returns the ids of the workspaces to bind. */
104 override fun getPagesToBindSynchronously(orderedScreenIds: LIntArray): LIntSet {
105 // If workspace binding is still in progress, getCurrentPageScreenIds won't be
106 // accurate, and we should use mSynchronouslyBoundPages that's set during initial binding.
107 val visibleIds =
108 when {
109 !pagesToBindSynchronously.isEmpty -> pagesToBindSynchronously
110 !launcher.isWorkspaceLoading -> launcher.workspace.currentPageScreenIds
111 else -> synchronouslyBoundPages
112 }
113 // Launcher IntArray has the same name as Kotlin IntArray
114 val result = LIntSet()
115 if (visibleIds.isEmpty) {
116 return result
117 }
118 val actualIds = orderedScreenIds.clone()
119 val firstId = visibleIds.first()
120 val pairId = launcher.workspace.getScreenPair(firstId)
121 // Double check that actual screenIds contains the visibleId, as empty screens are hidden
122 // in single panel.
123 if (actualIds.contains(firstId)) {
124 result.add(firstId)
125 if (launcher.deviceProfile.isTwoPanels && actualIds.contains(pairId)) {
126 result.add(pairId)
127 }
128 } else if (
129 LauncherAppState.getIDP(launcher).supportedProfiles.any(DeviceProfile::isTwoPanels) &&
130 actualIds.contains(pairId)
131 ) {
132 // Add the right panel if left panel is hidden when switching display, due to empty
133 // pages being hidden in single panel.
134 result.add(pairId)
135 }
136 return result
137 }
Sebastian Francobd7919c2023-09-19 10:55:37 -0700138}