Fixes an issue where hotseatItems may not reflect the number of hotseat views in Taskbar. Entries in the array can be null (e.g. no predictions but there is space in the hotseat for them). If these are filtered out immediately, hotseatItems.length will correspond to the number of hotseat views. Test: go/testedequals Flag: EXEMPT bugfix Fix: 379704910 Change-Id: I375d8152fccb6df5a9b783842ecf5dcedf6894c1
262 lines
8.9 KiB
Java
262 lines
8.9 KiB
Java
/*
|
|
* 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 androidx.annotation.UiThread;
|
|
|
|
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 com.android.launcher3.util.PackageUserKey;
|
|
import com.android.launcher3.util.Preconditions;
|
|
import com.android.quickstep.util.GroupTask;
|
|
|
|
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.Map;
|
|
import java.util.function.Predicate;
|
|
|
|
/**
|
|
* Launcher model Callbacks for rendering taskbar.
|
|
*/
|
|
public class TaskbarModelCallbacks implements
|
|
BgDataModel.Callbacks, LauncherBindableItemsContainer {
|
|
|
|
private final SparseArray<ItemInfo> mHotseatItems = new SparseArray<>();
|
|
private List<ItemInfo> mPredictedItems = Collections.emptyList();
|
|
|
|
private final TaskbarActivityContext mContext;
|
|
private final TaskbarView mContainer;
|
|
|
|
// Initialized in init.
|
|
protected TaskbarControllers mControllers;
|
|
|
|
// Used to defer any UI updates during the SUW unstash animation.
|
|
private boolean mDeferUpdatesForSUW;
|
|
private Runnable mDeferredUpdates;
|
|
|
|
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<ItemInfo> addNotAnimated,
|
|
ArrayList<ItemInfo> addAnimated) {
|
|
boolean add1 = handleItemsAdded(addNotAnimated);
|
|
boolean add2 = handleItemsAdded(addAnimated);
|
|
if (add1 || add2) {
|
|
commitItemsToUI();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) {
|
|
if (handleItemsAdded(shortcuts)) {
|
|
commitItemsToUI();
|
|
}
|
|
}
|
|
|
|
private boolean handleItemsAdded(List<ItemInfo> 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<WorkspaceItemInfo> updated) {
|
|
updateWorkspaceItems(updated, mContext);
|
|
}
|
|
|
|
@Override
|
|
public void bindRestoreItemsChange(HashSet<ItemInfo> 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 (item.getTag() instanceof ItemInfo itemInfo && op.evaluate(itemInfo, item)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
|
|
if (handleItemsRemoved(matcher)) {
|
|
commitItemsToUI();
|
|
}
|
|
}
|
|
|
|
private boolean handleItemsRemoved(Predicate<ItemInfo> 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<ItemInfo> 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;
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
final TaskbarRecentAppsController recentAppsController =
|
|
mControllers.taskbarRecentAppsController;
|
|
hotseatItemInfos = recentAppsController.updateHotseatItemInfos(hotseatItemInfos);
|
|
|
|
if (mDeferUpdatesForSUW) {
|
|
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
|
|
mDeferredUpdates = () ->
|
|
commitHotseatItemUpdates(finalHotseatItemInfos,
|
|
recentAppsController.getShownTasks());
|
|
} else {
|
|
commitHotseatItemUpdates(hotseatItemInfos, recentAppsController.getShownTasks());
|
|
}
|
|
}
|
|
|
|
private void commitHotseatItemUpdates(
|
|
ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
|
|
mContainer.updateItems(hotseatItemInfos, recentTasks);
|
|
mControllers.taskbarViewController.updateIconViewsRunningStates();
|
|
}
|
|
|
|
/**
|
|
* This is used to defer UI updates after SUW builds the unstash animation.
|
|
* @param defer if true, defers updates to the UI
|
|
* if false, posts updates (if any) to the UI
|
|
*/
|
|
public void setDeferUpdatesForSUW(boolean defer) {
|
|
mDeferUpdatesForSUW = defer;
|
|
|
|
if (!mDeferUpdatesForSUW) {
|
|
if (mDeferredUpdates != null) {
|
|
mContainer.post(mDeferredUpdates);
|
|
mDeferredUpdates = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Called when there's a change in running apps to update the UI. */
|
|
public void commitRunningAppsToUI() {
|
|
commitItemsToUI();
|
|
}
|
|
|
|
@Override
|
|
public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
|
|
mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
|
|
}
|
|
|
|
@UiThread
|
|
@Override
|
|
public void bindAllApplications(AppInfo[] apps, int flags,
|
|
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
|
|
Preconditions.assertUIThread();
|
|
mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
|
|
mControllers.taskbarPopupController.setApps(apps);
|
|
}
|
|
|
|
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()));
|
|
}
|
|
pw.println(String.format("%s\tmDeferUpdatesForSUW=%b", prefix, mDeferUpdatesForSUW));
|
|
pw.println(String.format("%s\tupdates pending=%b", prefix, (mDeferredUpdates != null)));
|
|
}
|
|
}
|