1 /* 2 * Copyright (C) 2023 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.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 22 import static android.content.ClipDescription.EXTRA_HIDE_DRAG_SOURCE_TASK_ID; 23 24 import android.app.ActivityManager; 25 import android.app.ActivityTaskManager; 26 import android.app.PendingIntent; 27 import android.app.WindowConfiguration; 28 import android.content.ClipData; 29 import android.content.ClipDescription; 30 import android.content.Intent; 31 import android.content.pm.ActivityInfo; 32 33 import androidx.annotation.Nullable; 34 35 import com.android.internal.protolog.ProtoLog; 36 import com.android.wm.shell.common.DisplayLayout; 37 import com.android.wm.shell.protolog.ShellProtoLogGroup; 38 39 import java.util.List; 40 41 /** 42 * Per-drag session data. 43 */ 44 public class DragSession { 45 private final ActivityTaskManager mActivityTaskManager; 46 @Nullable 47 private final ClipData mInitialDragData; 48 private final int mInitialDragFlags; 49 50 final DisplayLayout displayLayout; 51 // The activity info associated with the activity in the appData or the launchableIntent 52 @Nullable 53 ActivityInfo activityInfo; 54 // The intent bundle that includes data about an app-type drag that is started by 55 // Launcher/SysUI. Only one of appDragData OR launchableIntent will be non-null for a session. 56 @Nullable 57 Intent appData; 58 // A launchable intent that is specified in the ClipData directly. 59 // Only one of appDragData OR launchableIntent will be non-null for a session. 60 @Nullable 61 PendingIntent launchableIntent; 62 // Stores the current running task at the time that the drag was initiated 63 ActivityManager.RunningTaskInfo runningTaskInfo; 64 @WindowConfiguration.WindowingMode 65 int runningTaskWinMode = WINDOWING_MODE_UNDEFINED; 66 @WindowConfiguration.ActivityType 67 int runningTaskActType = ACTIVITY_TYPE_STANDARD; 68 boolean dragItemSupportsSplitscreen; 69 final int hideDragSourceTaskId; 70 DragSession(ActivityTaskManager activityTaskManager, DisplayLayout dispLayout, ClipData data, int dragFlags)71 DragSession(ActivityTaskManager activityTaskManager, 72 DisplayLayout dispLayout, ClipData data, int dragFlags) { 73 mActivityTaskManager = activityTaskManager; 74 mInitialDragData = data; 75 mInitialDragFlags = dragFlags; 76 displayLayout = dispLayout; 77 hideDragSourceTaskId = data != null && data.getDescription().getExtras() != null 78 ? data.getDescription().getExtras().getInt(EXTRA_HIDE_DRAG_SOURCE_TASK_ID, -1) 79 : -1; 80 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, 81 "Extracting drag source taskId: taskId=%d", hideDragSourceTaskId); 82 } 83 84 /** 85 * Returns the clip description associated with the drag. 86 */ getClipDescription()87 ClipDescription getClipDescription() { 88 return mInitialDragData.getDescription(); 89 } 90 91 /** 92 * Updates the running task for this drag session. 93 */ updateRunningTask()94 void updateRunningTask() { 95 final boolean hideDragSourceTask = hideDragSourceTaskId != -1; 96 final List<ActivityManager.RunningTaskInfo> tasks = 97 mActivityTaskManager.getTasks(5, false /* filterOnlyVisibleRecents */); 98 for (int i = 0; i < tasks.size(); i++) { 99 final ActivityManager.RunningTaskInfo task = tasks.get(i); 100 if (hideDragSourceTask && hideDragSourceTaskId == task.taskId) { 101 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, 102 "Skipping running task: id=%d component=%s", task.taskId, 103 task.baseIntent != null ? task.baseIntent.getComponent() : "null"); 104 continue; 105 } 106 if (!task.isVisible) { 107 // Skip invisible tasks 108 continue; 109 } 110 if (task.configuration.windowConfiguration.isAlwaysOnTop()) { 111 // Skip always-on-top floating tasks 112 continue; 113 } 114 runningTaskInfo = task; 115 runningTaskWinMode = task.getWindowingMode(); 116 runningTaskActType = task.getActivityType(); 117 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, 118 "Running task: id=%d component=%s", task.taskId, 119 task.baseIntent != null ? task.baseIntent.getComponent() : "null"); 120 break; 121 } 122 } 123 124 /** 125 * Updates the session data based on the current state of the system at the start of the drag. 126 */ initialize(boolean skipUpdateRunningTask)127 void initialize(boolean skipUpdateRunningTask) { 128 if (!skipUpdateRunningTask) { 129 updateRunningTask(); 130 } 131 132 activityInfo = mInitialDragData.getItemAt(0).getActivityInfo(); 133 // TODO: This should technically check & respect config_supportsNonResizableMultiWindow 134 dragItemSupportsSplitscreen = activityInfo == null 135 || ActivityInfo.isResizeableMode(activityInfo.resizeMode); 136 appData = mInitialDragData.getItemAt(0).getIntent(); 137 launchableIntent = DragUtils.getLaunchIntent(mInitialDragData, mInitialDragFlags); 138 } 139 } 140