1 /*
2  * Copyright (C) 2016 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.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;
19 
20 import android.util.ArrayMap;
21 import android.util.SparseArray;
22 import android.view.View;
23 
24 import com.android.launcher3.AppInfo;
25 import com.android.launcher3.ButtonDropTarget;
26 import com.android.launcher3.ItemInfo;
27 import com.android.launcher3.LauncherSettings;
28 import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
29 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
30 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
31 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
32 import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
33 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
34 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
35 import com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
36 import com.android.launcher3.util.InstantAppResolver;
37 
38 import java.lang.reflect.Field;
39 import java.lang.reflect.Modifier;
40 
41 /**
42  * Helper methods for logging.
43  */
44 public class LoggerUtils {
45     private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
46     private static final String UNKNOWN = "UNKNOWN";
47     private static final int DEFAULT_PREDICTED_RANK = -100;
48 
getFieldName(int value, Class c)49     public static String getFieldName(int value, Class c) {
50         SparseArray<String> cache;
51         synchronized (sNameCache) {
52             cache = sNameCache.get(c);
53             if (cache == null) {
54                 cache = new SparseArray<>();
55                 for (Field f : c.getDeclaredFields()) {
56                     if (f.getType() == int.class && Modifier.isStatic(f.getModifiers())) {
57                         try {
58                             f.setAccessible(true);
59                             cache.put(f.getInt(null), f.getName());
60                         } catch (IllegalAccessException e) {
61                             // Ignore
62                         }
63                     }
64                 }
65                 sNameCache.put(c, cache);
66             }
67         }
68         String result = cache.get(value);
69         return result != null ? result : UNKNOWN;
70     }
71 
getActionStr(Action action)72     public static String getActionStr(Action action) {
73         String str = "";
74         switch (action.type) {
75             case Action.Type.TOUCH:
76                 str += getFieldName(action.touch, Action.Touch.class);
77                 if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING) {
78                     str += " direction=" + getFieldName(action.dir, Action.Direction.class);
79                 }
80                 break;
81             case Action.Type.COMMAND:
82                 str += getFieldName(action.command, Action.Command.class);
83                 break;
84             default: return getFieldName(action.type, Action.Type.class);
85         }
86         if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING ||
87                 (action.command == Action.Command.BACK && action.dir != Action.Direction.NONE)) {
88             str += " direction=" + getFieldName(action.dir, Action.Direction.class);
89         }
90         return str;
91     }
92 
getTargetStr(Target t)93     public static String getTargetStr(Target t) {
94         if (t == null) {
95             return "";
96         }
97         String str = "";
98         switch (t.type) {
99             case Target.Type.ITEM:
100                 str = getItemStr(t);
101                 break;
102             case Target.Type.CONTROL:
103                 str = getFieldName(t.controlType, ControlType.class);
104                 break;
105             case Target.Type.CONTAINER:
106                 str = getFieldName(t.containerType, ContainerType.class);
107                 if (t.containerType == ContainerType.WORKSPACE ||
108                         t.containerType == ContainerType.HOTSEAT ||
109                         t.containerType == NAVBAR) {
110                     str += " id=" + t.pageIndex;
111                 } else if (t.containerType == ContainerType.FOLDER) {
112                     str += "[PageIndex=" + t.pageIndex + ", grid(" + t.gridX + "," + t.gridY + ")]";
113                 }
114                 break;
115             default:
116                 str += "UNKNOWN TARGET TYPE";
117         }
118 
119         if (t.spanX != 1 || t.spanY != 1) {
120             str += " span(" + t.spanX + "," + t.spanY + ")";
121         }
122 
123         if (t.tipType != TipType.DEFAULT_NONE) {
124             str += " " + getFieldName(t.tipType, TipType.class);
125         }
126 
127         return str;
128     }
129 
getItemStr(Target t)130     private static String getItemStr(Target t) {
131         String typeStr = getFieldName(t.itemType, ItemType.class);
132         if (t.packageNameHash != 0) {
133             typeStr += ", packageHash=" + t.packageNameHash;
134         }
135         if (t.componentHash != 0) {
136             typeStr += ", componentHash=" + t.componentHash;
137         }
138         if (t.intentHash != 0) {
139             typeStr += ", intentHash=" + t.intentHash;
140         }
141         if (t.itemType == ItemType.FOLDER_ICON) {
142             typeStr += ", grid(" + t.gridX + "," + t.gridY + ")";
143         } else if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0)
144                 && t.itemType != ItemType.TASK) {
145             typeStr += ", predictiveRank=" + t.predictedRank + ", grid(" + t.gridX + "," + t.gridY
146                     + "), span(" + t.spanX + "," + t.spanY + "), pageIdx=" + t.pageIndex;
147         }
148         if (t.searchQueryLength != 0) {
149             typeStr += ", searchQueryLength=" + t.searchQueryLength;
150         }
151         if (t.itemType == ItemType.TASK) {
152             typeStr += ", pageIdx=" + t.pageIndex;
153         }
154         return typeStr;
155     }
156 
newItemTarget(int itemType)157     public static Target newItemTarget(int itemType) {
158         Target t = newTarget(Target.Type.ITEM);
159         t.itemType = itemType;
160         return t;
161     }
162 
newItemTarget(View v, InstantAppResolver instantAppResolver)163     public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
164         return (v != null) && (v.getTag() instanceof ItemInfo)
165                 ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver)
166                 : newTarget(Target.Type.ITEM);
167     }
168 
newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver)169     public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
170         Target t = newTarget(Target.Type.ITEM);
171         switch (info.itemType) {
172             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
173                 t.itemType = (instantAppResolver != null && info instanceof AppInfo
174                         && instantAppResolver.isInstantApp(((AppInfo) info)))
175                         ? ItemType.WEB_APP
176                         : ItemType.APP_ICON;
177                 t.predictedRank = DEFAULT_PREDICTED_RANK;
178                 break;
179             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
180                 t.itemType = ItemType.SHORTCUT;
181                 t.predictedRank = DEFAULT_PREDICTED_RANK;
182                 break;
183             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
184                 t.itemType = ItemType.FOLDER_ICON;
185                 break;
186             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
187                 t.itemType = ItemType.WIDGET;
188                 break;
189             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
190                 t.itemType = ItemType.DEEPSHORTCUT;
191                 t.predictedRank = DEFAULT_PREDICTED_RANK;
192                 break;
193         }
194         return t;
195     }
196 
newDropTarget(View v)197     public static Target newDropTarget(View v) {
198         if (!(v instanceof ButtonDropTarget)) {
199             return newTarget(Target.Type.CONTAINER);
200         }
201         if (v instanceof ButtonDropTarget) {
202             return ((ButtonDropTarget) v).getDropTargetForLogging();
203         }
204         return newTarget(Target.Type.CONTROL);
205     }
206 
newTarget(int targetType, TargetExtension extension)207     public static Target newTarget(int targetType, TargetExtension extension) {
208         Target t = new Target();
209         t.type = targetType;
210         t.extension = extension;
211         return t;
212     }
213 
newTarget(int targetType)214     public static Target newTarget(int targetType) {
215         Target t = new Target();
216         t.type = targetType;
217         return t;
218     }
219 
newControlTarget(int controlType)220     public static Target newControlTarget(int controlType) {
221         Target t = newTarget(Target.Type.CONTROL);
222         t.controlType = controlType;
223         return t;
224     }
225 
newContainerTarget(int containerType)226     public static Target newContainerTarget(int containerType) {
227         Target t = newTarget(Target.Type.CONTAINER);
228         t.containerType = containerType;
229         return t;
230     }
231 
newAction(int type)232     public static Action newAction(int type) {
233         Action a = new Action();
234         a.type = type;
235         return a;
236     }
237 
newCommandAction(int command)238     public static Action newCommandAction(int command) {
239         Action a = newAction(Action.Type.COMMAND);
240         a.command = command;
241         return a;
242     }
243 
newTouchAction(int touch)244     public static Action newTouchAction(int touch) {
245         Action a = newAction(Action.Type.TOUCH);
246         a.touch = touch;
247         return a;
248     }
249 
newLauncherEvent(Action action, Target... srcTargets)250     public static LauncherEvent newLauncherEvent(Action action, Target... srcTargets) {
251         LauncherEvent event = new LauncherEvent();
252         event.srcTarget = srcTargets;
253         event.action = action;
254         return event;
255     }
256 }
257