• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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