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 android.window; 18 19 import static android.view.WindowManager.TRANSIT_CHANGE; 20 import static android.view.WindowManager.TRANSIT_CLOSE; 21 import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; 22 import static android.view.WindowManager.TRANSIT_NONE; 23 import static android.view.WindowManager.TRANSIT_OPEN; 24 25 import android.annotation.CallSuper; 26 import android.annotation.FlaggedApi; 27 import android.annotation.IntDef; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.RequiresPermission; 31 import android.annotation.TestApi; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 import android.view.RemoteAnimationDefinition; 36 import android.view.WindowManager; 37 38 import com.android.window.flags.Flags; 39 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.concurrent.Executor; 43 44 /** 45 * Interface for WindowManager to delegate control of {@code TaskFragment}. 46 * @hide 47 */ 48 @TestApi 49 public class TaskFragmentOrganizer extends WindowOrganizer { 50 51 /** 52 * Key to the {@link Throwable} in {@link TaskFragmentTransaction.Change#getErrorBundle()}. 53 */ 54 public static final String KEY_ERROR_CALLBACK_THROWABLE = "fragment_throwable"; 55 56 /** 57 * Key to the {@link TaskFragmentInfo} in 58 * {@link TaskFragmentTransaction.Change#getErrorBundle()}. 59 */ 60 public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info"; 61 62 /** 63 * Key to the {@link TaskFragmentOperation.OperationType} in 64 * {@link TaskFragmentTransaction.Change#getErrorBundle()}. 65 */ 66 public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type"; 67 68 /** 69 * No change set. 70 */ 71 @WindowManager.TransitionType 72 @TaskFragmentTransitionType 73 public static final int TASK_FRAGMENT_TRANSIT_NONE = TRANSIT_NONE; 74 75 /** 76 * A window that didn't exist before has been created and made visible. 77 */ 78 @WindowManager.TransitionType 79 @TaskFragmentTransitionType 80 public static final int TASK_FRAGMENT_TRANSIT_OPEN = TRANSIT_OPEN; 81 82 /** 83 * A window that was visible no-longer exists (was finished or destroyed). 84 */ 85 @WindowManager.TransitionType 86 @TaskFragmentTransitionType 87 public static final int TASK_FRAGMENT_TRANSIT_CLOSE = TRANSIT_CLOSE; 88 89 /** 90 * A window is visible before and after but changes in some way (eg. it resizes or changes 91 * windowing-mode). 92 */ 93 @WindowManager.TransitionType 94 @TaskFragmentTransitionType 95 public static final int TASK_FRAGMENT_TRANSIT_CHANGE = TRANSIT_CHANGE; 96 97 98 /** 99 * The task fragment drag resize transition used by activity embedding. 100 * 101 * This value is also used in Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE and must not 102 * conflict with other predefined transition types. 103 * 104 * @hide 105 */ 106 @WindowManager.TransitionType 107 @TaskFragmentTransitionType 108 public static final int TASK_FRAGMENT_TRANSIT_DRAG_RESIZE = TRANSIT_FIRST_CUSTOM + 17; 109 110 /** 111 * Introduced a sub set of {@link WindowManager.TransitionType} for the types that are used for 112 * TaskFragment transition. 113 * 114 * Doing this instead of exposing {@link WindowManager.TransitionType} because we want to keep 115 * the Shell transition API hidden until it comes fully stable. 116 * @hide 117 */ 118 @IntDef(prefix = { "TASK_FRAGMENT_TRANSIT_" }, value = { 119 TASK_FRAGMENT_TRANSIT_NONE, 120 TASK_FRAGMENT_TRANSIT_OPEN, 121 TASK_FRAGMENT_TRANSIT_CLOSE, 122 TASK_FRAGMENT_TRANSIT_CHANGE, 123 TASK_FRAGMENT_TRANSIT_DRAG_RESIZE, 124 }) 125 @Retention(RetentionPolicy.SOURCE) 126 public @interface TaskFragmentTransitionType {} 127 128 /** 129 * Creates a {@link Bundle} with an exception, operation type and TaskFragmentInfo (if any) 130 * that can be passed to {@link ITaskFragmentOrganizer#onTaskFragmentError}. 131 * @hide 132 */ putErrorInfoInBundle(@onNull Throwable exception, @Nullable TaskFragmentInfo info, @TaskFragmentOperation.OperationType int opType)133 public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception, 134 @Nullable TaskFragmentInfo info, @TaskFragmentOperation.OperationType int opType) { 135 final Bundle errorBundle = new Bundle(); 136 errorBundle.putSerializable(KEY_ERROR_CALLBACK_THROWABLE, exception); 137 if (info != null) { 138 errorBundle.putParcelable(KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, info); 139 } 140 errorBundle.putInt(KEY_ERROR_CALLBACK_OP_TYPE, opType); 141 return errorBundle; 142 } 143 144 /** 145 * Callbacks from WM Core are posted on this executor. 146 */ 147 private final Executor mExecutor; 148 TaskFragmentOrganizer(@onNull Executor executor)149 public TaskFragmentOrganizer(@NonNull Executor executor) { 150 mExecutor = executor; 151 } 152 153 /** 154 * Gets the executor to run callbacks on. 155 */ 156 @NonNull getExecutor()157 public Executor getExecutor() { 158 return mExecutor; 159 } 160 161 /** 162 * Registers a {@link TaskFragmentOrganizer} to manage TaskFragments. 163 */ 164 @CallSuper registerOrganizer()165 public void registerOrganizer() { 166 // TODO(b/302420256) point to registerOrganizer(boolean) when flag is removed. 167 try { 168 getController().registerOrganizer(mInterface, false /* isSystemOrganizer */); 169 } catch (RemoteException e) { 170 throw e.rethrowFromSystemServer(); 171 } 172 } 173 174 /** 175 * Registers a {@link TaskFragmentOrganizer} to manage TaskFragments. 176 * 177 * Registering a system organizer requires MANAGE_ACTIVITY_TASKS permission, and the organizer 178 * will have additional system capabilities, including: (1) it will receive SurfaceControl for 179 * the organized TaskFragment, and (2) it needs to update the 180 * {@link android.view.SurfaceControl} following the window change accordingly. 181 * 182 * @hide 183 */ 184 @CallSuper 185 @RequiresPermission(value = "android.permission.MANAGE_ACTIVITY_TASKS", conditional = true) 186 @FlaggedApi(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG) registerOrganizer(boolean isSystemOrganizer)187 public void registerOrganizer(boolean isSystemOrganizer) { 188 try { 189 getController().registerOrganizer(mInterface, isSystemOrganizer); 190 } catch (RemoteException e) { 191 throw e.rethrowFromSystemServer(); 192 } 193 } 194 195 /** 196 * Unregisters a previously registered TaskFragmentOrganizer. 197 */ 198 @CallSuper unregisterOrganizer()199 public void unregisterOrganizer() { 200 try { 201 getController().unregisterOrganizer(mInterface); 202 } catch (RemoteException e) { 203 throw e.rethrowFromSystemServer(); 204 } 205 } 206 207 /** 208 * Registers remote animations per transition type for the organizer. It will override the 209 * animations if the transition only contains windows that belong to the organized 210 * TaskFragments, and at least one of the transition window is embedded (not filling the Task). 211 * @hide 212 */ 213 @CallSuper registerRemoteAnimations(@onNull RemoteAnimationDefinition definition)214 public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) { 215 try { 216 getController().registerRemoteAnimations(mInterface, definition); 217 } catch (RemoteException e) { 218 throw e.rethrowFromSystemServer(); 219 } 220 } 221 222 /** 223 * Unregisters remote animations per transition type for the organizer. 224 * @hide 225 */ 226 @CallSuper unregisterRemoteAnimations()227 public void unregisterRemoteAnimations() { 228 try { 229 getController().unregisterRemoteAnimations(mInterface); 230 } catch (RemoteException e) { 231 throw e.rethrowFromSystemServer(); 232 } 233 } 234 235 /** 236 * Notifies the server that the organizer has finished handling the given transaction. The 237 * server should apply the given {@link WindowContainerTransaction} for the necessary changes. 238 * 239 * @param transactionToken {@link TaskFragmentTransaction#getTransactionToken()} from 240 * {@link #onTransactionReady(TaskFragmentTransaction)} 241 * @param wct {@link WindowContainerTransaction} that the server should apply for 242 * update of the transaction. 243 * @param transitionType {@link TaskFragmentTransitionType} if it needs to start a 244 * transition. 245 * @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new 246 * transition, which will be queued until the sync engine is 247 * free if there is any other active sync. If {@code false}, 248 * the {@code wct} will be directly applied to the active sync. 249 * @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission 250 * for permission enforcement. 251 */ onTransactionHandled(@onNull IBinder transactionToken, @NonNull WindowContainerTransaction wct, @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently)252 public void onTransactionHandled(@NonNull IBinder transactionToken, 253 @NonNull WindowContainerTransaction wct, 254 @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently) { 255 wct.setTaskFragmentOrganizer(mInterface); 256 try { 257 getController().onTransactionHandled(transactionToken, wct, transitionType, 258 shouldApplyIndependently); 259 } catch (RemoteException e) { 260 throw e.rethrowFromSystemServer(); 261 } 262 } 263 264 /** 265 * Must use {@link #applyTransaction(WindowContainerTransaction, int, boolean)} instead. 266 * @see #applyTransaction(WindowContainerTransaction, int, boolean) 267 */ 268 @Override applyTransaction(@onNull WindowContainerTransaction wct)269 public void applyTransaction(@NonNull WindowContainerTransaction wct) { 270 throw new RuntimeException("Not allowed!"); 271 } 272 273 /** 274 * Requests the server to apply the given {@link WindowContainerTransaction}. 275 * 276 * @param wct {@link WindowContainerTransaction} to apply. 277 * @param transitionType {@link TaskFragmentTransitionType} if it needs to start a 278 * transition. 279 * @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new 280 * transition, which will be queued until the sync engine is 281 * free if there is any other active sync. If {@code false}, 282 * the {@code wct} will be directly applied to the active sync. 283 * @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission 284 * for permission enforcement. 285 */ applyTransaction(@onNull WindowContainerTransaction wct, @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently)286 public void applyTransaction(@NonNull WindowContainerTransaction wct, 287 @TaskFragmentTransitionType int transitionType, boolean shouldApplyIndependently) { 288 if (wct.isEmpty()) { 289 return; 290 } 291 wct.setTaskFragmentOrganizer(mInterface); 292 try { 293 getController().applyTransaction( 294 wct, transitionType, shouldApplyIndependently, null /* remoteTransition */); 295 } catch (RemoteException e) { 296 throw e.rethrowFromSystemServer(); 297 } 298 } 299 300 /** 301 * Applies a transaction with a {@link RemoteTransition}. Only a system organizer is allowed to 302 * use {@link RemoteTransition}. See {@link TaskFragmentOrganizer#registerOrganizer(boolean)}. 303 * 304 * @hide 305 */ 306 @FlaggedApi(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG) applySystemTransaction(@onNull WindowContainerTransaction wct, @TaskFragmentTransitionType int transitionType, @Nullable RemoteTransition remoteTransition)307 public void applySystemTransaction(@NonNull WindowContainerTransaction wct, 308 @TaskFragmentTransitionType int transitionType, 309 @Nullable RemoteTransition remoteTransition) { 310 if (wct.isEmpty()) { 311 return; 312 } 313 wct.setTaskFragmentOrganizer(mInterface); 314 try { 315 getController().applyTransaction( 316 wct, transitionType, remoteTransition != null /* shouldApplyIndependently */, 317 remoteTransition); 318 } catch (RemoteException e) { 319 throw e.rethrowFromSystemServer(); 320 } 321 } 322 323 /** 324 * Called when the transaction is ready so that the organizer can update the TaskFragments based 325 * on the changes in transaction. 326 */ onTransactionReady(@onNull TaskFragmentTransaction transaction)327 public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) { 328 // Notify the server to finish the transaction. 329 onTransactionHandled(transaction.getTransactionToken(), new WindowContainerTransaction(), 330 TASK_FRAGMENT_TRANSIT_NONE, false /* shouldApplyIndependently */); 331 } 332 333 private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { 334 @Override 335 public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) { 336 mExecutor.execute(() -> TaskFragmentOrganizer.this.onTransactionReady(transaction)); 337 } 338 }; 339 340 private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface); 341 342 @NonNull getOrganizerToken()343 public TaskFragmentOrganizerToken getOrganizerToken() { 344 return mToken; 345 } 346 getController()347 private ITaskFragmentOrganizerController getController() { 348 try { 349 return getWindowOrganizerController().getTaskFragmentOrganizerController(); 350 } catch (RemoteException e) { 351 return null; 352 } 353 } 354 355 /** 356 * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and 357 * only occupies a portion of Task bounds. 358 * @hide 359 */ isActivityEmbedded(@onNull IBinder activityToken)360 public boolean isActivityEmbedded(@NonNull IBinder activityToken) { 361 try { 362 return getController().isActivityEmbedded(activityToken); 363 } catch (RemoteException e) { 364 throw e.rethrowFromSystemServer(); 365 } 366 } 367 } 368