Implements LAUNCHER_ITEM_DROP_FOLDER_CREATED event.

When item is dropped on a existing item resulting in new folder creation, triggers LAUNCHER_ITEM_DROP_FOLDER_CREATED event with details of the destination package.
This change also introduces new FolderIcon item to launcher_atom.proto to represent folder icon.

Screencast and sample logs: https://docs.google.com/document/d/1CBP2yTcXdFhPdNG5ZmWFKSgd8mDbMevY-akVlUXPLDo/edit#bookmark=id.tmbucd1f44qp

Bug: 152978018

Change-Id: Ib4d343ba9075aa8853652f128457c4638541ec59
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index 6cb803a..0b0983c 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -78,7 +78,7 @@
         public DraggableView originalView = null;
 
         /** Used for matching DROP event with its corresponding DRAG event on the server side. */
-        final InstanceId mLogInstanceId =
+        public final InstanceId logInstanceId =
                 new InstanceIdSequence(1 << 20 /*InstanceId.INSTANCE_ID_MAX*/)
                     .newInstanceId();
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index dd00bd3..412eef1 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -416,8 +416,12 @@
         mLauncher.getStateManager().goToState(SPRING_LOADED);
         mStatsLogManager.log(
                 LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED,
-                dragObject.mLogInstanceId,
-                dragObject.originalDragInfo.buildProto(null));
+                dragObject.logInstanceId,
+                dragObject.originalDragInfo.buildProto(
+                    dragObject.dragSource instanceof Folder
+                        ? ((Folder) dragObject.dragSource).mInfo
+                        : null)
+        );
     }
 
     public void deferRemoveExtraEmptyScreen() {
@@ -1645,7 +1649,10 @@
             Rect folderLocation = new Rect();
             float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
             target.removeView(v);
-
+            mStatsLogManager.log(
+                    LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED,
+                    d.logInstanceId,
+                    destInfo.buildProto(null));
             FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
                     targetCell[1]);
             destInfo.cellX = -1;
@@ -1683,6 +1690,10 @@
         if (dropOverView instanceof FolderIcon) {
             FolderIcon fi = (FolderIcon) dropOverView;
             if (fi.acceptDrop(d.dragInfo)) {
+                mStatsLogManager.log(
+                        LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+                        d.logInstanceId,
+                        fi.mInfo.buildProto(null));
                 fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
 
                 // if the drag started here, we need to remove it from the workspace
@@ -1885,15 +1896,15 @@
 
             mLauncher.getStateManager().goToState(
                     NORMAL, SPRING_LOADED_EXIT_DELAY, onCompleteRunnable);
+            mStatsLogManager.log(
+                    LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+                    d.logInstanceId,
+                    d.dragInfo.buildProto(null));
         }
 
         if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
             d.stateAnnouncer.completeAction(R.string.item_moved);
         }
-        mStatsLogManager.log(
-                LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
-                d.mLogInstanceId,
-                d.dragInfo.buildProto(null));
     }
 
     public void onNoCellFound(View dropTargetLayout) {
@@ -2515,6 +2526,10 @@
                 resetTransitionTransform();
             }
         }
+        mStatsLogManager.log(
+                LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+                d.logInstanceId,
+                d.dragInfo.buildProto(null));
     }
 
     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index d93fb1a..03028d3 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -186,8 +186,7 @@
 
         mDragObject.dragSource = source;
         mDragObject.dragInfo = dragInfo;
-        mDragObject.originalDragInfo = new ItemInfo();
-        mDragObject.originalDragInfo.copyFrom(dragInfo);
+        mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
 
         if (dragOffset != null) {
             dragView.setDragVisualizeOffset(new Point(dragOffset));
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c287190..9a36b3e 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -87,6 +87,7 @@
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.FolderInfo.FolderListener;
@@ -1346,6 +1347,10 @@
         if (d.stateAnnouncer != null) {
             d.stateAnnouncer.completeAction(R.string.item_moved);
         }
+        StatsLogManager.newInstance(getContext())
+                .log(StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+                    d.logInstanceId,
+                    d.dragInfo.buildProto(mInfo));
     }
 
     // This is used so the item doesn't immediately appear in the folder when added. In one case
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index b875a0b..e2963d7 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -85,7 +85,7 @@
 
     @Thunk ActivityContext mActivity;
     @Thunk Folder mFolder;
-    private FolderInfo mInfo;
+    public FolderInfo mInfo;
 
     private CheckLongPressHelper mLongPressHelper;
 
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 62a3829..abf027d 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -47,7 +47,10 @@
         @LauncherUiEvent(doc = "User dragged a launcher item")
         LAUNCHER_ITEM_DRAG_STARTED(383),
         @LauncherUiEvent(doc = "A dragged launcher item is successfully dropped")
