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.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE;
19 
20 import android.app.prediction.AppTarget;
21 import android.app.prediction.AppTargetEvent;
22 import android.app.prediction.AppTargetId;
23 import android.content.ComponentName;
24 import android.content.Context;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.launcher3.LauncherSettings;
29 import com.android.launcher3.Workspace;
30 import com.android.launcher3.logger.LauncherAtom;
31 import com.android.launcher3.model.data.ItemInfo;
32 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
33 import com.android.launcher3.model.data.WorkspaceItemInfo;
34 import com.android.launcher3.shortcuts.ShortcutKey;
35 
36 import java.util.Locale;
37 
38 /** Helper class with methods for converting launcher items to form usable by predictors */
39 public final class PredictionHelper {
40     private static final String APP_LOCATION_HOTSEAT = "hotseat";
41     private static final String APP_LOCATION_WORKSPACE = "workspace";
42 
43     /**
44      * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null
45      * if item type is not supported in predictions
46      */
47     @Nullable
getAppTargetFromItemInfo(Context context, ItemInfo info)48     public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) {
49         if (info == null) return null;
50         if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
51                 && info instanceof LauncherAppWidgetInfo
52                 && ((LauncherAppWidgetInfo) info).providerName != null) {
53             ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
54             return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
55                     cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
56         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
57                 && info.getTargetComponent() != null) {
58             ComponentName cn = info.getTargetComponent();
59             return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
60                     cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
61         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
62                 && info instanceof WorkspaceItemInfo) {
63             ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
64             //TODO: switch to using full shortcut info
65             return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
66                     shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
67         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
68             return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
69                     context.getPackageName(), info.user).build();
70         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR) {
71             return new AppTarget.Builder(new AppTargetId("app_pair:" + info.id),
72                     context.getPackageName(), info.user).build();
73         }
74         return null;
75     }
76 
77     /**
78      * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
79      * location using {@link ItemInfo}
80      */
wrapAppTargetWithItemLocation( AppTarget target, int action, ItemInfo info)81     public static AppTargetEvent wrapAppTargetWithItemLocation(
82             AppTarget target, int action, ItemInfo info) {
83         String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
84                 info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
85                         ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
86                 info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
87         return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
88     }
89 
90     /**
91      * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat
92      * predictors
93      */
isTrackedForHotseatPrediction(ItemInfo info)94     public static boolean isTrackedForHotseatPrediction(ItemInfo info) {
95         return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
96                 info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
97                         && info.screenId == Workspace.FIRST_SCREEN_ID);
98     }
99 
100     /**
101      * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to
102      * hotseat predictors
103      */
isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info)104     public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
105         LauncherAtom.ContainerInfo ci = info.getContainerInfo();
106         switch (ci.getContainerCase()) {
107             case HOTSEAT:
108                 return true;
109             case WORKSPACE:
110                 return ci.getWorkspace().getPageIndex() == 0;
111             default:
112                 return false;
113         }
114     }
115 
116     /**
117      * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget
118      * predictors
119      */
isTrackedForWidgetPrediction(ItemInfo info)120     public static boolean isTrackedForWidgetPrediction(ItemInfo info) {
121         return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
122                 && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP;
123     }
124 
125     /**
126      * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported
127      * to widget predictors
128      */
isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info)129     public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) {
130         return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET
131                 && info.getContainerInfo().getContainerCase() == WORKSPACE;
132     }
133 }
134