1 /*
2  * Copyright (C) 2018 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.logging;
17 
18 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
19 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_DOWN;
20 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_OPEN_UP;
21 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
22 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
23 
24 import android.content.Context;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.launcher3.R;
29 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
30 import com.android.launcher3.logger.LauncherAtom.FromState;
31 import com.android.launcher3.logger.LauncherAtom.ToState;
32 import com.android.launcher3.model.data.ItemInfo;
33 import com.android.launcher3.userevent.LauncherLogProto;
34 import com.android.launcher3.util.ResourceBasedOverride;
35 
36 /**
37  * Handles the user event logging in R+.
38  * All of the event ids are defined here.
39  * Most of the methods are dummy methods for Launcher3
40  * Actual call happens only for Launcher variant that implements QuickStep.
41  */
42 public class StatsLogManager implements ResourceBasedOverride {
43 
44     public static final int LAUNCHER_STATE_UNSPECIFIED = 0;
45     public static final int LAUNCHER_STATE_BACKGROUND = 1;
46     public static final int LAUNCHER_STATE_HOME = 2;
47     public static final int LAUNCHER_STATE_OVERVIEW = 3;
48     public static final int LAUNCHER_STATE_ALLAPPS = 4;
49     public static final int LAUNCHER_STATE_UNCHANGED = 5;
50 
51     /**
52      * Returns proper launcher state enum for {@link StatsLogManager}
53      * (to be removed during UserEventDispatcher cleanup)
54      */
containerTypeToAtomState(int containerType)55     public static int containerTypeToAtomState(int containerType) {
56         switch (containerType) {
57             case LauncherLogProto.ContainerType.ALLAPPS_VALUE:
58                 return LAUNCHER_STATE_ALLAPPS;
59             case LauncherLogProto.ContainerType.OVERVIEW_VALUE:
60                 return LAUNCHER_STATE_OVERVIEW;
61             case LauncherLogProto.ContainerType.WORKSPACE_VALUE:
62                 return LAUNCHER_STATE_HOME;
63             case LauncherLogProto.ContainerType.APP_VALUE:
64                 return LAUNCHER_STATE_BACKGROUND;
65         }
66         return LAUNCHER_STATE_UNSPECIFIED;
67     }
68 
69     /**
70      * Returns event enum based on the two {@link ContainerType} transition information when
71      * swipe gesture happens.
72      * (to be removed during UserEventDispatcher cleanup)
73      */
getLauncherAtomEvent(int startContainerType, int targetContainerType, EventEnum fallbackEvent)74     public static EventEnum getLauncherAtomEvent(int startContainerType,
75             int targetContainerType, EventEnum fallbackEvent) {
76         if (startContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()
77                 && targetContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()) {
78             return LAUNCHER_HOME_GESTURE;
79         } else if (startContainerType != LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()
80                 && targetContainerType == LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()) {
81             return LAUNCHER_OVERVIEW_GESTURE;
82         } else if (startContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()
83                 && targetContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()) {
84             return LAUNCHER_ALLAPPS_OPEN_UP;
85         } else if (startContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()
86                 && targetContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()) {
87             return LAUNCHER_ALLAPPS_CLOSE_DOWN;
88         }
89         return fallbackEvent; // TODO fix
90     }
91 
92     public interface EventEnum {
getId()93         int getId();
94     }
95 
96     public enum LauncherEvent implements EventEnum {
97         /* Used to prevent double logging. */
98         IGNORE(-1),
99 
100         @UiEvent(doc = "App launched from workspace, hotseat or folder in launcher")
101         LAUNCHER_APP_LAUNCH_TAP(338),
102 
103         @UiEvent(doc = "Task launched from overview using TAP")
104         LAUNCHER_TASK_LAUNCH_TAP(339),
105 
106         @UiEvent(doc = "User tapped on notification inside popup context menu.")
107         LAUNCHER_NOTIFICATION_LAUNCH_TAP(516),
108 
109         @UiEvent(doc = "Task launched from overview using SWIPE DOWN")
110         LAUNCHER_TASK_LAUNCH_SWIPE_DOWN(340),
111 
112         @UiEvent(doc = "TASK dismissed from overview using SWIPE UP")
113         LAUNCHER_TASK_DISMISS_SWIPE_UP(341),
114 
115         @UiEvent(doc = "User dragged a launcher item")
116         LAUNCHER_ITEM_DRAG_STARTED(383),
117 
118         @UiEvent(doc = "A dragged launcher item is successfully dropped")
119         LAUNCHER_ITEM_DROP_COMPLETED(385),
120 
121         @UiEvent(doc = "A dragged launcher item is successfully dropped on another item "
122                 + "resulting in a new folder creation")
123         LAUNCHER_ITEM_DROP_FOLDER_CREATED(386),
124 
125         @UiEvent(doc = "Folder's label is automatically assigned.")
126         LAUNCHER_FOLDER_AUTO_LABELED(591),
127 
128         @UiEvent(doc = "Could not auto-label a folder because primary suggestion is null or empty.")
129         LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY(592),
130 
131         @UiEvent(doc = "Could not auto-label a folder because no suggestions exist.")
132         LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS(593),
133 
134         @UiEvent(doc = "User manually updated the folder label.")
135         LAUNCHER_FOLDER_LABEL_UPDATED(460),
136 
137         @UiEvent(doc = "User long pressed on the workspace empty space.")
138         LAUNCHER_WORKSPACE_LONGPRESS(461),
139 
140         @UiEvent(doc = "User tapped or long pressed on a wallpaper icon inside launcher settings.")
141         LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS(462),
142 
143         @UiEvent(doc = "User tapped or long pressed on settings icon inside launcher settings.")
144         LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS(463),
145 
146         @UiEvent(doc = "User tapped or long pressed on widget tray icon inside launcher settings.")
147         LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS(464),
148 
149         @UiEvent(doc = "A dragged item is dropped on 'Remove' button in the target bar")
150         LAUNCHER_ITEM_DROPPED_ON_REMOVE(465),
151 
152         @UiEvent(doc = "A dragged item is dropped on 'Cancel' button in the target bar")
153         LAUNCHER_ITEM_DROPPED_ON_CANCEL(466),
154 
155         @UiEvent(doc = "A predicted item is dragged and dropped on 'Don't suggest app'"
156                 + " button in the target bar")
157         LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST(467),
158 
159         @UiEvent(doc = "A dragged item is dropped on 'Uninstall' button in target bar")
160         LAUNCHER_ITEM_DROPPED_ON_UNINSTALL(468),
161 
162         @UiEvent(doc = "User completed uninstalling the package after dropping on "
163                 + "the icon onto 'Uninstall' button in the target bar")
164         LAUNCHER_ITEM_UNINSTALL_COMPLETED(469),
165 
166         @UiEvent(doc = "User cancelled uninstalling the package after dropping on "
167                 + "the icon onto 'Uninstall' button in the target bar")
168         LAUNCHER_ITEM_UNINSTALL_CANCELLED(470),
169 
170         @UiEvent(doc = "User tapped or long pressed on the task icon(aka package icon) "
171                 + "from overview to open task menu.")
172         LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS(517),
173 
174         @UiEvent(doc = "User opened package specific widgets list by tapping on widgets system "
175                 + "shortcut inside popup context menu.")
176         LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514),
177 
178         @UiEvent(doc = "User tapped on app info system shortcut.")
179         LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515),
180 
181         @UiEvent(doc = "User tapped on split screen icon on a task menu.")
182         LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP(518),
183 
184         @UiEvent(doc = "User tapped on free form icon on a task menu.")
185         LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519),
186 
187         @UiEvent(doc = "User tapped on pause app system shortcut.")
188         LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP(521),
189 
190         @UiEvent(doc = "User tapped on pin system shortcut.")
191         LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP(522),
192 
193         @UiEvent(doc = "User is shown All Apps education view.")
194         LAUNCHER_ALL_APPS_EDU_SHOWN(523),
195 
196         @UiEvent(doc = "User opened a folder.")
197         LAUNCHER_FOLDER_OPEN(551),
198 
199         @UiEvent(doc = "Hotseat education half sheet seen")
200         LAUNCHER_HOTSEAT_EDU_SEEN(479),
201 
202         @UiEvent(doc = "Hotseat migration accepted")
203         LAUNCHER_HOTSEAT_EDU_ACCEPT(480),
204 
205         @UiEvent(doc = "Hotseat migration denied")
206         LAUNCHER_HOTSEAT_EDU_DENY(481),
207 
208         @UiEvent(doc = "Hotseat education tip shown")
209         LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482),
210 
211         /**
212          * @deprecated LauncherUiChanged.rank field is repurposed to store all apps rank, so no
213          * separate event is required.
214          */
215         @Deprecated
216         @UiEvent(doc = "App launch ranking logged for all apps predictions")
217         LAUNCHER_ALL_APPS_RANKED(552),
218 
219         @UiEvent(doc = "App launch ranking logged for hotseat predictions)")
220         LAUNCHER_HOTSEAT_RANKED(553),
221         @UiEvent(doc = "Launcher is now in background. e.g., Screen off event")
222         LAUNCHER_ONSTOP(562),
223 
224         @UiEvent(doc = "Launcher is now in foreground. e.g., Screen on event, back button")
225         LAUNCHER_ONRESUME(563),
226 
227         @UiEvent(doc = "User swipes or fling in LEFT direction on workspace.")
228         LAUNCHER_SWIPELEFT(564),
229 
230         @UiEvent(doc = "User swipes or fling in RIGHT direction on workspace.")
231         LAUNCHER_SWIPERIGHT(565),
232 
233         @UiEvent(doc = "User swipes or fling in UP direction in unknown way.")
234         LAUNCHER_UNKNOWN_SWIPEUP(566),
235 
236         @UiEvent(doc = "User swipes or fling in DOWN direction in unknown way.")
237         LAUNCHER_UNKNOWN_SWIPEDOWN(567),
238 
239         @UiEvent(doc = "User swipes or fling in UP direction to open apps drawer.")
240         LAUNCHER_ALLAPPS_OPEN_UP(568),
241 
242         @UiEvent(doc = "User swipes or fling in DOWN direction to close apps drawer.")
243         LAUNCHER_ALLAPPS_CLOSE_DOWN(569),
244 
245         @UiEvent(doc = "User swipes or fling in UP direction and hold from the bottom bazel area")
246         LAUNCHER_OVERVIEW_GESTURE(570),
247 
248         @UiEvent(doc = "User swipes or fling in LEFT direction on the bottom bazel area.")
249         LAUNCHER_QUICKSWITCH_LEFT(571),
250 
251         @UiEvent(doc = "User swipes or fling in RIGHT direction on the bottom bazel area.")
252         LAUNCHER_QUICKSWITCH_RIGHT(572),
253 
254         @UiEvent(doc = "User swipes or fling in DOWN direction on the bottom bazel area.")
255         LAUNCHER_SWIPEDOWN_NAVBAR(573),
256 
257         @UiEvent(doc = "User swipes or fling in UP direction from bottom bazel area.")
258         LAUNCHER_HOME_GESTURE(574),
259 
260         @UiEvent(doc = "User's workspace layout information is snapshot in the background.")
261         LAUNCHER_WORKSPACE_SNAPSHOT(579),
262 
263         @UiEvent(doc = "User tapped on the screenshot button on overview)")
264         LAUNCHER_OVERVIEW_ACTIONS_SCREENSHOT(580),
265 
266         @UiEvent(doc = "User tapped on the select button on overview)")
267         LAUNCHER_OVERVIEW_ACTIONS_SELECT(581),
268 
269         @UiEvent(doc = "User tapped on the share button on overview")
270         LAUNCHER_OVERVIEW_ACTIONS_SHARE(582),
271 
272         @UiEvent(doc = "User tapped on the close button in select mode")
273         LAUNCHER_SELECT_MODE_CLOSE(583),
274 
275         @UiEvent(doc = "User tapped on the highlight items in select mode")
276         LAUNCHER_SELECT_MODE_ITEM(584);
277 
278         // ADD MORE
279 
280         private final int mId;
281 
LauncherEvent(int id)282         LauncherEvent(int id) {
283             mId = id;
284         }
285 
getId()286         public int getId() {
287             return mId;
288         }
289     }
290 
291     /**
292      * Launcher specific ranking related events.
293      */
294     public enum LauncherRankingEvent implements EventEnum {
295 
296         UNKNOWN(0);
297         // ADD MORE
298 
299         private final int mId;
300 
LauncherRankingEvent(int id)301         LauncherRankingEvent(int id) {
302             mId = id;
303         }
304 
getId()305         public int getId() {
306             return mId;
307         }
308     }
309 
310     /**
311      * Helps to construct and write the log message.
312      */
313     public interface StatsLogger {
314 
315         /**
316          * Sets log fields from provided {@link ItemInfo}.
317          */
withItemInfo(ItemInfo itemInfo)318         default StatsLogger withItemInfo(ItemInfo itemInfo) {
319             return this;
320         }
321 
322 
323         /**
324          * Sets {@link InstanceId} of log message.
325          */
withInstanceId(InstanceId instanceId)326         default StatsLogger withInstanceId(InstanceId instanceId) {
327             return this;
328         }
329 
330         /**
331          * Sets rank field of log message.
332          */
withRank(int rank)333         default StatsLogger withRank(int rank) {
334             return this;
335         }
336 
337         /**
338          * Sets source launcher state field of log message.
339          */
withSrcState(int srcState)340         default StatsLogger withSrcState(int srcState) {
341             return this;
342         }
343 
344         /**
345          * Sets destination launcher state field of log message.
346          */
withDstState(int dstState)347         default StatsLogger withDstState(int dstState) {
348             return this;
349         }
350 
351         /**
352          * Sets FromState field of log message.
353          */
withFromState(FromState fromState)354         default StatsLogger withFromState(FromState fromState) {
355             return this;
356         }
357 
358         /**
359          * Sets ToState field of log message.
360          */
withToState(ToState toState)361         default StatsLogger withToState(ToState toState) {
362             return this;
363         }
364 
365         /**
366          * Sets editText field of log message.
367          */
withEditText(String editText)368         default StatsLogger withEditText(String editText) {
369             return this;
370         }
371 
372         /**
373          * Sets the final value for container related fields of log message.
374          *
375          * By default container related fields are derived from {@link ItemInfo}, this method would
376          * override those values.
377          */
withContainerInfo(ContainerInfo containerInfo)378         default StatsLogger withContainerInfo(ContainerInfo containerInfo) {
379             return this;
380         }
381 
382         /**
383          * Builds the final message and logs it as {@link EventEnum}.
384          */
log(EventEnum event)385         default void log(EventEnum event) {
386         }
387     }
388 
389     /**
390      * Returns new logger object.
391      */
logger()392     public StatsLogger logger() {
393         return new StatsLogger() {
394         };
395     }
396 
397     /**
398      * Creates a new instance of {@link StatsLogManager} based on provided context.
399      */
newInstance(Context context)400     public static StatsLogManager newInstance(Context context) {
401         StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
402                 context.getApplicationContext(), R.string.stats_log_manager_class);
403         return mgr;
404     }
405 
406     /**
407      * Log an event with ranked-choice information along with package. Does nothing if event.getId()
408      * <= 0.
409      *
410      * @param rankingEvent an enum implementing EventEnum interface.
411      * @param instanceId An identifier obtained from an InstanceIdSequence.
412      * @param packageName the package name of the relevant app, if known (null otherwise).
413      * @param position the position picked.
414      */
log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName, int position)415     public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
416             int position) {
417     }
418 
419     /**
420      * Logs snapshot, or impression of the current workspace.
421      */
logSnapshot()422     public void logSnapshot() {
423     }
424 }
425