/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.taskbar; import android.util.SparseArray; import android.view.View; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LauncherBindableItemsContainer; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.function.Predicate; /** * Launcher model Callbacks for rendering taskbar. */ public class TaskbarModelCallbacks implements BgDataModel.Callbacks, LauncherBindableItemsContainer { private final SparseArray mHotseatItems = new SparseArray<>(); private List mPredictedItems = Collections.emptyList(); private final TaskbarActivityContext mContext; private final TaskbarView mContainer; // Initialized in init. private TaskbarControllers mControllers; public TaskbarModelCallbacks( TaskbarActivityContext context, TaskbarView container) { mContext = context; mContainer = container; } public void init(TaskbarControllers controllers) { mControllers = controllers; } @Override public void startBinding() { mContext.setBindingItems(true); mHotseatItems.clear(); mPredictedItems = Collections.emptyList(); } @Override public void finishBindingItems(IntSet pagesBoundFirst) { mContext.setBindingItems(false); commitItemsToUI(); } @Override public void bindAppsAdded(IntArray newScreens, ArrayList addNotAnimated, ArrayList addAnimated) { boolean add1 = handleItemsAdded(addNotAnimated); boolean add2 = handleItemsAdded(addAnimated); if (add1 || add2) { commitItemsToUI(); } } @Override public void bindItems(List shortcuts, boolean forceAnimateIcons) { if (handleItemsAdded(shortcuts)) { commitItemsToUI(); } } private boolean handleItemsAdded(List items) { boolean modified = false; for (ItemInfo item : items) { if (item.container == Favorites.CONTAINER_HOTSEAT) { mHotseatItems.put(item.screenId, item); modified = true; } } return modified; } @Override public void bindWorkspaceItemsChanged(List updated) { updateWorkspaceItems(updated, mContext); } @Override public void bindRestoreItemsChange(HashSet updates) { updateRestoreItems(updates, mContext); } @Override public void mapOverItems(ItemOperator op) { final int itemCount = mContainer.getChildCount(); for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { View item = mContainer.getChildAt(itemIdx); if (op.evaluate((ItemInfo) item.getTag(), item)) { return; } } } @Override public void bindWorkspaceComponentsRemoved(Predicate matcher) { if (handleItemsRemoved(matcher)) { commitItemsToUI(); } } private boolean handleItemsRemoved(Predicate matcher) { boolean modified = false; for (int i = mHotseatItems.size() - 1; i >= 0; i--) { if (matcher.test(mHotseatItems.valueAt(i))) { modified = true; mHotseatItems.removeAt(i); } } return modified; } @Override public void bindItemsModified(List items) { boolean removed = handleItemsRemoved(ItemInfoMatcher.ofItems(items)); boolean added = handleItemsAdded(items); if (removed || added) { commitItemsToUI(); } } @Override public void bindExtraContainerItems(FixedContainerItems item) { if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) { mPredictedItems = item.items; commitItemsToUI(); } else if (item.containerId == Favorites.CONTAINER_PREDICTION) { mControllers.taskbarAllAppsController.setPredictedApps(item.items); } } private void commitItemsToUI() { if (mContext.isBindingItems()) { return; } ItemInfo[] hotseatItemInfos = new ItemInfo[mContext.getDeviceProfile().numShownHotseatIcons]; int predictionSize = mPredictedItems.size(); int predictionNextIndex = 0; boolean isHotseatEmpty = true; for (int i = 0; i < hotseatItemInfos.length; i++) { hotseatItemInfos[i] = mHotseatItems.get(i); if (hotseatItemInfos[i] == null && predictionNextIndex < predictionSize) { hotseatItemInfos[i] = mPredictedItems.get(predictionNextIndex); hotseatItemInfos[i].screenId = i; predictionNextIndex++; } if (hotseatItemInfos[i] != null) { isHotseatEmpty = false; } } mContainer.updateHotseatItems(hotseatItemInfos); final boolean finalIsHotseatEmpty = isHotseatEmpty; mControllers.runAfterInit(() -> { mControllers.taskbarStashController.updateStateForFlag( TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty); mControllers.taskbarStashController.applyState(); }); } @Override public void bindDeepShortcutMap(HashMap deepShortcutMapCopy) { mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy); } @Override public void bindAllApplications(AppInfo[] apps, int flags) { mControllers.taskbarAllAppsController.setApps(apps, flags); } protected void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarModelCallbacks:"); pw.println(String.format("%s\thotseat items count=%s", prefix, mHotseatItems.size())); if (mPredictedItems != null) { pw.println( String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size())); } } }