1 /* 2 * Copyright (C) 2021 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.taskbar; 17 18 import android.util.SparseArray; 19 import android.view.View; 20 21 import com.android.launcher3.LauncherSettings.Favorites; 22 import com.android.launcher3.model.BgDataModel; 23 import com.android.launcher3.model.BgDataModel.FixedContainerItems; 24 import com.android.launcher3.model.data.ItemInfo; 25 import com.android.launcher3.model.data.WorkspaceItemInfo; 26 import com.android.launcher3.util.ComponentKey; 27 import com.android.launcher3.util.IntArray; 28 import com.android.launcher3.util.IntSet; 29 import com.android.launcher3.util.ItemInfoMatcher; 30 import com.android.launcher3.util.LauncherBindableItemsContainer; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.HashSet; 36 import java.util.List; 37 38 /** 39 * Launcher model Callbacks for rendering taskbar. 40 */ 41 public class TaskbarModelCallbacks implements 42 BgDataModel.Callbacks, LauncherBindableItemsContainer { 43 44 private final SparseArray<ItemInfo> mHotseatItems = new SparseArray<>(); 45 private List<ItemInfo> mPredictedItems = Collections.emptyList(); 46 47 private final TaskbarActivityContext mContext; 48 private final TaskbarView mContainer; 49 50 // Initialized in init. 51 private TaskbarControllers mControllers; 52 53 private boolean mBindInProgress = false; 54 TaskbarModelCallbacks( TaskbarActivityContext context, TaskbarView container)55 public TaskbarModelCallbacks( 56 TaskbarActivityContext context, TaskbarView container) { 57 mContext = context; 58 mContainer = container; 59 } 60 init(TaskbarControllers controllers)61 public void init(TaskbarControllers controllers) { 62 mControllers = controllers; 63 } 64 65 @Override startBinding()66 public void startBinding() { 67 mBindInProgress = true; 68 mHotseatItems.clear(); 69 mPredictedItems = Collections.emptyList(); 70 } 71 72 @Override finishBindingItems(IntSet pagesBoundFirst)73 public void finishBindingItems(IntSet pagesBoundFirst) { 74 mBindInProgress = false; 75 commitItemsToUI(); 76 } 77 78 @Override bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated)79 public void bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated, 80 ArrayList<ItemInfo> addAnimated) { 81 boolean add1 = handleItemsAdded(addNotAnimated); 82 boolean add2 = handleItemsAdded(addAnimated); 83 if (add1 || add2) { 84 commitItemsToUI(); 85 } 86 } 87 88 @Override bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons)89 public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) { 90 if (handleItemsAdded(shortcuts)) { 91 commitItemsToUI(); 92 } 93 } 94 handleItemsAdded(List<ItemInfo> items)95 private boolean handleItemsAdded(List<ItemInfo> items) { 96 boolean modified = false; 97 for (ItemInfo item : items) { 98 if (item.container == Favorites.CONTAINER_HOTSEAT) { 99 mHotseatItems.put(item.screenId, item); 100 modified = true; 101 } 102 } 103 return modified; 104 } 105 106 107 @Override bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated)108 public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { 109 updateWorkspaceItems(updated, mContext); 110 } 111 112 @Override bindRestoreItemsChange(HashSet<ItemInfo> updates)113 public void bindRestoreItemsChange(HashSet<ItemInfo> updates) { 114 updateRestoreItems(updates, mContext); 115 } 116 117 @Override mapOverItems(ItemOperator op)118 public void mapOverItems(ItemOperator op) { 119 final int itemCount = mContainer.getChildCount(); 120 for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { 121 View item = mContainer.getChildAt(itemIdx); 122 if (op.evaluate((ItemInfo) item.getTag(), item)) { 123 return; 124 } 125 } 126 } 127 128 @Override bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher)129 public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { 130 if (handleItemsRemoved(matcher)) { 131 commitItemsToUI(); 132 } 133 } 134 handleItemsRemoved(ItemInfoMatcher matcher)135 private boolean handleItemsRemoved(ItemInfoMatcher matcher) { 136 boolean modified = false; 137 for (int i = mHotseatItems.size() - 1; i >= 0; i--) { 138 if (matcher.matchesInfo(mHotseatItems.valueAt(i))) { 139 modified = true; 140 mHotseatItems.removeAt(i); 141 } 142 } 143 return modified; 144 } 145 146 @Override bindItemsModified(List<ItemInfo> items)147 public void bindItemsModified(List<ItemInfo> items) { 148 boolean removed = handleItemsRemoved(ItemInfoMatcher.ofItems(items)); 149 boolean added = handleItemsAdded(items); 150 if (removed || added) { 151 commitItemsToUI(); 152 } 153 } 154 155 @Override bindExtraContainerItems(FixedContainerItems item)156 public void bindExtraContainerItems(FixedContainerItems item) { 157 if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) { 158 mPredictedItems = item.items; 159 commitItemsToUI(); 160 } 161 } 162 commitItemsToUI()163 private void commitItemsToUI() { 164 if (mBindInProgress) { 165 return; 166 } 167 168 ItemInfo[] hotseatItemInfos = 169 new ItemInfo[mContext.getDeviceProfile().numShownHotseatIcons]; 170 int predictionSize = mPredictedItems.size(); 171 int predictionNextIndex = 0; 172 173 boolean isHotseatEmpty = true; 174 for (int i = 0; i < hotseatItemInfos.length; i++) { 175 hotseatItemInfos[i] = mHotseatItems.get(i); 176 if (hotseatItemInfos[i] == null && predictionNextIndex < predictionSize) { 177 hotseatItemInfos[i] = mPredictedItems.get(predictionNextIndex); 178 hotseatItemInfos[i].screenId = i; 179 predictionNextIndex++; 180 } 181 if (hotseatItemInfos[i] != null) { 182 isHotseatEmpty = false; 183 } 184 } 185 mContainer.updateHotseatItems(hotseatItemInfos); 186 187 final boolean finalIsHotseatEmpty = isHotseatEmpty; 188 mControllers.runAfterInit(() -> { 189 mControllers.taskbarStashController.updateStateForFlag( 190 TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty); 191 mControllers.taskbarStashController.applyState(); 192 }); 193 } 194 195 @Override bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy)196 public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) { 197 mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy); 198 } 199 } 200