-        LAUNCHER_ITEM_DROP_COMPLETED(385);
+        LAUNCHER_ITEM_DROP_COMPLETED(385),
+        @LauncherUiEvent(doc = "A dragged launcher item is successfully dropped on another item "
+                + "resulting in new folder creation")
+        LAUNCHER_ITEM_DROP_FOLDER_CREATED(386);
         // ADD MORE
 
         private final int mId;
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index cfe34c1..3ac6a22 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -21,6 +21,7 @@
 
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.util.ContentWriter;
 
@@ -155,4 +156,20 @@
         return super.dumpProperties()
                 + " manuallyTypedTitle=" + hasOption(FLAG_MANUAL_FOLDER_NAME);
     }
+
+    @Override
+    public LauncherAtom.ItemInfo buildProto(FolderInfo fInfo) {
+        return getDefaultItemInfoBuilder()
+            .setFolderIcon(LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size()))
+            .setContainerInfo(getContainerInfo())
+            .build();
+    }
+
+    @Override
+    public ItemInfo makeShallowCopy() {
+        FolderInfo folderInfo = new FolderInfo();
+        folderInfo.copyFrom(this);
+        folderInfo.contents = this.contents;
+        return folderInfo;
+    }
 }
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 12ea888..4359f25 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -253,8 +253,7 @@
      * Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
      */
     public LauncherAtom.ItemInfo buildProto(FolderInfo fInfo) {
-        LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
-        itemBuilder.setIsWork(user != Process.myUserHandle());
+        LauncherAtom.ItemInfo.Builder itemBuilder = getDefaultItemInfoBuilder();
         Optional<ComponentName> nullableComponent = Optional.ofNullable(getTargetComponent());
         switch (itemType) {
             case ITEM_TYPE_APPLICATION:
@@ -305,28 +304,45 @@
             }
             itemBuilder.setContainerInfo(ContainerInfo.newBuilder().setFolder(folderBuilder));
         } else {
-            switch (container) {
-                case CONTAINER_HOTSEAT:
-                case CONTAINER_HOTSEAT_PREDICTION:
-                    itemBuilder.setContainerInfo(
-                            ContainerInfo.newBuilder().setHotseat(
-                                    LauncherAtom.HotseatContainer.newBuilder().setIndex(screenId)));
-                    break;
-                case CONTAINER_DESKTOP:
-                    itemBuilder.setContainerInfo(
-                            ContainerInfo.newBuilder().setWorkspace(
-                                    LauncherAtom.WorkspaceContainer.newBuilder()
-                                            .setGridX(cellX)
-                                            .setGridY(cellY)
-                                            .setPageIndex(screenId)));
-                    break;
-                case CONTAINER_ALL_APPS:
-                    itemBuilder.setContainerInfo(
-                            ContainerInfo.newBuilder().setAllAppsContainer(
-                                    AllAppsContainer.getDefaultInstance()));
-                    break;
-            }
+            itemBuilder.setContainerInfo(getContainerInfo());
         }
         return itemBuilder.build();
     }
+
+    LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
+        LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
+        itemBuilder.setIsWork(user != Process.myUserHandle());
+        return itemBuilder;
+    }
+
+    ContainerInfo getContainerInfo() {
+        switch (container) {
+            case CONTAINER_HOTSEAT:
+            case CONTAINER_HOTSEAT_PREDICTION:
+                return ContainerInfo.newBuilder()
+                    .setHotseat(LauncherAtom.HotseatContainer.newBuilder().setIndex(screenId))
+                    .build();
+            case CONTAINER_DESKTOP:
+                return ContainerInfo.newBuilder()
+                    .setWorkspace(
+                        LauncherAtom.WorkspaceContainer.newBuilder()
+                        .setGridX(cellX)
+                        .setGridY(cellY)
+                        .setPageIndex(screenId))
+                    .build();
+            case CONTAINER_ALL_APPS:
+                return ContainerInfo.newBuilder()
+                        .setAllAppsContainer(
+                                AllAppsContainer.getDefaultInstance())
+                        .build();
+        }
+        return ContainerInfo.getDefaultInstance();
+    }
+
+    /** Returns shallow copy of the object. */
+    public ItemInfo makeShallowCopy() {
+        ItemInfo itemInfo = new ItemInfo();
+        itemInfo.copyFrom(this);
+        return itemInfo;
+    }
 }