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