diff options
author | Hyunyoung Song <hyunyoungs@google.com> | 2017-02-06 10:46:24 -0800 |
---|---|---|
committer | Hyunyoung Song <hyunyoungs@google.com> | 2017-04-04 23:06:30 +0000 |
commit | e295acaeb34c474430e68cbfb069a6a6bfea4041 (patch) | |
tree | 7575140da81484b2897ad165da8debd51a986eab /src | |
parent | ca18746163621211847a2f184d19a6b3e2b4a1c0 (diff) | |
download | android_packages_apps_Trebuchet-e295acaeb34c474430e68cbfb069a6a6bfea4041.tar.gz android_packages_apps_Trebuchet-e295acaeb34c474430e68cbfb069a6a6bfea4041.tar.bz2 android_packages_apps_Trebuchet-e295acaeb34c474430e68cbfb069a6a6bfea4041.zip |
Launcher dump proto that will be used for:
$ adb shell dumpsys activity provider com.android.launcher3/com.android.launcher3.LauncherProvider
To see how the proto is filled: go/launcher-proto-dump
b/31772480
Change-Id: I8e0f1e5e38148a3dfeabd2fc057392193b2625dd
(cherry picked from commit 6aa3729e98502d4cffc40a7e602628b85d558edd)
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherProvider.java | 15 | ||||
-rw-r--r-- | src/com/android/launcher3/logging/DumpTargetWrapper.java | 149 | ||||
-rw-r--r-- | src/com/android/launcher3/logging/LoggerUtils.java | 33 | ||||
-rw-r--r-- | src/com/android/launcher3/model/BgDataModel.java | 108 |
5 files changed, 299 insertions, 11 deletions
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 5a41eeb1f..8e99d47d0 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -127,6 +127,11 @@ public class LauncherModel extends BroadcastReceiver // our monitoring of the package manager provides all updates and we never // need to do a requery. This is only ever touched from the loader thread. private boolean mModelLoaded; + public boolean isModelLoaded() { + synchronized (mLock) { + return mModelLoaded && mLoaderTask == null; + } + } /** * Set of runnables to be called on the background thread after the workspace binding diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 4771649d5..65d76728d 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -47,6 +47,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.Log; +import android.view.ViewGroup; import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; import com.android.launcher3.LauncherSettings.Favorites; @@ -64,6 +65,8 @@ import com.android.launcher3.util.NoLocaleSqliteContext; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Thunk; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; @@ -86,6 +89,18 @@ public class LauncherProvider extends ContentProvider { protected DatabaseHelper mOpenHelper; + /** + * $ adb shell dumpsys activity provider com.android.launcher3 + */ + @Override + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); + if (appState == null || !appState.getModel().isModelLoaded()) { + return; + } + appState.getModel().dumpState("", fd, writer, args); + } + @Override public boolean onCreate() { if (ProviderConfig.IS_DOGFOOD_BUILD) { diff --git a/src/com/android/launcher3/logging/DumpTargetWrapper.java b/src/com/android/launcher3/logging/DumpTargetWrapper.java new file mode 100644 index 000000000..2646a2242 --- /dev/null +++ b/src/com/android/launcher3/logging/DumpTargetWrapper.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.logging; + +import android.os.Process; +import android.text.TextUtils; + +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.model.nano.LauncherDumpProto; +import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType; +import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget; +import com.android.launcher3.model.nano.LauncherDumpProto.ItemType; +import com.android.launcher3.model.nano.LauncherDumpProto.UserType; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class can be used when proto definition doesn't support nesting. + */ +public class DumpTargetWrapper { + DumpTarget node; + ArrayList<DumpTargetWrapper> children; + + public DumpTargetWrapper() { + children = new ArrayList<>(); + } + + public DumpTargetWrapper(DumpTarget t) { + this(); + node = t; + } + + public DumpTargetWrapper(int containerType, int id) { + this(); + node = newContainerTarget(containerType, id); + } + + public DumpTargetWrapper(ItemInfo info) { + this(); + node = newItemTarget(info); + } + + public DumpTarget getDumpTarget() { + return node; + } + + public void add(DumpTargetWrapper child) { + children.add(child); + } + + public List<DumpTarget> getFlattenedList() { + ArrayList<DumpTarget> list = new ArrayList<>(); + list.add(node); + if (!children.isEmpty()) { + for(DumpTargetWrapper t: children) { + list.addAll(t.getFlattenedList()); + } + list.add(node); // add a delimiter empty object + } + return list; + } + public DumpTarget newItemTarget(ItemInfo info) { + DumpTarget dt = new DumpTarget(); + dt.type = DumpTarget.Type.ITEM; + + switch (info.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + dt.itemType = ItemType.APP_ICON; + break; + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + dt.itemType = ItemType.UNKNOWN_ITEMTYPE; + break; + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + dt.itemType = ItemType.WIDGET; + break; + case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + dt.itemType = ItemType.SHORTCUT; + break; + } + return dt; + } + + public DumpTarget newContainerTarget(int type, int id) { + DumpTarget dt = new DumpTarget(); + dt.type = DumpTarget.Type.CONTAINER; + dt.containerType = type; + dt.pageId = id; + return dt; + } + + public static String getDumpTargetStr(DumpTarget t) { + if (t == null){ + return ""; + } + switch (t.type) { + case LauncherDumpProto.DumpTarget.Type.ITEM: + return getItemStr(t); + case LauncherDumpProto.DumpTarget.Type.CONTAINER: + String str = LoggerUtils.getFieldName(t.containerType, ContainerType.class); + if (t.containerType == ContainerType.WORKSPACE) { + str += " id=" + t.pageId; + } else if (t.containerType == ContainerType.FOLDER) { + str += " grid(" + t.gridX + "," + t.gridY+ ")"; + } + return str; + default: + return "UNKNOWN TARGET TYPE"; + } + } + + private static String getItemStr(DumpTarget t) { + String typeStr = LoggerUtils.getFieldName(t.itemType, ItemType.class); + if (!TextUtils.isEmpty(t.packageName)) { + typeStr += ", package=" + t.packageName; + } + if (!TextUtils.isEmpty(t.component)) { + typeStr += ", component=" + t.component; + } + return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY + + "), pageIdx=" + t.pageId + " user=" + t.userType; + } + + public DumpTarget writeToDumpTarget(ItemInfo info) { + node.component = info.getTargetComponent() == null? "": + info.getTargetComponent().flattenToString(); + node.packageName = info.getIntent() == null? "": info.getIntent().getPackage(); + node.gridX = info.cellX; + node.gridY = info.cellY; + node.spanX = info.spanX; + node.spanY = info.spanY; + node.userType = (info.user.equals(Process.myUserHandle()))? UserType.DEFAULT : UserType.WORK; + return node; + } +} diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java index c13e8b336..499fdc7d3 100644 --- a/src/com/android/launcher3/logging/LoggerUtils.java +++ b/src/com/android/launcher3/logging/LoggerUtils.java @@ -1,5 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.launcher3.logging; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.SparseArray; import android.view.View; @@ -27,7 +43,7 @@ public class LoggerUtils { private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>(); private static final String UNKNOWN = "UNKNOWN"; - private static String getFieldName(int value, Class c) { + public static String getFieldName(int value, Class c) { SparseArray<String> cache; synchronized (sNameCache) { cache = sNameCache.get(c); @@ -68,8 +84,13 @@ public class LoggerUtils { case Target.Type.CONTROL: return getFieldName(t.controlType, ControlType.class); case Target.Type.CONTAINER: - return getFieldName(t.containerType, ContainerType.class) - + " id=" + t.pageIndex; + String str = getFieldName(t.containerType, ContainerType.class); + if (t.containerType == ContainerType.WORKSPACE) { + str += " id=" + t.pageIndex; + } else if (t.containerType == ContainerType.FOLDER) { + str += " grid(" + t.gridX + "," + t.gridY+ ")"; + } + return str; default: return "UNKNOWN TARGET TYPE"; } @@ -86,10 +107,8 @@ public class LoggerUtils { if (t.intentHash != 0) { typeStr += ", intentHash=" + t.intentHash; } - if (t.spanX != 0) { - typeStr += ", spanX=" + t.spanX; - } - return typeStr + ", grid=(" + t.gridX + "," + t.gridY + "), id=" + t.pageIndex; + return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY + + "), pageIdx=" + t.pageIndex; } public static Target newItemTarget(View v) { diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 6b64087a2..0e73ca6d3 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -24,19 +24,27 @@ import android.util.MutableInt; import com.android.launcher3.FolderInfo; import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.config.ProviderConfig; +import com.android.launcher3.logging.LoggerUtils; +import com.android.launcher3.logging.DumpTargetWrapper; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.model.nano.LauncherDumpProto; +import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType; +import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget; +import com.android.launcher3.model.nano.LauncherDumpProto.ItemType; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.MultiHashMap; +import com.google.protobuf.nano.MessageNano; import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -102,21 +110,31 @@ public class BgDataModel { deepShortcutMap.clear(); } - // TODO: current dump is very cryptic and hard to understand. Make it more legible. - public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer, + String[] args) { + if (args.length > 0 && TextUtils.equals(args[0], "--proto")) { + dumpProto(prefix, fd, writer, args); + return; + } writer.println(prefix + "Data Model:"); + writer.print(prefix + " ---- workspace screens: "); for (int i = 0; i < workspaceScreens.size(); i++) { - writer.println(prefix + "\tIndex of workspaceScreens:" + workspaceScreens.get(i).toString()); + writer.print(" " + workspaceScreens.get(i).toString()); } + writer.println(); + writer.println(prefix + " ---- workspace items "); for (int i = 0; i < workspaceItems.size(); i++) { writer.println(prefix + '\t' + workspaceItems.get(i).toString()); } + writer.println(prefix + " ---- appwidget items "); for (int i = 0; i < appWidgets.size(); i++) { writer.println(prefix + '\t' + appWidgets.get(i).toString()); } + writer.println(prefix + " ---- folder items "); for (int i = 0; i< folders.size(); i++) { writer.println(prefix + '\t' + folders.valueAt(i).toString()); } + writer.println(prefix + " ---- items id map "); for (int i = 0; i< itemsIdMap.size(); i++) { writer.println(prefix + '\t' + itemsIdMap.valueAt(i).toString()); } @@ -133,6 +151,88 @@ public class BgDataModel { } } + private synchronized void dumpProto(String prefix, FileDescriptor fd, PrintWriter writer, + String[] args) { + + // Add top parent nodes. (L1) + DumpTargetWrapper hotseat = new DumpTargetWrapper(ContainerType.HOTSEAT, 0); + LongArrayMap<DumpTargetWrapper> workspaces = new LongArrayMap<>(); + for (int i = 0; i < workspaceScreens.size(); i++) { + workspaces.put(new Long(workspaceScreens.get(i)), + new DumpTargetWrapper(ContainerType.WORKSPACE, i)); + } + DumpTargetWrapper dtw; + // Add non leaf / non top nodes (L2) + for (int i = 0; i < folders.size(); i++) { + FolderInfo fInfo = folders.valueAt(i); + dtw = new DumpTargetWrapper(ContainerType.FOLDER, folders.size()); + dtw.writeToDumpTarget(fInfo); + for(ShortcutInfo sInfo: fInfo.contents) { + DumpTargetWrapper child = new DumpTargetWrapper(sInfo); + child.writeToDumpTarget(sInfo); + dtw.add(child); + } + if (fInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + hotseat.add(dtw); + } else if (fInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + workspaces.get(new Long(fInfo.screenId)).add(dtw); + } + } + // Add leaf nodes (L3): *Info + for (int i = 0; i < workspaceItems.size(); i++) { + ItemInfo info = workspaceItems.get(i); + if (info instanceof FolderInfo) { + continue; + } + dtw = new DumpTargetWrapper(info); + dtw.writeToDumpTarget(info); + if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + hotseat.add(dtw); + } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + workspaces.get(new Long(info.screenId)).add(dtw); + } + } + for (int i = 0; i < appWidgets.size(); i++) { + ItemInfo info = appWidgets.get(i); + dtw = new DumpTargetWrapper(info); + dtw.writeToDumpTarget(info); + if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + hotseat.add(dtw); + } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + workspaces.get(new Long(info.screenId)).add(dtw); + } + } + + + // Traverse target wrapper + ArrayList<DumpTarget> targetList = new ArrayList<>(); + targetList.addAll(hotseat.getFlattenedList()); + for (int i = 0; i < workspaces.size(); i++) { + targetList.addAll(workspaces.valueAt(i).getFlattenedList()); + } + + if (args.length > 1 && TextUtils.equals(args[1], "--debug")) { + for (int i = 0; i < targetList.size(); i++) { + writer.println(prefix + DumpTargetWrapper.getDumpTargetStr(targetList.get(i))); + } + return; + } else { + LauncherDumpProto.LauncherImpression proto = new LauncherDumpProto.LauncherImpression(); + proto.targets = new DumpTarget[targetList.size()]; + for (int i = 0; i < targetList.size(); i++) { + proto.targets[i] = targetList.get(i); + } + FileOutputStream fos = new FileOutputStream(fd); + try { + + fos.write(MessageNano.toByteArray(proto)); + Log.d(TAG, MessageNano.toByteArray(proto).length + "Bytes"); + } catch (IOException e) { + Log.e(TAG, "Exception writing dumpsys --proto", e); + } + } + } + public synchronized void removeItem(Context context, ItemInfo... items) { removeItem(context, Arrays.asList(items)); } |