• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.launcher3.taskbar;
17 
18 import static android.view.View.INVISIBLE;
19 import static android.view.View.VISIBLE;
20 
21 import android.content.ClipData;
22 import android.content.ClipDescription;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.LauncherApps;
26 import android.content.res.Resources;
27 import android.graphics.Canvas;
28 import android.graphics.Point;
29 import android.os.UserHandle;
30 import android.view.DragEvent;
31 import android.view.View;
32 
33 import com.android.launcher3.BubbleTextView;
34 import com.android.launcher3.LauncherSettings;
35 import com.android.launcher3.R;
36 import com.android.launcher3.model.data.WorkspaceItemInfo;
37 import com.android.systemui.shared.recents.model.Task;
38 import com.android.systemui.shared.system.ClipDescriptionCompat;
39 import com.android.systemui.shared.system.LauncherAppsCompat;
40 
41 /**
42  * Handles long click on Taskbar items to start a system drag and drop operation.
43  */
44 public class TaskbarDragController {
45 
46     private final Context mContext;
47     private final int mDragIconSize;
48 
TaskbarDragController(Context context)49     public TaskbarDragController(Context context) {
50         mContext = context;
51         Resources resources = mContext.getResources();
52         mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size);
53     }
54 
55     /**
56      * Attempts to start a system drag and drop operation for the given View, using its tag to
57      * generate the ClipDescription and Intent.
58      * @return Whether {@link View#startDragAndDrop} started successfully.
59      */
startSystemDragOnLongClick(View view)60     protected boolean startSystemDragOnLongClick(View view) {
61         if (!(view instanceof BubbleTextView)) {
62             return false;
63         }
64 
65         BubbleTextView btv = (BubbleTextView) view;
66         View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) {
67             @Override
68             public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
69                 shadowSize.set(mDragIconSize, mDragIconSize);
70                 // TODO: should be based on last touch point on the icon.
71                 shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
72             }
73 
74             @Override
75             public void onDrawShadow(Canvas canvas) {
76                 canvas.save();
77                 float scale = (float) mDragIconSize / btv.getIconSize();
78                 canvas.scale(scale, scale);
79                 btv.getIcon().draw(canvas);
80                 canvas.restore();
81             }
82         };
83 
84         Object tag = view.getTag();
85         ClipDescription clipDescription = null;
86         Intent intent = null;
87         if (tag instanceof WorkspaceItemInfo) {
88             WorkspaceItemInfo item = (WorkspaceItemInfo) tag;
89             LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
90             clipDescription = new ClipDescription(item.title,
91                     new String[] {
92                             item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
93                                     ? ClipDescriptionCompat.MIMETYPE_APPLICATION_SHORTCUT
94                                     : ClipDescriptionCompat.MIMETYPE_APPLICATION_ACTIVITY
95                     });
96             intent = new Intent();
97             if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
98                 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, item.getIntent().getPackage());
99                 intent.putExtra(Intent.EXTRA_SHORTCUT_ID, item.getDeepShortcutId());
100             } else {
101                 intent.putExtra(ClipDescriptionCompat.EXTRA_PENDING_INTENT,
102                         LauncherAppsCompat.getMainActivityLaunchIntent(launcherApps,
103                                 item.getIntent().getComponent(), null, item.user));
104             }
105             intent.putExtra(Intent.EXTRA_USER, item.user);
106         } else if (tag instanceof Task) {
107             Task task = (Task) tag;
108             clipDescription = new ClipDescription(task.titleDescription,
109                     new String[] {
110                             ClipDescriptionCompat.MIMETYPE_APPLICATION_TASK
111                     });
112             intent = new Intent();
113             intent.putExtra(ClipDescriptionCompat.EXTRA_TASK_ID, task.key.id);
114             intent.putExtra(Intent.EXTRA_USER, UserHandle.of(task.key.userId));
115         }
116 
117         if (clipDescription != null && intent != null) {
118             ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
119             view.setOnDragListener(getDraggedViewDragListener());
120             return view.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
121                     View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE);
122         }
123         return false;
124     }
125 
126     /**
127      * Hide the original Taskbar item while it is being dragged.
128      */
getDraggedViewDragListener()129     private View.OnDragListener getDraggedViewDragListener() {
130         return (view, dragEvent) -> {
131             switch (dragEvent.getAction()) {
132                 case DragEvent.ACTION_DRAG_STARTED:
133                     view.setVisibility(INVISIBLE);
134                     return true;
135                 case DragEvent.ACTION_DRAG_ENDED:
136                     view.setVisibility(VISIBLE);
137                     view.setOnDragListener(null);
138                     return true;
139             }
140             return false;
141         };
142     }
143 }
144