• 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 
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