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.model; 17 18 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; 19 20 import android.app.prediction.AppTarget; 21 import android.text.TextUtils; 22 23 import androidx.annotation.NonNull; 24 25 import com.android.launcher3.LauncherAppState; 26 import com.android.launcher3.model.BgDataModel.FixedContainerItems; 27 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState; 28 import com.android.launcher3.model.data.ItemInfo; 29 import com.android.launcher3.util.ComponentKey; 30 import com.android.launcher3.util.PackageUserKey; 31 import com.android.launcher3.widget.PendingAddWidgetInfo; 32 33 import java.util.ArrayList; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.function.Predicate; 38 import java.util.stream.Collectors; 39 40 /** Task to update model as a result of predicted widgets update */ 41 public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask { 42 private final PredictorState mPredictorState; 43 private final List<AppTarget> mTargets; 44 WidgetsPredictionUpdateTask(PredictorState predictorState, List<AppTarget> targets)45 WidgetsPredictionUpdateTask(PredictorState predictorState, List<AppTarget> targets) { 46 mPredictorState = predictorState; 47 mTargets = targets; 48 } 49 50 /** 51 * Uses the app predication result to infer widgets that the user may want to use. 52 * 53 * <p>The algorithm uses the app prediction ranking to create a widgets ranking which only 54 * includes one widget per app and excludes widgets that have already been added to the 55 * workspace. 56 */ 57 @Override execute(@onNull final LauncherAppState appState, @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps)58 public void execute(@NonNull final LauncherAppState appState, 59 @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) { 60 Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map( 61 widget -> new ComponentKey(widget.providerName, widget.user)).collect( 62 Collectors.toSet()); 63 Predicate<WidgetItem> notOnWorkspace = w -> !widgetsInWorkspace.contains(w); 64 Map<PackageUserKey, List<WidgetItem>> allWidgets = 65 dataModel.widgetsModel.getAllWidgetsWithoutShortcuts(); 66 67 List<WidgetItem> servicePredictedItems = new ArrayList<>(); 68 List<WidgetItem> localFilteredWidgets = new ArrayList<>(); 69 70 for (AppTarget app : mTargets) { 71 PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(), app.getUser()); 72 List<WidgetItem> widgets = allWidgets.get(packageUserKey); 73 if (widgets == null || widgets.isEmpty()) { 74 continue; 75 } 76 String className = app.getClassName(); 77 if (!TextUtils.isEmpty(className)) { 78 WidgetItem item = widgets.stream() 79 .filter(w -> className.equals(w.componentName.getClassName())) 80 .filter(notOnWorkspace) 81 .findFirst() 82 .orElse(null); 83 if (item != null) { 84 servicePredictedItems.add(item); 85 continue; 86 } 87 } 88 // No widget was added by the service, try local filtering 89 widgets.stream().filter(notOnWorkspace).findFirst() 90 .ifPresent(localFilteredWidgets::add); 91 } 92 if (servicePredictedItems.isEmpty()) { 93 servicePredictedItems.addAll(localFilteredWidgets); 94 } 95 96 List<ItemInfo> items = servicePredictedItems.stream() 97 .map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION)) 98 .collect(Collectors.toList()); 99 FixedContainerItems fixedContainerItems = 100 new FixedContainerItems(mPredictorState.containerId, items); 101 102 dataModel.extraItems.put(mPredictorState.containerId, fixedContainerItems); 103 bindExtraContainerItems(fixedContainerItems); 104 105 // Don't store widgets prediction to disk because it is not used frequently. 106 } 107 } 108