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