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