• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 java.util.Objects.requireNonNull;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.content.Intent;
26 import android.content.res.Configuration;
27 import android.os.Binder;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Used to communicate information about what are changing on embedded TaskFragments belonging to
40  * the same TaskFragmentOrganizer. A transaction can contain multiple changes.
41  * @see TaskFragmentTransaction.Change
42  * @hide
43  */
44 public final class TaskFragmentTransaction implements Parcelable {
45 
46     /** Unique token to represent this transaction. */
47     private final IBinder mTransactionToken;
48 
49     /** Changes in this transaction. */
50     private final ArrayList<Change> mChanges = new ArrayList<>();
51 
TaskFragmentTransaction()52     public TaskFragmentTransaction() {
53         mTransactionToken = new Binder();
54     }
55 
TaskFragmentTransaction(Parcel in)56     private TaskFragmentTransaction(Parcel in) {
57         mTransactionToken = in.readStrongBinder();
58         in.readTypedList(mChanges, Change.CREATOR);
59     }
60 
61     @Override
writeToParcel(@onNull Parcel dest, int flags)62     public void writeToParcel(@NonNull Parcel dest, int flags) {
63         dest.writeStrongBinder(mTransactionToken);
64         dest.writeTypedList(mChanges);
65     }
66 
67     @NonNull
getTransactionToken()68     public IBinder getTransactionToken() {
69         return mTransactionToken;
70     }
71 
72     /** Adds a {@link Change} to this transaction. */
addChange(@ullable Change change)73     public void addChange(@Nullable Change change) {
74         if (change != null) {
75             mChanges.add(change);
76         }
77     }
78 
79     /** Whether this transaction contains any {@link Change}. */
isEmpty()80     public boolean isEmpty() {
81         return mChanges.isEmpty();
82     }
83 
84     @NonNull
getChanges()85     public List<Change> getChanges() {
86         return mChanges;
87     }
88 
89     @Override
toString()90     public String toString() {
91         StringBuilder sb = new StringBuilder();
92         sb.append("TaskFragmentTransaction{token=");
93         sb.append(mTransactionToken);
94         sb.append(" changes=[");
95         for (int i = 0; i < mChanges.size(); ++i) {
96             if (i > 0) {
97                 sb.append(',');
98             }
99             sb.append(mChanges.get(i));
100         }
101         sb.append("]}");
102         return sb.toString();
103     }
104 
105     @Override
describeContents()106     public int describeContents() {
107         return 0;
108     }
109 
110     @NonNull
111     public static final Creator<TaskFragmentTransaction> CREATOR = new Creator<>() {
112         @Override
113         public TaskFragmentTransaction createFromParcel(Parcel in) {
114             return new TaskFragmentTransaction(in);
115         }
116 
117         @Override
118         public TaskFragmentTransaction[] newArray(int size) {
119             return new TaskFragmentTransaction[size];
120         }
121     };
122 
123     /** Change type: the TaskFragment is attached to the hierarchy. */
124     public static final int TYPE_TASK_FRAGMENT_APPEARED = 1;
125 
126     /** Change type: the status of the TaskFragment is changed. */
127     public static final int TYPE_TASK_FRAGMENT_INFO_CHANGED = 2;
128 
129     /** Change type: the TaskFragment is removed form the hierarchy. */
130     public static final int TYPE_TASK_FRAGMENT_VANISHED = 3;
131 
132     /** Change type: the status of the parent leaf Task is changed. */
133     public static final int TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED = 4;
134 
135     /** Change type: the TaskFragment related operation failed on the server side. */
136     public static final int TYPE_TASK_FRAGMENT_ERROR = 5;
137 
138     /**
139      * Change type: an Activity is reparented to the Task. For example, when an Activity enters and
140      * then exits Picture-in-picture, it will be reparented back to its original Task. In this case,
141      * we need to notify the organizer so that it can check if the Activity matches any split rule.
142      */
143     public static final int TYPE_ACTIVITY_REPARENTED_TO_TASK = 6;
144 
145     @IntDef(prefix = { "TYPE_" }, value = {
146             TYPE_TASK_FRAGMENT_APPEARED,
147             TYPE_TASK_FRAGMENT_INFO_CHANGED,
148             TYPE_TASK_FRAGMENT_VANISHED,
149             TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED,
150             TYPE_TASK_FRAGMENT_ERROR,
151             TYPE_ACTIVITY_REPARENTED_TO_TASK
152     })
153     @Retention(RetentionPolicy.SOURCE)
154     @interface ChangeType {}
155 
156     /** Represents the change an embedded TaskFragment undergoes. */
157     public static final class Change implements Parcelable {
158 
159         /** @see ChangeType */
160         @ChangeType
161         private final int mType;
162 
163         /** @see #setTaskFragmentToken(IBinder) */
164         @Nullable
165         private IBinder mTaskFragmentToken;
166 
167         /** @see #setTaskFragmentInfo(TaskFragmentInfo) */
168         @Nullable
169         private TaskFragmentInfo mTaskFragmentInfo;
170 
171         /** @see #setTaskId(int) */
172         private int mTaskId;
173 
174         /** @see #setErrorCallbackToken(IBinder) */
175         @Nullable
176         private IBinder mErrorCallbackToken;
177 
178         /** @see #setErrorBundle(Bundle) */
179         @Nullable
180         private Bundle mErrorBundle;
181 
182         /** @see #setActivityIntent(Intent) */
183         @Nullable
184         private Intent mActivityIntent;
185 
186         /** @see #setActivityToken(IBinder) */
187         @Nullable
188         private IBinder mActivityToken;
189 
190         @Nullable
191         private TaskFragmentParentInfo mTaskFragmentParentInfo;
192 
Change(@hangeType int type)193         public Change(@ChangeType int type) {
194             mType = type;
195         }
196 
Change(Parcel in)197         private Change(Parcel in) {
198             mType = in.readInt();
199             mTaskFragmentToken = in.readStrongBinder();
200             mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR);
201             mTaskId = in.readInt();
202             mErrorCallbackToken = in.readStrongBinder();
203             mErrorBundle = in.readBundle(TaskFragmentTransaction.class.getClassLoader());
204             mActivityIntent = in.readTypedObject(Intent.CREATOR);
205             mActivityToken = in.readStrongBinder();
206             mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
207         }
208 
209         @Override
writeToParcel(@onNull Parcel dest, int flags)210         public void writeToParcel(@NonNull Parcel dest, int flags) {
211             dest.writeInt(mType);
212             dest.writeStrongBinder(mTaskFragmentToken);
213             dest.writeTypedObject(mTaskFragmentInfo, flags);
214             dest.writeInt(mTaskId);
215             dest.writeStrongBinder(mErrorCallbackToken);
216             dest.writeBundle(mErrorBundle);
217             dest.writeTypedObject(mActivityIntent, flags);
218             dest.writeStrongBinder(mActivityToken);
219             dest.writeTypedObject(mTaskFragmentParentInfo, flags);
220         }
221 
222         /** The change is related to the TaskFragment created with this unique token. */
223         @NonNull
setTaskFragmentToken(@onNull IBinder taskFragmentToken)224         public Change setTaskFragmentToken(@NonNull IBinder taskFragmentToken) {
225             mTaskFragmentToken = requireNonNull(taskFragmentToken);
226             return this;
227         }
228 
229         /** Info of the embedded TaskFragment. */
230         @NonNull
setTaskFragmentInfo(@onNull TaskFragmentInfo info)231         public Change setTaskFragmentInfo(@NonNull TaskFragmentInfo info) {
232             mTaskFragmentInfo = requireNonNull(info);
233             return this;
234         }
235 
236         /** Task id the parent Task. */
237         @NonNull
setTaskId(int taskId)238         public Change setTaskId(int taskId) {
239             mTaskId = taskId;
240             return this;
241         }
242 
243         // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
244         /** Configuration of the parent Task. */
245         @NonNull
setTaskConfiguration(@onNull Configuration configuration)246         public Change setTaskConfiguration(@NonNull Configuration configuration) {
247             return this;
248         }
249 
250         /**
251          * If the {@link #TYPE_TASK_FRAGMENT_ERROR} is from a {@link WindowContainerTransaction}
252          * from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
253          * report back.
254          */
255         @NonNull
setErrorCallbackToken(@ullable IBinder errorCallbackToken)256         public Change setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
257             mErrorCallbackToken = errorCallbackToken;
258             return this;
259         }
260 
261         /**
262          * Bundle with necessary info about the failure operation of
263          * {@link #TYPE_TASK_FRAGMENT_ERROR}.
264          */
265         @NonNull
setErrorBundle(@onNull Bundle errorBundle)266         public Change setErrorBundle(@NonNull Bundle errorBundle) {
267             mErrorBundle = requireNonNull(errorBundle);
268             return this;
269         }
270 
271         /**
272          * Intent of the activity that is reparented to the Task for
273          * {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
274          */
275         @NonNull
setActivityIntent(@onNull Intent intent)276         public Change setActivityIntent(@NonNull Intent intent) {
277             mActivityIntent = requireNonNull(intent);
278             return this;
279         }
280 
281         /**
282          * Token of the reparent activity for {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
283          * If the activity belongs to the same process as the organizer, this will be the actual
284          * activity token; if the activity belongs to a different process, the server will generate
285          * a temporary token that the organizer can use to reparent the activity through
286          * {@link WindowContainerTransaction} if needed.
287          */
288         @NonNull
setActivityToken(@onNull IBinder activityToken)289         public Change setActivityToken(@NonNull IBinder activityToken) {
290             mActivityToken = requireNonNull(activityToken);
291             return this;
292         }
293 
294         // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
295         /**
296          * Sets info of the parent Task of the embedded TaskFragment.
297          * @see TaskFragmentParentInfo
298          *
299          * @hide pending unhide
300          */
301         @NonNull
setTaskFragmentParentInfo(@onNull TaskFragmentParentInfo info)302         public Change setTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
303             mTaskFragmentParentInfo = requireNonNull(info);
304             return this;
305         }
306 
307         @ChangeType
getType()308         public int getType() {
309             return mType;
310         }
311 
312         @Nullable
getTaskFragmentToken()313         public IBinder getTaskFragmentToken() {
314             return mTaskFragmentToken;
315         }
316 
317         @Nullable
getTaskFragmentInfo()318         public TaskFragmentInfo getTaskFragmentInfo() {
319             return mTaskFragmentInfo;
320         }
321 
getTaskId()322         public int getTaskId() {
323             return mTaskId;
324         }
325 
326         // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
327         @Nullable
getTaskConfiguration()328         public Configuration getTaskConfiguration() {
329             return mTaskFragmentParentInfo.getConfiguration();
330         }
331 
332         @Nullable
getErrorCallbackToken()333         public IBinder getErrorCallbackToken() {
334             return mErrorCallbackToken;
335         }
336 
337         @NonNull
getErrorBundle()338         public Bundle getErrorBundle() {
339             return mErrorBundle != null ? mErrorBundle : Bundle.EMPTY;
340         }
341 
342         @SuppressLint("IntentBuilderName") // This is not creating new Intent.
343         @Nullable
getActivityIntent()344         public Intent getActivityIntent() {
345             return mActivityIntent;
346         }
347 
348         @Nullable
getActivityToken()349         public IBinder getActivityToken() {
350             return mActivityToken;
351         }
352 
353         // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
354         /** @hide pending unhide */
355         @Nullable
getTaskFragmentParentInfo()356         public TaskFragmentParentInfo getTaskFragmentParentInfo() {
357             return mTaskFragmentParentInfo;
358         }
359 
360         @Override
toString()361         public String toString() {
362             return "Change{ type=" + mType + " }";
363         }
364 
365         @Override
describeContents()366         public int describeContents() {
367             return 0;
368         }
369 
370         @NonNull
371         public static final Creator<Change> CREATOR = new Creator<>() {
372             @Override
373             public Change createFromParcel(Parcel in) {
374                 return new Change(in);
375             }
376 
377             @Override
378             public Change[] newArray(int size) {
379                 return new Change[size];
380             }
381         };
382     }
383 }
384