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