<UserEventLogging> Log app launches b/26494415
am: fbf19cccd2

* commit 'fbf19cccd293ca23cbed38eaa25abc6ea72be83e':
  <UserEventLogging> Log app launches b/26494415
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ce96261..7b53f9f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -108,6 +108,7 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.userevent.Logger;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.TestingUtils;
@@ -367,6 +368,8 @@
     }
 
     private Stats mStats;
+    private Logger mUserEventLogger;
+
     public FocusIndicatorView mFocusHandler;
     private boolean mRotationEnabled = false;
 
@@ -424,6 +427,7 @@
         mDragController = new DragController(this);
         mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
 
+        mUserEventLogger = new Logger(this);
         mStats = new Stats(this);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
@@ -627,6 +631,7 @@
     public Stats getStats() {
         return mStats;
     }
+    public Logger getLogger() {return mUserEventLogger; }
 
     public boolean isDraggingEnabled() {
         // We prevent dragging when we are loading the workspace as it is possible to pick up a view
@@ -950,6 +955,7 @@
         }
 
         super.onResume();
+        mUserEventLogger.resetElapsedSessionMillis();
 
         // Restore the previous launcher state
         if (mOnResumeState == State.WORKSPACE) {
@@ -3331,6 +3337,7 @@
             getWindow().getDecorView()
                     .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
+        mUserEventLogger.resetElapsedContainerMillis();
         return changed;
     }
 
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 772fbf3..1d75752 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -54,20 +54,33 @@
      */
     public void onLauncherProviderChange();
     public void finishBindingItems(final boolean upgradePath);
-    public void onClickAllAppsButton(View v);
     public void bindAllApplications(ArrayList<AppInfo> apps);
+    public void onInteractionBegin();
+    public void onInteractionEnd();
+
+    /**
+     * Extension points for Gel Logging.
+     */
+    @Deprecated
+    public void onClickAllAppsButton(View v);
+    @Deprecated
     public void onClickFolderIcon(View v);
+    @Deprecated
     public void onClickAppShortcut(View v);
     @Deprecated
     public void onClickPagedViewIcon(View v);
+    @Deprecated
     public void onClickWallpaperPicker(View v);
+    @Deprecated
     public void onClickSettingsButton(View v);
+    @Deprecated
     public void onClickAddWidgetButton(View v);
+    @Deprecated
     public void onPageSwitch(View newPage, int newPageIndex);
+    @Deprecated
     public void onWorkspaceLockedChanged();
+    @Deprecated
     public void onDragStarted(View view);
