From 7ac0ef1cb1c3499a1fe36ce25838798e57562a2f Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 26 Mar 2020 01:48:24 -0700 Subject: [PATCH] ItemInfo supports lite proto builder (1/n) Bug: 144953948 Bug: 137777105 The new lite proto builder is used to send two types of logging to statsd 1) Snapshot logging 2) App launch, task launch, task dismiss Statsd will be connected once platform CL is submitted Change-Id: If606cee5288fe4bd6c522605ae84eb0f24174f5b --- protos/launcher_atom.proto | 108 ++++++++ .../android/quickstep/views/RecentsView.java | 18 +- .../com/android/quickstep/views/TaskView.java | 18 +- .../logging/StatsLogCompatManager.java | 241 ++++-------------- .../launcher3/BaseDraggingActivity.java | 3 +- src/com/android/launcher3/ItemInfo.java | 78 ++++++ .../launcher3/LauncherAppWidgetInfo.java | 14 +- src/com/android/launcher3/Workspace.java | 2 - .../launcher3/logging/LauncherUiEvent.java | 30 +++ .../launcher3/logging/StatsLogManager.java | 48 +++- .../android/launcher3/model/LoaderCursor.java | 4 + 11 files changed, 343 insertions(+), 221 deletions(-) create mode 100644 protos/launcher_atom.proto create mode 100644 src/com/android/launcher3/logging/LauncherUiEvent.java diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto new file mode 100644 index 0000000000..a89fe5c594 --- /dev/null +++ b/protos/launcher_atom.proto @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 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. + */ +syntax = "proto2"; + +option java_package = "com.android.launcher3.logger"; +option java_outer_classname = "LauncherAtom"; + +// +// ItemInfos +message ItemInfo { + oneof Item { + Application application = 1; + Task task= 2; + Shortcut shortcut = 3; + Widget widget = 4; + } + // When used for launch event, stores the global predictive rank + optional int32 rank = 5; + + // Stores whether the Item belows to non primary user + optional bool is_work = 6; + + // Item can be child node to parent container or parent containers (nested) + oneof Container { + WorkspaceContainer workspace = 7; + HotseatContainer hotseat = 8; + FolderContainer folder = 9; + } + // Stores the origin of the Item + optional Origin source = 10; +} + +enum Origin { + UNKNOWN = 0; + DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat + BACKUP_RESTORE = 2; // icon layout restored from backup + PINITEM = 3; // from another app (e.g., Chrome's "Add to Home screen") + ALLAPPS_ATOZ = 4; // within launcher surface, all aps a-z + WIDGETS = 5; // within launcher, widgets tray + ADD_TO_HOMESCREEN = 6; // play install + launcher home setting + ALLAPPS_PREDICTION = 7; // from prediction bar in all apps container + HOTSEAT_PREDICTION = 8; // from prediction bar in hotseat container +} + +// Main app icons +message Application { + optional string package_name = 1; + optional string component_name = 2; +} + +// Legacy shortcuts and shortcuts handled by ShortcutManager +message Shortcut { + optional string shortcut_name = 1; +} + +// AppWidgets handled by AppWidgetManager +message Widget { + optional int32 span_x = 1; + optional int32 span_y = 2; + optional int32 app_widget_id = 3; + optional string package_name = 4; // only populated during snapshot if from workspace + optional string component_name = 5; // only populated during snapshot if from workspace +} + +// Tasks handled by PackageManager +message Task { + optional string package_name = 1; + optional string component_name = 2; + optional int32 index = 3; +} + +////////////////////////////////////////////// +// Containers + +message WorkspaceContainer { + optional int32 page_index = 1; // range [-1, l], 0 is the index of the main homescreen + optional int32 grid_x = 2; // [0, m], m varies based on the display density and resolution + optional int32 grid_y = 3; // [0, n], n varies based on the display density and resolution +} + +message HotseatContainer { + optional int32 index = 1; +} + +message FolderContainer { + optional int32 page_index = 1; + optional int32 grid_x = 2; + optional int32 grid_y = 3; + oneof Container { + WorkspaceContainer workspace = 4; + HotseatContainer hotseat = 5; + } +} + + diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 57a9940925..1c95a9ef77 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -30,6 +30,8 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN; import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; @@ -1183,13 +1185,13 @@ public abstract class RecentsView extends PagedView impl verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp); } - private void removeTask(Task task, int index, EndState endState) { - if (task != null) { - ActivityManagerWrapper.getInstance().removeTask(task.key.id); - ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key); + private void removeTask(TaskView taskView, int index, EndState endState) { + if (taskView.getTask() != null) { + ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id); + ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key); mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( - endState.logAction, Direction.UP, index, componentKey); - mActivity.getStatsLogManager().logTaskDismiss(this, componentKey); + endState.logAction, Direction.UP, index, compKey); + mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto()); } } @@ -1284,7 +1286,7 @@ public abstract class RecentsView extends PagedView impl private void onEnd(EndState endState) { if (endState.isSuccess) { if (shouldRemoveTask) { - removeTask(taskView.getTask(), draggedIndex, endState); + removeTask(taskView, draggedIndex, endState); } int pageToSnapTo = mCurrentPage; @@ -1733,6 +1735,8 @@ public abstract class RecentsView extends PagedView impl mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( endState.logAction, Direction.DOWN, indexOfChild(tv), TaskUtils.getLaunchComponentKeyForTask(task.key)); + mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto() + ); } } else { onTaskLaunched(false); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 56e3632dcd..8160aaebbd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -29,6 +29,7 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -43,6 +44,7 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; +import android.os.Process; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; @@ -59,6 +61,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.states.RotationHelper; @@ -68,6 +71,7 @@ import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ViewPool.Reusable; import com.android.quickstep.RecentsModel; import com.android.quickstep.TaskIconCache; @@ -217,8 +221,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this), TaskUtils.getLaunchComponentKeyForTask(getTask().key)); - mActivity.getStatsLogManager().logTaskLaunch(getRecentsView(), - TaskUtils.getLaunchComponentKeyForTask(getTask().key)); + mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto()); }); mCornerRadius = TaskCornerRadius.get(context); mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources()); @@ -229,6 +232,17 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { setOutlineProvider(mOutlineProvider); } + /* Builds proto for logging */ + protected LauncherAtom.ItemInfo buildProto() { + ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key); + LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder(); + itemBuilder.setIsWork(componentKey.user != Process.myUserHandle()); + itemBuilder.setTask(LauncherAtom.Task.newBuilder() + .setComponentName(componentKey.componentName.flattenToShortString()) + .setIndex(getRecentsView().indexOfChild(this))); + return itemBuilder.build(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 22fe2e13eb..58bb980ab6 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -18,36 +18,22 @@ package com.android.quickstep.logging; import static android.stats.launcher.nano.Launcher.ALLAPPS; import static android.stats.launcher.nano.Launcher.BACKGROUND; -import static android.stats.launcher.nano.Launcher.DISMISS_TASK; import static android.stats.launcher.nano.Launcher.HOME; -import static android.stats.launcher.nano.Launcher.LAUNCH_APP; -import static android.stats.launcher.nano.Launcher.LAUNCH_TASK; import static android.stats.launcher.nano.Launcher.OVERVIEW; -import static com.android.launcher3.logging.UserEventDispatcher.makeTargetsList; - import android.content.Context; -import android.content.Intent; -import android.os.UserHandle; -import android.stats.launcher.nano.Launcher; -import android.stats.launcher.nano.LauncherExtension; -import android.stats.launcher.nano.LauncherTarget; -import android.util.Log; -import android.view.View; - -import androidx.annotation.Nullable; +import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogUtils; -import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; -import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; -import com.android.launcher3.userevent.nano.LauncherLogProto.Target; -import com.android.launcher3.util.ComponentKey; -import com.android.systemui.shared.system.SysUiStatsLog; - -import com.google.protobuf.nano.MessageNano; +import com.android.launcher3.model.AllAppsList; +import com.android.launcher3.model.BaseModelUpdateTask; +import com.android.launcher3.model.BgDataModel; +import com.android.launcher3.util.IntSparseArrayMap; import java.util.ArrayList; @@ -62,186 +48,17 @@ import java.util.ArrayList; public class StatsLogCompatManager extends StatsLogManager { private static final int SUPPORTED_TARGET_DEPTH = 2; - private static final String TAG = "StatsLogCompatManager"; + private static final String TAG = "StatsLog"; private static final boolean DEBUG = false; + private static Context sContext; public StatsLogCompatManager(Context context) { + sContext = context; } @Override - public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) { - LauncherExtension ext = new LauncherExtension(); - ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; - int srcState = mStateProvider.getCurrentState(); - fillInLauncherExtension(v, ext); - if (ext.srcTarget[0] != null) { - ext.srcTarget[0].item = LauncherTarget.APP_ICON; - } - SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_APP, srcState, - BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true); - } - - @Override - public void logTaskLaunch(View v, ComponentKey componentKey) { - LauncherExtension ext = new LauncherExtension(); - ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; - int srcState = OVERVIEW; - fillInLauncherExtension(v, ext); - SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_TASK, srcState, - BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true); - } - - @Override - public void logTaskDismiss(View v, ComponentKey componentKey) { - LauncherExtension ext = new LauncherExtension(); - ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; - int srcState = OVERVIEW; - fillInLauncherExtension(v, ext); - SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, DISMISS_TASK, srcState, - BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true); - } - - @Override - public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { - LauncherExtension ext = new LauncherExtension(); - ext.srcTarget = new LauncherTarget[1]; - int srcState = mStateProvider.getCurrentState(); - fillInLauncherExtensionWithPageId(ext, pageId); - int launcherAction = isSwipingToLeft ? Launcher.SWIPE_LEFT : Launcher.SWIPE_RIGHT; - SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, launcherAction, srcState, srcState, - MessageNano.toByteArray(ext), true); - } - - public static boolean fillInLauncherExtension(View v, LauncherExtension extension) { - if (DEBUG) { - Log.d(TAG, "fillInLauncherExtension"); - } - - StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v); - if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) { - if (DEBUG) { - Log.d(TAG, "View or provider is null, or view doesn't have an ItemInfo tag."); - } - - return false; - } - Target child = new Target(); - ArrayList targets = makeTargetsList(child); - targets.add(child); - provider.fillInLogContainerData((ItemInfo) v.getTag(), child, targets); - - int maxDepth = Math.min(SUPPORTED_TARGET_DEPTH, targets.size()); - extension.srcTarget = new LauncherTarget[maxDepth]; - for (int i = 0; i < maxDepth; i++) { - extension.srcTarget[i] = new LauncherTarget(); - copy(targets.get(i), extension.srcTarget[i]); - } - return true; - } - - public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) { - if (DEBUG) { - Log.d(TAG, "fillInLauncherExtensionWithPageId, pageId = " + pageId); - } - - Target target = new Target(); - target.pageIndex = pageId; - ext.srcTarget[0] = new LauncherTarget(); - copy(target, ext.srcTarget[0]); - return true; - } - - private static void copy(Target src, LauncherTarget dst) { - if (DEBUG) { - Log.d(TAG, "copy target information from clearcut Target to LauncherTarget."); - } - - // Fill in type - switch (src.type) { - case Target.Type.ITEM: - dst.type = LauncherTarget.ITEM_TYPE; - break; - case Target.Type.CONTROL: - dst.type = LauncherTarget.CONTROL_TYPE; - break; - case Target.Type.CONTAINER: - dst.type = LauncherTarget.CONTAINER_TYPE; - break; - default: - dst.type = LauncherTarget.NONE; - break; - } - - // Fill in item - switch (src.itemType) { - case ItemType.APP_ICON: - dst.item = LauncherTarget.APP_ICON; - break; - case ItemType.SHORTCUT: - dst.item = LauncherTarget.SHORTCUT; - break; - case ItemType.WIDGET: - dst.item = LauncherTarget.WIDGET; - break; - case ItemType.FOLDER_ICON: - dst.item = LauncherTarget.FOLDER_ICON; - break; - case ItemType.DEEPSHORTCUT: - dst.item = LauncherTarget.DEEPSHORTCUT; - break; - case ItemType.SEARCHBOX: - dst.item = LauncherTarget.SEARCHBOX; - break; - case ItemType.EDITTEXT: - dst.item = LauncherTarget.EDITTEXT; - break; - case ItemType.NOTIFICATION: - dst.item = LauncherTarget.NOTIFICATION; - break; - case ItemType.TASK: - dst.item = LauncherTarget.TASK; - break; - default: - dst.item = LauncherTarget.DEFAULT_ITEM; - break; - } - - // Fill in container - switch (src.containerType) { - case ContainerType.HOTSEAT: - dst.container = LauncherTarget.HOTSEAT; - break; - case ContainerType.FOLDER: - dst.container = LauncherTarget.FOLDER; - break; - case ContainerType.PREDICTION: - dst.container = LauncherTarget.PREDICTION; - break; - case ContainerType.SEARCHRESULT: - dst.container = LauncherTarget.SEARCHRESULT; - break; - default: - dst.container = LauncherTarget.DEFAULT_CONTAINER; - break; - } - - // Fill in control - switch (src.controlType) { - case ControlType.UNINSTALL_TARGET: - dst.control = LauncherTarget.UNINSTALL; - break; - case ControlType.REMOVE_TARGET: - dst.control = LauncherTarget.REMOVE; - break; - default: - dst.control = LauncherTarget.DEFAULT_CONTROL; - break; - } - - // Fill in other fields - dst.pageId = src.pageIndex; - dst.gridX = src.gridX; - dst.gridY = src.gridY; + public void log(LauncherEvent eventId, LauncherAtom.ItemInfo item) { + // Call StatsLog method } @Override @@ -254,4 +71,36 @@ public class StatsLogCompatManager extends StatsLogManager { "StatsLogUtil constants doesn't match enums in launcher.proto"); } } + + /** + * Logs the workspace layout information on the model thread. + */ + public void logSnapshot() { + LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask( + new SnapshotWorker()); + } + + private class SnapshotWorker extends BaseModelUpdateTask { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { + IntSparseArrayMap folders = dataModel.folders.clone(); + ArrayList workspaceItems = (ArrayList) dataModel.workspaceItems.clone(); + ArrayList appWidgets = (ArrayList) dataModel.appWidgets.clone(); + + for (ItemInfo info : workspaceItems) { + LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null); + // call StatsLog method + } + for (FolderInfo fInfo : folders) { + for (ItemInfo info : fInfo.contents) { + LauncherAtom.ItemInfo atomInfo = info.buildProto(null, fInfo); + // call StatsLog method + } + } + for (ItemInfo info : appWidgets) { + LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null); + // call StatsLog method + } + } + } } diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 9f3b48f78c..6fa3c28b21 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP; import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION; import android.app.ActivityOptions; @@ -181,7 +182,7 @@ public abstract class BaseDraggingActivity extends BaseActivity sourceContainer); } getUserEventDispatcher().logAppLaunch(v, intent, user); - getStatsLogManager().logAppLaunch(v, intent, user); + getStatsLogManager().log(APP_LAUNCH_TAP, item.buildProto(null, null)); return true; } catch (NullPointerException|ActivityNotFoundException|SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index c99465c77c..8c4e4a0946 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -16,6 +16,13 @@ package com.android.launcher3; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + import android.content.ComponentName; import android.content.ContentValues; import android.content.Intent; @@ -24,13 +31,17 @@ import android.os.UserHandle; import androidx.annotation.Nullable; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.util.ContentWriter; + + /** * Represents an item in the launcher. */ public class ItemInfo { + public static final boolean DEBUG = true; public static final int NO_ID = -1; /** @@ -190,6 +201,7 @@ public class ItemInfo { return "id=" + id + " type=" + LauncherSettings.Favorites.itemTypeToString(itemType) + " container=" + LauncherSettings.Favorites.containerToString((int)container) + + " targetComponent=" + getTargetComponent() + " screen=" + screenId + " cell(" + cellX + "," + cellY + ")" + " span(" + spanX + "," + spanY + ")" @@ -221,4 +233,70 @@ public class ItemInfo { return container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION || container == LauncherSettings.Favorites.CONTAINER_PREDICTION; } + + /** + * Can be overridden by inherited classes to fill in {@link LauncherAtom.ItemInfo} + */ + public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) { + } + + /** + * Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info. + */ + public LauncherAtom.ItemInfo buildProto(Intent intent, FolderInfo fInfo) { + + LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder(); + itemBuilder.setIsWork(user != Process.myUserHandle()); + ComponentName cn = getTargetComponent(); + switch (itemType) { + case ITEM_TYPE_APPLICATION: + itemBuilder.setApplication(LauncherAtom.Application.newBuilder() + .setComponentName(cn.flattenToShortString()) + .setPackageName(cn.getPackageName())); + break; + case ITEM_TYPE_DEEP_SHORTCUT: + case ITEM_TYPE_SHORTCUT: + itemBuilder.setShortcut(LauncherAtom.Shortcut.newBuilder() + .setShortcutName(cn.flattenToShortString())); + break; + case ITEM_TYPE_APPWIDGET: + setItemBuilder(itemBuilder); + break; + default: + break; + + } + if (fInfo != null) { + LauncherAtom.FolderContainer.Builder folderBuilder = + LauncherAtom.FolderContainer.newBuilder(); + folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId); + + switch (fInfo.container) { + case CONTAINER_HOTSEAT: + folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder() + .setIndex(fInfo.screenId)); + break; + case CONTAINER_DESKTOP: + folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder() + .setPageIndex(fInfo.screenId) + .setGridX(fInfo.cellX).setGridY(fInfo.cellY)); + break; + } + itemBuilder.setFolder(folderBuilder); + } else { + switch (container) { + case CONTAINER_HOTSEAT: + itemBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder() + .setIndex(screenId)); + break; + case CONTAINER_DESKTOP: + itemBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder() + .setGridX(cellX) + .setGridY(cellY) + .setPageIndex(screenId)); + break; + } + } + return itemBuilder.build(); + } } diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java index b82430184a..3a478dd8e0 100644 --- a/src/com/android/launcher3/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java @@ -21,6 +21,7 @@ import android.content.ComponentName; import android.content.Intent; import android.os.Process; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.util.ContentWriter; @@ -162,7 +163,9 @@ public class LauncherAppWidgetInfo extends ItemInfo { @Override protected String dumpProperties() { - return super.dumpProperties() + " appWidgetId=" + appWidgetId; + return super.dumpProperties() + + " providerName=" + providerName + + " appWidgetId=" + appWidgetId; } public final boolean isWidgetIdAllocated() { @@ -182,4 +185,13 @@ public class LauncherAppWidgetInfo extends ItemInfo { public final boolean hasOptionFlag(int option) { return (options & option) != 0; } + + @Override + public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) { + builder.setWidget(LauncherAtom.Widget.newBuilder() + .setSpanX(spanX) + .setSpanY(spanY) + .setComponentName(providerName.toString()) + .setPackageName(providerName.getPackageName())); + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index ee9c099119..8bc0242920 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -991,7 +991,6 @@ public class Workspace extends PagedView if (!mOverlayShown) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.LEFT, ContainerType.WORKSPACE, 0); - mLauncher.getStatsLogManager().logSwipeOnContainer(true, 0); } mOverlayShown = true; // Not announcing the overlay page for accessibility since it announces itself. @@ -1001,7 +1000,6 @@ public class Workspace extends PagedView if (!ued.isPreviousHomeGesture()) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.RIGHT, ContainerType.WORKSPACE, -1); - mLauncher.getStatsLogManager().logSwipeOnContainer(false, -1); } } else if (Float.compare(mOverlayTranslation, 0f) != 0) { // When arriving to 0 overscroll from non-zero overscroll, announce page for diff --git a/src/com/android/launcher3/logging/LauncherUiEvent.java b/src/com/android/launcher3/logging/LauncherUiEvent.java new file mode 100644 index 0000000000..4507ff7d76 --- /dev/null +++ b/src/com/android/launcher3/logging/LauncherUiEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 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 static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(SOURCE) +@Target(FIELD) +public @interface LauncherUiEvent { + /** An explanation, suitable for Android analysts, of the UI event that this log represents. */ + String doc(); +} + diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 9dfd7ab943..2829951da2 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -16,23 +16,44 @@ package com.android.launcher3.logging; import android.content.Context; -import android.content.Intent; -import android.os.UserHandle; -import android.view.View; - -import androidx.annotation.Nullable; import com.android.launcher3.R; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.logger.LauncherAtom.ItemInfo; import com.android.launcher3.logging.StatsLogUtils.LogStateProvider; -import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ResourceBasedOverride; /** - * Handles the user event logging in Q. + * Handles the user event logging in R+. */ public class StatsLogManager implements ResourceBasedOverride { + interface EventEnum { + int getId(); + } + + public enum LauncherEvent implements EventEnum { + @LauncherUiEvent(doc = "App launched from workspace, hotseat or folder in launcher") + APP_LAUNCH_TAP(1), + @LauncherUiEvent(doc = "Task launched from overview using TAP") + TASK_LAUNCH_TAP(2), + @LauncherUiEvent(doc = "Task launched from overview using SWIPE DOWN") + TASK_LAUNCH_SWIPE_DOWN(2), + @LauncherUiEvent(doc = "TASK dismissed from overview using SWIPE UP") + TASK_DISMISS_SWIPE_UP(3); + // ADD MORE + + private final int mId; + LauncherEvent(int id) { + mId = id; + } + public int getId() { + return mId; + } + } + protected LogStateProvider mStateProvider; + public static StatsLogManager newInstance(Context context, LogStateProvider stateProvider) { StatsLogManager mgr = Overrides.getObject(StatsLogManager.class, context.getApplicationContext(), R.string.stats_log_manager_class); @@ -42,11 +63,14 @@ public class StatsLogManager implements ResourceBasedOverride { } /** - * Logs app launches + * Logs an event and accompanying {@link ItemInfo} */ - public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) { } - public void logTaskLaunch(View v, ComponentKey key) { } - public void logTaskDismiss(View v, ComponentKey key) { } - public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { } + public void log(LauncherEvent eventId, LauncherAtom.ItemInfo itemInfo) { } + + /** + * Logs snapshot, or impression of the current workspace. + */ + public void logSnapshot() { } + public void verify() {} // TODO: should move into robo tests } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 2311dcce44..695d2a6940 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -35,6 +35,8 @@ import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.AppInfo; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; @@ -150,8 +152,10 @@ public class LoaderCursor extends CursorWrapper { } } + @VisibleForTesting public WorkspaceItemInfo loadSimpleWorkspaceItem() { final WorkspaceItemInfo info = new WorkspaceItemInfo(); + info.intent = new Intent(); // Non-app shortcuts are only supported for current user. info.user = user; info.itemType = itemType;