1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wm.shell.draganddrop;
18 
19 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
20 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
21 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
22 
23 import android.content.ClipData;
24 import android.content.ClipDescription;
25 import android.content.pm.ActivityInfo;
26 import android.view.DragEvent;
27 
28 import androidx.annotation.Nullable;
29 
30 import com.android.internal.logging.InstanceId;
31 import com.android.internal.logging.InstanceIdSequence;
32 import com.android.internal.logging.UiEvent;
33 import com.android.internal.logging.UiEventLogger;
34 
35 /**
36  * Helper class that to log Drag & Drop UIEvents for a single session, see also go/uievent
37  */
38 public class DragAndDropEventLogger {
39 
40     private final UiEventLogger mUiEventLogger;
41     // Used to generate instance ids for this drag if one is not provided
42     private final InstanceIdSequence mIdSequence;
43 
44     // Tracks the current drag session
45     private ActivityInfo mActivityInfo;
46     private InstanceId mInstanceId;
47 
DragAndDropEventLogger(UiEventLogger uiEventLogger)48     public DragAndDropEventLogger(UiEventLogger uiEventLogger) {
49         mUiEventLogger = uiEventLogger;
50         mIdSequence = new InstanceIdSequence(Integer.MAX_VALUE);
51     }
52 
53     /**
54      * Logs the start of a drag.
55      */
logStart(DragEvent event)56     public InstanceId logStart(DragEvent event) {
57         final ClipDescription description = event.getClipDescription();
58         final ClipData data = event.getClipData();
59         final ClipData.Item item = data.getItemAt(0);
60         mInstanceId = item.getIntent().getParcelableExtra(
61                 ClipDescription.EXTRA_LOGGING_INSTANCE_ID);
62         if (mInstanceId == null) {
63             mInstanceId = mIdSequence.newInstanceId();
64         }
65         mActivityInfo = item.getActivityInfo();
66         log(getStartEnum(description), mActivityInfo);
67         return mInstanceId;
68     }
69 
70     /**
71      * Logs a successful drop.
72      */
logDrop()73     public void logDrop() {
74         log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_DROPPED, mActivityInfo);
75     }
76 
77     /**
78      * Logs the end of a drag.
79      */
logEnd()80     public void logEnd() {
81         log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_END, mActivityInfo);
82     }
83 
log(UiEventLogger.UiEventEnum event, @Nullable ActivityInfo activityInfo)84     private void log(UiEventLogger.UiEventEnum event, @Nullable ActivityInfo activityInfo) {
85         mUiEventLogger.logWithInstanceId(event,
86                 activityInfo == null ? 0 : activityInfo.applicationInfo.uid,
87                 activityInfo == null ? null : activityInfo.applicationInfo.packageName,
88                 mInstanceId);
89     }
90 
91     /**
92      * Returns the start logging enum for the given drag description.
93      */
getStartEnum(ClipDescription description)94     private DragAndDropUiEventEnum getStartEnum(ClipDescription description) {
95         if (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)) {
96             return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_ACTIVITY;
97         } else if (description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)) {
98             return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_SHORTCUT;
99         } else if (description.hasMimeType(MIMETYPE_APPLICATION_TASK)) {
100             return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_TASK;
101         }
102         throw new IllegalArgumentException("Not an app drag");
103     }
104 
105     /**
106      * Enums for logging Drag & Drop UiEvents
107      */
108     public enum DragAndDropUiEventEnum implements UiEventLogger.UiEventEnum {
109         @UiEvent(doc = "Starting a global drag and drop of an activity")
110         GLOBAL_APP_DRAG_START_ACTIVITY(884),
111 
112         @UiEvent(doc = "Starting a global drag and drop of a shortcut")
113         GLOBAL_APP_DRAG_START_SHORTCUT(885),
114 
115         @UiEvent(doc = "Starting a global drag and drop of a task")
116         GLOBAL_APP_DRAG_START_TASK(888),
117 
118         @UiEvent(doc = "A global app drag was successfully dropped")
119         GLOBAL_APP_DRAG_DROPPED(887),
120 
121         @UiEvent(doc = "Ending a global app drag and drop")
122         GLOBAL_APP_DRAG_END(886);
123 
124         private final int mId;
125 
DragAndDropUiEventEnum(int id)126         DragAndDropUiEventEnum(int id) {
127             mId = id;
128         }
129 
130         @Override
getId()131         public int getId() {
132             return mId;
133         }
134     }
135 }
136