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.util.ArrayMap;
19 import android.util.SparseArray;
20 import android.view.View;
21 
22 import com.android.launcher3.ButtonDropTarget;
23 import com.android.launcher3.LauncherSettings;
24 import com.android.launcher3.model.data.AppInfo;
25 import com.android.launcher3.model.data.ItemInfo;
26 import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
27 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
28 import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
29 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
30 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
31 import com.android.launcher3.util.InstantAppResolver;
32 
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Modifier;
35 import java.util.ArrayList;
36 
37 /**
38  * Helper methods for logging.
39  */
40 public class LoggerUtils {
41     private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
42     private static final String UNKNOWN = "UNKNOWN";
43     private static final int DEFAULT_PREDICTED_RANK = 10000;
44     private static final String DELIMITER_DOT = "\\.";
45 
getFieldName(int value, Class c)46     public static String getFieldName(int value, Class c) {
47         SparseArray<String> cache;
48         synchronized (sNameCache) {
49             cache = sNameCache.get(c);
50             if (cache == null) {
51                 cache = new SparseArray<>();
52                 for (Field f : c.getDeclaredFields()) {
53                     if (f.getType() == int.class && Modifier.isStatic(f.getModifiers())) {
54                         try {
55                             f.setAccessible(true);
56                             cache.put(f.getInt(null), f.getName());
57                         } catch (IllegalAccessException e) {
58                             // Ignore
59                         }
60                     }
61                 }
62                 sNameCache.put(c, cache);
63             }
64         }
65         String result = cache.get(value);
66         return result != null ? result : UNKNOWN;
67     }
68 
newItemTarget(int itemType)69     public static Target newItemTarget(int itemType) {
70         Target t = newTarget(Target.Type.ITEM);
71         t.itemType = itemType;
72         return t;
73     }
74 
newItemTarget(View v, InstantAppResolver instantAppResolver)75     public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
76         return (v != null) && (v.getTag() instanceof ItemInfo)
77                 ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver)
78                 : newTarget(Target.Type.ITEM);
79     }
80 
newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver)81     public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
82         Target t = newTarget(Target.Type.ITEM);
83         switch (info.itemType) {
84             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
85                 t.itemType = (instantAppResolver != null && info instanceof AppInfo
86                         && instantAppResolver.isInstantApp(((AppInfo) info)))
87                         ? ItemType.WEB_APP
88                         : ItemType.APP_ICON;
89                 t.predictedRank = DEFAULT_PREDICTED_RANK;
90                 break;
91             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
92                 t.itemType = ItemType.SHORTCUT;
93                 t.predictedRank = DEFAULT_PREDICTED_RANK;
94                 break;
95             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
96                 t.itemType = ItemType.FOLDER_ICON;
97                 break;
98             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
99                 t.itemType = ItemType.WIDGET;
100                 break;
101             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
102                 t.itemType = ItemType.DEEPSHORTCUT;
103                 t.predictedRank = DEFAULT_PREDICTED_RANK;
104                 break;
105         }
106         return t;
107     }
108 
newDropTarget(View v)109     public static Target newDropTarget(View v) {
110         if (!(v instanceof ButtonDropTarget)) {
111             return newTarget(Target.Type.CONTAINER);
112         }
113         if (v instanceof ButtonDropTarget) {
114             return ((ButtonDropTarget) v).getDropTargetForLogging();
115         }
116         return newTarget(Target.Type.CONTROL);
117     }
118 
newTarget(int targetType, TargetExtension extension)119     public static Target newTarget(int targetType, TargetExtension extension) {
120         Target t = new Target();
121         t.type = targetType;
122         t.extension = extension;
123         return t;
124     }
125 
newTarget(int targetType)126     public static Target newTarget(int targetType) {
127         Target t = new Target();
128         t.type = targetType;
129         return t;
130     }
131 
newControlTarget(int controlType)132     public static Target newControlTarget(int controlType) {
133         Target t = newTarget(Target.Type.CONTROL);
134         t.controlType = controlType;
135         return t;
136     }
137 
newContainerTarget(int containerType)138     public static Target newContainerTarget(int containerType) {
139         Target t = newTarget(Target.Type.CONTAINER);
140         t.containerType = containerType;
141         return t;
142     }
143 
newAction(int type)144     public static Action newAction(int type) {
145         Action a = new Action();
146         a.type = type;
147         return a;
148     }
149 
newCommandAction(int command)150     public static Action newCommandAction(int command) {
151         Action a = newAction(Action.Type.COMMAND);
152         a.command = command;
153         return a;
154     }
155 
newTouchAction(int touch)156     public static Action newTouchAction(int touch) {
157         Action a = newAction(Action.Type.TOUCH);
158         a.touch = touch;
159         return a;
160     }
161 
newLauncherEvent(Action action, Target... srcTargets)162     public static LauncherEvent newLauncherEvent(Action action, Target... srcTargets) {
163         LauncherEvent event = new LauncherEvent();
164         event.srcTarget = srcTargets;
165         event.action = action;
166         return event;
167     }
168 
169     /**
170      * Creates LauncherEvent using Action and ArrayList of Targets
171      */
newLauncherEvent(Action action, ArrayList<Target> targets)172     public static LauncherEvent newLauncherEvent(Action action, ArrayList<Target> targets) {
173         Target[] targetsArray = new Target[targets.size()];
174         targets.toArray(targetsArray);
175         return newLauncherEvent(action, targetsArray);
176     }
177 
178     /**
179      * String conversion for only the helpful parts of {@link Object#toString()} method
180      * @param stringToExtract "foo.bar.baz.MyObject@1234"
181      * @return "MyObject@1234"
182      */
extractObjectNameAndAddress(String stringToExtract)183     public static String extractObjectNameAndAddress(String stringToExtract) {
184         String[] superStringParts = stringToExtract.split(DELIMITER_DOT);
185         if (superStringParts.length == 0) {
186             return "";
187         }
188         return superStringParts[superStringParts.length - 1];
189     }
190 }
191