f7c2adf861
Make sure that the ArrayList cannot be cleared on the model thread while it is being used on the UI thread to render a launcher preview. Test: Manual Fix: 210123588 Change-Id: I5a47cb3f28f5ac9e400f6ae535e410c345e14ee1
109 lines
4.9 KiB
Java
109 lines
4.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.model;
|
|
|
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
|
|
|
|
import android.app.prediction.AppTarget;
|
|
import android.content.ComponentName;
|
|
import android.text.TextUtils;
|
|
|
|
import com.android.launcher3.LauncherAppState;
|
|
import com.android.launcher3.config.FeatureFlags;
|
|
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
|
|
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
|
|
import com.android.launcher3.util.ComponentKey;
|
|
import com.android.launcher3.util.PackageUserKey;
|
|
import com.android.launcher3.widget.PendingAddWidgetInfo;
|
|
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
|
|
/** Task to update model as a result of predicted widgets update */
|
|
public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask {
|
|
private final PredictorState mPredictorState;
|
|
private final List<AppTarget> mTargets;
|
|
|
|
WidgetsPredictionUpdateTask(PredictorState predictorState, List<AppTarget> targets) {
|
|
mPredictorState = predictorState;
|
|
mTargets = targets;
|
|
}
|
|
|
|
/**
|
|
* Uses the app predication result to infer widgets that the user may want to use.
|
|
*
|
|
* <p>The algorithm uses the app prediction ranking to create a widgets ranking which only
|
|
* includes one widget per app and excludes widgets that have already been added to the
|
|
* workspace.
|
|
*/
|
|
@Override
|
|
public void execute(LauncherAppState appState, BgDataModel dataModel, AllAppsList apps) {
|
|
Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map(
|
|
widget -> new ComponentKey(widget.providerName, widget.user)).collect(
|
|
Collectors.toSet());
|
|
Map<PackageUserKey, List<WidgetItem>> allWidgets =
|
|
dataModel.widgetsModel.getAllWidgetsWithoutShortcuts();
|
|
|
|
FixedContainerItems fixedContainerItems =
|
|
new FixedContainerItems(mPredictorState.containerId);
|
|
|
|
if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) {
|
|
for (AppTarget app : mTargets) {
|
|
PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(),
|
|
app.getUser());
|
|
if (allWidgets.containsKey(packageUserKey)) {
|
|
List<WidgetItem> notAddedWidgets = allWidgets.get(packageUserKey).stream()
|
|
.filter(item ->
|
|
!widgetsInWorkspace.contains(
|
|
new ComponentKey(item.componentName, item.user)))
|
|
.collect(Collectors.toList());
|
|
if (notAddedWidgets.size() > 0) {
|
|
// Even an apps have more than one widgets, we only include one widget.
|
|
fixedContainerItems.items.add(
|
|
new PendingAddWidgetInfo(
|
|
notAddedWidgets.get(0).widgetInfo,
|
|
CONTAINER_WIDGETS_PREDICTION));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Map<ComponentKey, WidgetItem> widgetItems =
|
|
allWidgets.values().stream().flatMap(List::stream).distinct()
|
|
.collect(Collectors.toMap(widget -> (ComponentKey) widget,
|
|
widget -> widget));
|
|
for (AppTarget app : mTargets) {
|
|
if (TextUtils.isEmpty(app.getClassName())) {
|
|
continue;
|
|
}
|
|
ComponentKey targetWidget = new ComponentKey(
|
|
new ComponentName(app.getPackageName(), app.getClassName()), app.getUser());
|
|
if (widgetItems.containsKey(targetWidget)) {
|
|
fixedContainerItems.items.add(
|
|
new PendingAddWidgetInfo(widgetItems.get(
|
|
targetWidget).widgetInfo,
|
|
CONTAINER_WIDGETS_PREDICTION));
|
|
}
|
|
}
|
|
}
|
|
dataModel.extraItems.put(mPredictorState.containerId, fixedContainerItems);
|
|
bindExtraContainerItems(fixedContainerItems);
|
|
|
|
// Don't store widgets prediction to disk because it is not used frequently.
|
|
}
|
|
}
|