Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ac0ef1c authored by Hyunyoung Song's avatar Hyunyoung Song
Browse files

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
parent 514dfa2d
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
/*
 * 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;
  }
}

+11 −7
Original line number Diff line number Diff line
@@ -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<T extends BaseActivity> 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<T extends BaseActivity> 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<T extends BaseActivity> 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);
+16 −2
Original line number Diff line number Diff line
@@ -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();
+45 −196
Original line number Diff line number Diff line
@@ -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,196 +48,59 @@ 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);
    public void log(LauncherEvent eventId, LauncherAtom.ItemInfo item) {
        // Call StatsLog method
    }

    @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<Target> 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);
    public void verify() {
        if (!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS
                && StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND
                && StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW
                && StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
            throw new IllegalStateException(
                    "StatsLogUtil constants doesn't match enums in launcher.proto");
        }

        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.");
    /**
     * Logs the workspace layout information on the model thread.
     */
    public void logSnapshot() {
        LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
                new SnapshotWorker());
    }

        // 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;
        }
    private class SnapshotWorker extends BaseModelUpdateTask {
        @Override
        public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
            IntSparseArrayMap<FolderInfo> folders = dataModel.folders.clone();
            ArrayList<ItemInfo> workspaceItems = (ArrayList) dataModel.workspaceItems.clone();
            ArrayList<LauncherAppWidgetInfo> appWidgets = (ArrayList) dataModel.appWidgets.clone();

        // 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;
            for (ItemInfo info : workspaceItems) {
                LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
                // call StatsLog method
            }

        // 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;
            for (FolderInfo fInfo : folders) {
                for (ItemInfo info : fInfo.contents) {
                    LauncherAtom.ItemInfo atomInfo = info.buildProto(null, fInfo);
                    // call StatsLog method
                }

        // 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;
            for (ItemInfo info : appWidgets) {
                LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
                // call StatsLog method
            }

    @Override
    public void verify() {
        if (!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS
                && StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND
                && StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW
                && StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
            throw new IllegalStateException(
                    "StatsLogUtil constants doesn't match enums in launcher.proto");
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -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();
Loading