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.content.ComponentName; 22 import android.text.TextUtils; 23 24 import com.android.launcher3.LauncherAppState; 25 import com.android.launcher3.config.FeatureFlags; 26 import com.android.launcher3.model.BgDataModel.FixedContainerItems; 27 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState; 28 import com.android.launcher3.util.ComponentKey; 29 import com.android.launcher3.util.PackageUserKey; 30 import com.android.launcher3.widget.PendingAddWidgetInfo; 31 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Set; 35 import java.util.stream.Collectors; 36 37 /** Task to update model as a result of predicted widgets update */ 38 public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask { 39 private final PredictorState mPredictorState; 40 private final List<AppTarget> mTargets; 41 WidgetsPredictionUpdateTask(PredictorState predictorState, List<AppTarget> targets)42 WidgetsPredictionUpdateTask(PredictorState predictorState, List<AppTarget> targets) { 43 mPredictorState = predictorState; 44 mTargets = targets; 45 } 46 47 /** 48 * Uses the app predication result to infer widgets that the user may want to use. 49 * 50 * <p>The algorithm uses the app prediction ranking to create a widgets ranking which only 51 * includes one widget per app and excludes widgets that have already been added to the 52 * workspace. 53 */ 54 @Override execute(LauncherAppState appState, BgDataModel dataModel, AllAppsList apps)55 public void execute(LauncherAppState appState, BgDataModel dataModel, AllAppsList apps) { 56 Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map( 57 widget -> new ComponentKey(widget.providerName, widget.user)).collect( 58 Collectors.toSet()); 59 Map<PackageUserKey, List<WidgetItem>> allWidgets = 60 dataModel.widgetsModel.getAllWidgetsWithoutShortcuts(); 61 62 FixedContainerItems fixedContainerItems = mPredictorState.items; 63 fixedContainerItems.items.clear(); 64 65 if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) { 66 for (AppTarget app : mTargets) { 67 PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(), 68 app.getUser()); 69 if (allWidgets.containsKey(packageUserKey)) { 70 List<WidgetItem> notAddedWidgets = allWidgets.get(packageUserKey).stream() 71 .filter(item -> 72 !widgetsInWorkspace.contains( 73 new ComponentKey(item.componentName, item.user))) 74 .collect(Collectors.toList()); 75 if (notAddedWidgets.size() > 0) { 76 // Even an apps have more than one widgets, we only include one widget. 77 fixedContainerItems.items.add( 78 new PendingAddWidgetInfo( 79 notAddedWidgets.get(0).widgetInfo, 80 CONTAINER_WIDGETS_PREDICTION)); 81 } 82 } 83 } 84 } else { 85 Map<ComponentKey, WidgetItem> widgetItems = 86 allWidgets.values().stream().flatMap(List::stream).distinct() 87 .collect(Collectors.toMap(widget -> (ComponentKey) widget, 88 widget -> widget)); 89 for (AppTarget app : mTargets) { 90 if (TextUtils.isEmpty(app.getClassName())) { 91 continue; 92 } 93 ComponentKey targetWidget = new ComponentKey( 94 new ComponentName(app.getPackageName(), app.getClassName()), app.getUser()); 95 if (widgetItems.containsKey(targetWidget)) { 96 fixedContainerItems.items.add( 97 new PendingAddWidgetInfo(widgetItems.get( 98 targetWidget).widgetInfo, 99 CONTAINER_WIDGETS_PREDICTION)); 100 } 101 } 102 } 103 bindExtraContainerItems(fixedContainerItems); 104 105 // Don't store widgets prediction to disk because it is not used frequently. 106 } 107 } 108