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 android.annotation.CallSuper;
20 import android.annotation.NonNull;
21 import android.annotation.TestApi;
22 import android.content.res.Configuration;
23 import android.os.Bundle;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.view.RemoteAnimationDefinition;
27 
28 import java.util.concurrent.Executor;
29 
30 /**
31  * Interface for WindowManager to delegate control of {@code TaskFragment}.
32  * @hide
33  */
34 @TestApi
35 public class TaskFragmentOrganizer extends WindowOrganizer {
36 
37     /**
38      * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}.
39      */
40     private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception";
41 
42     /**
43      * Creates a {@link Bundle} with an exception that can be passed to
44      * {@link ITaskFragmentOrganizer#onTaskFragmentError}.
45      * @hide
46      */
putExceptionInBundle(@onNull Throwable exception)47     public static Bundle putExceptionInBundle(@NonNull Throwable exception) {
48         final Bundle exceptionBundle = new Bundle();
49         exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception);
50         return exceptionBundle;
51     }
52 
53     /**
54      * Callbacks from WM Core are posted on this executor.
55      */
56     private final Executor mExecutor;
57 
TaskFragmentOrganizer(@onNull Executor executor)58     public TaskFragmentOrganizer(@NonNull Executor executor) {
59         mExecutor = executor;
60     }
61 
62     /**
63      * Gets the executor to run callbacks on.
64      */
65     @NonNull
getExecutor()66     public Executor getExecutor() {
67         return mExecutor;
68     }
69 
70     /**
71      * Registers a TaskFragmentOrganizer to manage TaskFragments.
72      */
73     @CallSuper
registerOrganizer()74     public void registerOrganizer() {
75         try {
76             getController().registerOrganizer(mInterface);
77         } catch (RemoteException e) {
78             throw e.rethrowFromSystemServer();
79         }
80     }
81 
82     /**
83      * Unregisters a previously registered TaskFragmentOrganizer.
84      */
85     @CallSuper
unregisterOrganizer()86     public void unregisterOrganizer() {
87         try {
88             getController().unregisterOrganizer(mInterface);
89         } catch (RemoteException e) {
90             throw e.rethrowFromSystemServer();
91         }
92     }
93 
94     /**
95      * Registers remote animations per transition type for the organizer. It will override the
96      * animations if the transition only contains windows that belong to the organized
97      * TaskFragments.
98      * @hide
99      */
100     @CallSuper
registerRemoteAnimations(@onNull RemoteAnimationDefinition definition)101     public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
102         try {
103             getController().registerRemoteAnimations(mInterface, definition);
104         } catch (RemoteException e) {
105             throw e.rethrowFromSystemServer();
106         }
107     }
108 
109     /**
110      * Unregisters remote animations per transition type for the organizer.
111      * @hide
112      */
113     @CallSuper
unregisterRemoteAnimations()114     public void unregisterRemoteAnimations() {
115         try {
116             getController().unregisterRemoteAnimations(mInterface);
117         } catch (RemoteException e) {
118             throw e.rethrowFromSystemServer();
119         }
120     }
121 
122     /** Called when a TaskFragment is created and organized by this organizer. */
onTaskFragmentAppeared(@onNull TaskFragmentInfo taskFragmentInfo)123     public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {}
124 
125     /** Called when the status of an organized TaskFragment is changed. */
onTaskFragmentInfoChanged(@onNull TaskFragmentInfo taskFragmentInfo)126     public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {}
127 
128     /** Called when an organized TaskFragment is removed. */
onTaskFragmentVanished(@onNull TaskFragmentInfo taskFragmentInfo)129     public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {}
130 
131     /**
132      * Called when the parent leaf Task of organized TaskFragments is changed.
133      * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
134      * transaction.
135      *
136      * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
137      * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
138      * bounds.
139      */
onTaskFragmentParentInfoChanged( @onNull IBinder fragmentToken, @NonNull Configuration parentConfig)140     public void onTaskFragmentParentInfoChanged(
141             @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
142 
143     /**
144      * Called when the {@link WindowContainerTransaction} created with
145      * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
146      *
147      * @param errorCallbackToken    token set in
148      *                             {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
149      * @param exception             exception from the server side.
150      */
onTaskFragmentError( @onNull IBinder errorCallbackToken, @NonNull Throwable exception)151     public void onTaskFragmentError(
152             @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {}
153 
154     @Override
applyTransaction(@onNull WindowContainerTransaction t)155     public void applyTransaction(@NonNull WindowContainerTransaction t) {
156         t.setTaskFragmentOrganizer(mInterface);
157         super.applyTransaction(t);
158     }
159 
160     // Suppress the lint because it is not a registration method.
161     @SuppressWarnings("ExecutorRegistration")
162     @Override
applySyncTransaction(@onNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback)163     public int applySyncTransaction(@NonNull WindowContainerTransaction t,
164             @NonNull WindowContainerTransactionCallback callback) {
165         t.setTaskFragmentOrganizer(mInterface);
166         return super.applySyncTransaction(t, callback);
167     }
168 
169     private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
170         @Override
171         public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
172             mExecutor.execute(
173                     () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo));
174         }
175 
176         @Override
177         public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
178             mExecutor.execute(
179                     () -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo));
180         }
181 
182         @Override
183         public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
184             mExecutor.execute(
185                     () -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo));
186         }
187 
188         @Override
189         public void onTaskFragmentParentInfoChanged(
190                 @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
191             mExecutor.execute(
192                     () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged(
193                             fragmentToken, parentConfig));
194         }
195 
196         @Override
197         public void onTaskFragmentError(
198                 @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) {
199             mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError(
200                     errorCallbackToken,
201                     (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION)));
202         }
203     };
204 
205     private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface);
206 
207     @NonNull
getOrganizerToken()208     public TaskFragmentOrganizerToken getOrganizerToken() {
209         return mToken;
210     }
211 
getController()212     private ITaskFragmentOrganizerController getController() {
213         try {
214             return getWindowOrganizerController().getTaskFragmentOrganizerController();
215         } catch (RemoteException e) {
216             return null;
217         }
218     }
219 
220     /**
221      * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and
222      * only occupies a portion of Task bounds.
223      * @hide
224      */
isActivityEmbedded(@onNull IBinder activityToken)225     public boolean isActivityEmbedded(@NonNull IBinder activityToken) {
226         try {
227             return getController().isActivityEmbedded(activityToken);
228         } catch (RemoteException e) {
229             throw e.rethrowFromSystemServer();
230         }
231     }
232 }
233