1 /* 2 * Copyright (C) 2022 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.car.carlauncher; 18 19 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 20 21 import static com.android.car.carlauncher.TaskViewManager.DBG; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.ActivityManager; 26 import android.content.Context; 27 import android.graphics.Rect; 28 import android.util.Log; 29 import android.util.SparseArray; 30 import android.view.SurfaceControl; 31 import android.window.WindowContainerToken; 32 import android.window.WindowContainerTransaction; 33 34 import com.android.wm.shell.ShellTaskOrganizer; 35 import com.android.wm.shell.TaskView; 36 import com.android.wm.shell.common.SyncTransactionQueue; 37 38 /** 39 * CarLauncher version of {@link TaskView} which solves some CarLauncher specific issues: 40 * <ul> 41 * <li>b/228092608: Clears the hidden flag to make it TopFocusedRootTask.</li> 42 * <li>b/225388469: Moves the embedded task to the top to make it resumed.</li> 43 * </ul> 44 */ 45 public class CarTaskView extends TaskView { 46 private static final String TAG = CarTaskView.class.getSimpleName(); 47 @Nullable 48 private WindowContainerToken mTaskToken; 49 private final SyncTransactionQueue mSyncQueue; 50 private final SparseArray<Rect> mInsets = new SparseArray<>(); 51 private boolean mTaskViewReadySent; 52 CarTaskView(Context context, ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue)53 public CarTaskView(Context context, ShellTaskOrganizer organizer, 54 SyncTransactionQueue syncQueue) { 55 super(context, organizer, /* taskViewTransitions= */ null, syncQueue); 56 mSyncQueue = syncQueue; 57 } 58 59 @Override onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash)60 public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { 61 mTaskToken = taskInfo.token; 62 super.onTaskAppeared(taskInfo, leash); 63 64 applyInsets(); 65 } 66 67 @Override notifyInitialized()68 protected void notifyInitialized() { 69 super.notifyInitialized(); 70 if (mTaskViewReadySent) { 71 if (DBG) Log.i(TAG, "car task view ready already sent"); 72 return; 73 } 74 onCarTaskViewInitialized(); 75 mTaskViewReadySent = true; 76 } 77 78 /** 79 * Called only once when the {@link CarTaskView} is ready. 80 */ onCarTaskViewInitialized()81 protected void onCarTaskViewInitialized() {} 82 83 /** 84 * Moves the embedded task over the embedding task to make it shown. 85 */ showEmbeddedTask(WindowContainerTransaction wct)86 public void showEmbeddedTask(WindowContainerTransaction wct) { 87 if (mTaskToken == null) { 88 return; 89 } 90 // Clears the hidden flag to make it TopFocusedRootTask: b/228092608 91 wct.setHidden(mTaskToken, /* hidden= */ false); 92 // Moves the embedded task to the top to make it resumed: b/225388469 93 wct.reorder(mTaskToken, /* onTop= */ true); 94 } 95 96 // TODO(b/238473897): Consider taking insets one by one instead of taking all insets. 97 /** 98 * Set & apply the given {@code insets} on the Task. 99 * 100 * <p> 101 * The insets that were specified in an earlier call but not specified later, will remain 102 * applied to the task. Clients should explicitly call {@link #removeInsets(int[])} to remove 103 * the insets from the underlying task. 104 * </p> 105 */ setInsets(SparseArray<Rect> insets)106 public void setInsets(SparseArray<Rect> insets) { 107 mInsets.clear(); 108 for (int i = insets.size() - 1; i >= 0; i--) { 109 mInsets.append(insets.keyAt(i), insets.valueAt(i)); 110 } 111 applyInsets(); 112 } 113 114 /** 115 * Removes the given insets from the Task. 116 * 117 * Note: This will only remove the insets that were set using {@link #setInsets(SparseArray)} 118 * 119 * @param insetsTypes the types of insets to be removed 120 */ removeInsets(@onNull int[] insetsTypes)121 public void removeInsets(@NonNull int[] insetsTypes) { 122 if (mInsets == null || mInsets.size() == 0) { 123 Log.w(TAG, "No insets set."); 124 return; 125 } 126 if (mTaskToken == null) { 127 Log.w(TAG, "Cannot remove insets as the task token is not present."); 128 return; 129 } 130 WindowContainerTransaction wct = new WindowContainerTransaction(); 131 for (int i = 0; i < insetsTypes.length; i++) { 132 int insetsType = insetsTypes[i]; 133 if (mInsets.indexOfKey(insetsType) != -1) { 134 wct.removeInsetsProvider(mTaskToken, new int[]{insetsType}); 135 mInsets.remove(insetsType); 136 } else { 137 Log.w(TAG, "Insets type: " + insetsType + " can't be removed as it was not " 138 + "applied as part of hte last setInsets()"); 139 } 140 } 141 mSyncQueue.queue(wct); 142 } 143 applyInsets()144 private void applyInsets() { 145 if (mInsets == null || mInsets.size() == 0) { 146 Log.w(TAG, "Cannot apply null or empty insets"); 147 return; 148 } 149 if (mTaskToken == null) { 150 Log.w(TAG, "Cannot apply insets as the task token is not present."); 151 return; 152 } 153 WindowContainerTransaction wct = new WindowContainerTransaction(); 154 for (int i = 0; i < mInsets.size(); i++) { 155 wct.addRectInsetsProvider(mTaskToken, mInsets.valueAt(i), new int[]{mInsets.keyAt(i)}); 156 } 157 mSyncQueue.queue(wct); 158 } 159 160 /** 161 * @return the taskId of the currently running task. 162 */ getTaskId()163 public int getTaskId() { 164 if (mTaskInfo == null) { 165 return INVALID_TASK_ID; 166 } 167 return mTaskInfo.taskId; 168 } 169 } 170