-    public void onInteractionBegin();
-    public void onInteractionEnd();
 
     /*
      * Extension points for replacing the search experience
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index 59feeb7..2873828 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -26,6 +26,7 @@
 import android.view.ViewParent;
 
 import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.userevent.Logger;
 
 public class Stats {
 
@@ -145,5 +146,6 @@
         LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
         broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
         mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
+        mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras);
     }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 6bcbb61..22af94c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -47,6 +47,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.userevent.Logger;
 import com.android.launcher3.util.ComponentKey;
 
 import java.nio.charset.Charset;
@@ -312,6 +313,7 @@
                 icon.getMeasuredHeight());
 
         updateBackgroundAndPaddings();
+        mLauncher.getLogger().resetElapsedContainerMillis();
     }
 
     @Override
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e8e15c2..1988c2d 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -35,4 +35,5 @@
     public static boolean LAUNCHER3_LEGACY_WORKSPACE_DND = false;
     public static boolean LAUNCHER3_ICON_NORMALIZATION = true;
     public static boolean LAUNCHER3_CLIPPED_FOLDER_ICON = false;
+    public static boolean LAUNCHER3_LEGACY_LOGGING = false;
 }
diff --git a/src/com/android/launcher3/userevent/Logger.java b/src/com/android/launcher3/userevent/Logger.java
new file mode 100644
index 0000000..ae9041a
--- /dev/null
+++ b/src/com/android/launcher3/userevent/Logger.java
@@ -0,0 +1,208 @@
+package com.android.launcher3.userevent;
+
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.Stats;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Locale;
+
+/**
+ * Creates {@LauncherLogProto} nano protobuf object that can be used for user event
+ * metrics analysis.
+ */
+public class Logger {
+
+    private static final String TAG = "UserEventLogger";
+    private static final boolean DEBUG = false;
+
+    private long mActionDurationMillis;
+    private long mElapsedContainerMillis;
+    private long mElapsedSessionMillis;
+
+    private Context mContext;
+
+    public Logger(Context context) {
+        mContext = context;
+    }
+
+    public void logAppLaunch(String provider, ShortcutInfo shortcut, Bundle bundle) {
+        LauncherEvent event = new LauncherEvent();
+        event.action = new Action();
+        event.action.type = Action.TOUCH;
+        event.action.touch = Action.TAP;
+
+        event.srcTarget = new Target();
+        event.srcTarget.type = Target.ITEM;
+        event.srcTarget.itemType = LauncherLogProto.APP_ICON;
+        // TODO: package hash name should be different per device.
+        event.srcTarget.packageNameHash = provider.hashCode();
+
+        event.srcTarget.parent = new Target();
+        String subContainer = bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER);
+
+        if (shortcut != null) {
+            event.srcTarget.parent.containerType = getContainerType(shortcut);
+            event.srcTarget.pageIndex = (int) shortcut.screenId;
+            event.srcTarget.gridX = shortcut.cellX;
+            event.srcTarget.gridX = shortcut.cellY;
+        }
+        if (subContainer != null) {
+            event.srcTarget.parent.type = Target.CONTAINER;
+            if (subContainer.equals(Stats.SUB_CONTAINER_FOLDER)) {
+                event.srcTarget.parent.containerType = LauncherLogProto.FOLDER;
+            } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_A_Z)) {
+                event.srcTarget.parent.containerType = LauncherLogProto.ALLAPPS;
+            } else if (subContainer.equals(Stats.CONTAINER_HOTSEAT)) {
+                event.srcTarget.parent.containerType = LauncherLogProto.HOTSEAT;
+            } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_PREDICTION)) {
+                event.srcTarget.parent.containerType = LauncherLogProto.PREDICTION;
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, String.format("parent bundle: %s %s %s %s",
+                        bundle.getString(Stats.SOURCE_EXTRA_CONTAINER),
+                        bundle.getString(Stats.SOURCE_EXTRA_CONTAINER_PAGE),
+                        bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER),
+                        bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE)));
+            }
+        }
+
+
+        // Assign timeToAction
+        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+
+        // Debug
+        processLauncherEvent(event);
+    }
+
+    public void resetElapsedContainerMillis() {
+        mElapsedContainerMillis = System.currentTimeMillis();
+    }
+
+    public void resetElapsedSessionMillis() {
+        mElapsedSessionMillis = System.currentTimeMillis();
+    }
+
+    //
+    // Debugging helper methods.
+    // toString() cannot be overriden inside auto generated {@link LauncherLogProto}.
+    // Note: switch statement cannot be replaced with reflection as proguard strips the constants
+
+    private static void processLauncherEvent(LauncherEvent ev) {
+        if (DEBUG) {
+            if (ev.action.touch == Action.TAP && ev.srcTarget.itemType == LauncherLogProto.APP_ICON) {
+                Log.d(TAG, String.format(Locale.US, "action:%s target:%s\n\telapsed container %d ms session %d ms",
+                        getActionStr(ev.action),
+                        getTargetStr(ev.srcTarget),
+                        ev.elapsedContainerMillis,
+                        ev.elapsedSessionMillis));
+            }
+        }
+    }
+
+    private static int getContainerType(ShortcutInfo shortcut) {
+        switch ((int) shortcut.container) {
+            case LauncherSettings.Favorites.CONTAINER_DESKTOP: return LauncherLogProto.WORKSPACE;
+            case LauncherSettings.Favorites.CONTAINER_HOTSEAT: return LauncherLogProto.HOTSEAT;
+            default:
+                return (int) shortcut.container;
+        }
+    }
+
+    private static String getActionStr(Action action) {
+        switch(action.touch) {
+            case Action.TAP: return "TAP";
+            case Action.LONGPRESS: return "LONGPRESS";
+            case Action.DRAGDROP: return "DRAGDROP";
+            case Action.PINCH: return "PINCH";
+            default: return "UNKNOWN";
+        }
+    }
+
+    private static String getTargetStr(Target t) {
+        String typeStr;
+        switch (t.type) {
+            case LauncherLogProto.Target.ITEM:
+                return getItemStr(t);
+            case LauncherLogProto.Target.CONTROL:
+                return getControlStr(t);
+            case LauncherLogProto.Target.CONTAINER:
+                return getContainerStr(t);
+            default:
+                return "UNKNOWN TARGET TYPE";
+        }
+    }
+
+    private static String getItemStr(Target t) {
+        String typeStr = "";
+        switch(t.itemType){
+            case LauncherLogProto.APP_ICON: typeStr = "ICON"; break;
+            case LauncherLogProto.SHORTCUT: typeStr = "SHORTCUT"; break;
+            case LauncherLogProto.WIDGET: typeStr = "WIDGET"; break;
+            default: typeStr = "UNKNOWN";
+        }
+
+        return typeStr + " " + t.packageNameHash + " grid=(" + t.gridX + "," + t.gridY + ") "
+                + getContainerStr(t.parent);
+    }
+
+    private static String getControlStr(Target t) {
+        switch(t.controlType) {
+            case LauncherLogProto.ALL_APPS_BUTTON: return "ALL_APPS_BUTTON";
+            case LauncherLogProto.WIDGETS_BUTTON: return "WIDGETS_BUTTON";
+            case LauncherLogProto.WALLPAPER_BUTTON: return "WALLPAPER_BUTTON";
+            case LauncherLogProto.SETTINGS_BUTTON: return "SETTINGS_BUTTON";
+            case LauncherLogProto.REMOVE_TARGET: return "REMOVE_TARGET";
+            case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET";
+            case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET";
+            case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE";
+            case LauncherLogProto.FAST_SCROLL_HANDLE: return "FAST_SCROLL_HANDLE";
+            default: return "UNKNOWN";
+        }
+    }
+
+    private static String getContainerStr(Target t) {
+        String str;
+        Log.d(TAG, "t.containerType" + t.containerType);
+        switch (t.containerType) {
+            case LauncherLogProto.WORKSPACE:
+                str = "WORKSPACE";
+                break;
+            case LauncherLogProto.HOTSEAT:
+                str = "HOTSEAT";
+                break;
+            case LauncherLogProto.FOLDER:
+                str = "FOLDER";
+                break;
+            case LauncherLogProto.ALLAPPS:
+                str = "ALLAPPS";
+                break;
+            case LauncherLogProto.WIDGETS:
+                str = "WIDGETS";
+                break;
+            case LauncherLogProto.OVERVIEW:
+                str = "OVERVIEW";
+                break;
+            case LauncherLogProto.PREDICTION:
+                str = "PREDICTION";
+                break;
+            case LauncherLogProto.SEARCHRESULT:
+                str = "SEARCHRESULT";
+                break;
+            default:
+                str = "UNKNOWN";
+        }
+        return str + " id=" + t.pageIndex;
+    }
+}
+