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