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