Sebastian Franco | bd7919c | 2023-09-19 10:55:37 -0700 | [diff] [blame] | 1 | package com.android.launcher3 |
| 2 | |
| 3 | import androidx.annotation.UiThread |
| 4 | import com.android.launcher3.model.BgDataModel |
| 5 | import com.android.launcher3.model.data.AppInfo |
| 6 | import com.android.launcher3.model.data.ItemInfo |
| 7 | import com.android.launcher3.model.data.LauncherAppWidgetInfo |
| 8 | import com.android.launcher3.model.data.WorkspaceItemInfo |
| 9 | import com.android.launcher3.popup.PopupContainerWithArrow |
| 10 | import com.android.launcher3.util.ComponentKey |
Sebastian Franco | 69fd742 | 2023-10-06 16:48:58 -0700 | [diff] [blame] | 11 | import com.android.launcher3.util.IntArray as LIntArray |
| 12 | import com.android.launcher3.util.IntSet as LIntSet |
Sebastian Franco | bd7919c | 2023-09-19 10:55:37 -0700 | [diff] [blame] | 13 | import com.android.launcher3.util.PackageUserKey |
| 14 | import com.android.launcher3.util.Preconditions |
Sebastian Franco | 50b74c3 | 2023-11-16 11:36:49 -0600 | [diff] [blame^] | 15 | import com.android.launcher3.widget.PendingAddWidgetInfo |
Sebastian Franco | bd7919c | 2023-09-19 10:55:37 -0700 | [diff] [blame] | 16 | import com.android.launcher3.widget.model.WidgetsListBaseEntry |
| 17 | import java.util.function.Predicate |
| 18 | |
| 19 | class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { |
Sebastian Franco | 69fd742 | 2023-10-06 16:48:58 -0700 | [diff] [blame] | 20 | |
| 21 | var synchronouslyBoundPages = LIntSet() |
| 22 | var pagesToBindSynchronously = LIntSet() |
| 23 | |
Sebastian Franco | bd7919c | 2023-09-19 10:55:37 -0700 | [diff] [blame] | 24 | 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 Franco | 69fd742 | 2023-10-06 16:48:58 -0700 | [diff] [blame] | 103 | |
| 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 Franco | 50b74c3 | 2023-11-16 11:36:49 -0600 | [diff] [blame^] | 139 | |
| 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 Franco | bd7919c | 2023-09-19 10:55:37 -0700 | [diff] [blame] | 169 | } |