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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 20 import static android.app.WindowConfiguration.WindowingMode; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.RequiresPermission; 26 import android.annotation.TestApi; 27 import android.content.pm.ActivityInfo; 28 import android.content.pm.ActivityInfo.ScreenOrientation; 29 import android.graphics.Rect; 30 import android.os.IBinder; 31 import android.os.Parcel; 32 import android.os.Parcelable; 33 34 /** 35 * Data object for options to create TaskFragment with. 36 * @hide 37 */ 38 @TestApi 39 public final class TaskFragmentCreationParams implements Parcelable { 40 41 /** The organizer that will organize this TaskFragment. */ 42 @NonNull 43 private final TaskFragmentOrganizerToken mOrganizer; 44 45 /** 46 * Unique token assigned from the client organizer to identify the {@link TaskFragmentInfo} when 47 * a new TaskFragment is created with this option. 48 */ 49 @NonNull 50 private final IBinder mFragmentToken; 51 52 /** 53 * Activity token used to identify the leaf Task to create the TaskFragment in. It has to belong 54 * to the same app as the root Activity of the target Task. 55 */ 56 @NonNull 57 private final IBinder mOwnerToken; 58 59 /** 60 * The initial relative bounds of the TaskFragment in parent coordinate. 61 * Fills parent if empty. 62 */ 63 @NonNull 64 private final Rect mInitialRelativeBounds = new Rect(); 65 66 /** The initial windowing mode of the TaskFragment. Inherits from parent if not set. */ 67 @WindowingMode 68 private final int mWindowingMode; 69 70 /** 71 * The fragment token of the paired primary TaskFragment. 72 * When it is set, the new TaskFragment will be positioned right above the paired TaskFragment. 73 * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. 74 * 75 * This is different from {@link WindowContainerTransaction#setAdjacentTaskFragments} as we may 76 * set this when the pair of TaskFragments are stacked, while adjacent is only set on the pair 77 * of TaskFragments that are in split. 78 * 79 * This is needed in case we need to launch a placeholder Activity to split below a transparent 80 * always-expand Activity. 81 * 82 * This should not be used with {@link #mPairedActivityToken}. 83 */ 84 @Nullable 85 private final IBinder mPairedPrimaryFragmentToken; 86 87 /** 88 * The Activity token to place the new TaskFragment on top of. 89 * When it is set, the new TaskFragment will be positioned right above the target Activity. 90 * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. 91 * 92 * This is needed in case we need to place an Activity into TaskFragment to launch placeholder 93 * below a transparent always-expand Activity, or when there is another Intent being started in 94 * a TaskFragment above. 95 * 96 * This should not be used with {@link #mPairedPrimaryFragmentToken}. 97 */ 98 @Nullable 99 private final IBinder mPairedActivityToken; 100 101 /** 102 * If {@code true}, transitions are allowed even if the TaskFragment is empty. If 103 * {@code false}, transitions will wait until the TaskFragment becomes non-empty or other 104 * conditions are met. Default to {@code false}. 105 */ 106 private final boolean mAllowTransitionWhenEmpty; 107 108 /** 109 * The override orientation for the TaskFragment. This is effective only for a system organizer. 110 * The value is ignored otherwise. Default to {@code SCREEN_ORIENTATION_UNSPECIFIED}. 111 * 112 * @see TaskFragmentOrganizer#registerOrganizer(boolean) 113 */ 114 private final @ScreenOrientation int mOverrideOrientation; 115 116 /** 117 * {@link android.content.pm.ActivityInfo.Config} mask that specifies which 118 * configuration changes should trigger TaskFragment info change callbacks. 119 * 120 * @see android.content.pm.ActivityInfo.Config 121 */ 122 private final @ActivityInfo.Config int mConfigurationChangeMask; 123 TaskFragmentCreationParams( @onNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @Nullable IBinder pairedActivityToken, boolean allowTransitionWhenEmpty, @ScreenOrientation int overrideOrientation, @ActivityInfo.Config int configurationChangeMask)124 private TaskFragmentCreationParams( 125 @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, 126 @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, 127 @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, 128 @Nullable IBinder pairedActivityToken, boolean allowTransitionWhenEmpty, 129 @ScreenOrientation int overrideOrientation, 130 @ActivityInfo.Config int configurationChangeMask) { 131 if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { 132 throw new IllegalArgumentException("pairedPrimaryFragmentToken and" 133 + " pairedActivityToken should not be set at the same time."); 134 } 135 mOrganizer = organizer; 136 mFragmentToken = fragmentToken; 137 mOwnerToken = ownerToken; 138 mInitialRelativeBounds.set(initialRelativeBounds); 139 mWindowingMode = windowingMode; 140 mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; 141 mPairedActivityToken = pairedActivityToken; 142 mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; 143 mOverrideOrientation = overrideOrientation; 144 mConfigurationChangeMask = configurationChangeMask; 145 } 146 147 @NonNull getOrganizer()148 public TaskFragmentOrganizerToken getOrganizer() { 149 return mOrganizer; 150 } 151 152 @NonNull getFragmentToken()153 public IBinder getFragmentToken() { 154 return mFragmentToken; 155 } 156 157 @NonNull getOwnerToken()158 public IBinder getOwnerToken() { 159 return mOwnerToken; 160 } 161 162 @NonNull getInitialRelativeBounds()163 public Rect getInitialRelativeBounds() { 164 return mInitialRelativeBounds; 165 } 166 167 @WindowingMode getWindowingMode()168 public int getWindowingMode() { 169 return mWindowingMode; 170 } 171 172 /** 173 * TODO(b/232476698): remove the hide with adding CTS for this in next release. 174 * @hide 175 */ 176 @Nullable getPairedPrimaryFragmentToken()177 public IBinder getPairedPrimaryFragmentToken() { 178 return mPairedPrimaryFragmentToken; 179 } 180 181 /** 182 * TODO(b/232476698): remove the hide with adding CTS for this in next release. 183 * @hide 184 */ 185 @Nullable getPairedActivityToken()186 public IBinder getPairedActivityToken() { 187 return mPairedActivityToken; 188 } 189 190 /** @hide */ getAllowTransitionWhenEmpty()191 public boolean getAllowTransitionWhenEmpty() { 192 return mAllowTransitionWhenEmpty; 193 } 194 195 /** @hide */ getOverrideOrientation()196 public @ScreenOrientation int getOverrideOrientation() { 197 return mOverrideOrientation; 198 } 199 200 /** @hide */ getConfigurationChangeMask()201 public @ActivityInfo.Config int getConfigurationChangeMask() { 202 return mConfigurationChangeMask; 203 } 204 TaskFragmentCreationParams(Parcel in)205 private TaskFragmentCreationParams(Parcel in) { 206 mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); 207 mFragmentToken = in.readStrongBinder(); 208 mOwnerToken = in.readStrongBinder(); 209 mInitialRelativeBounds.readFromParcel(in); 210 mWindowingMode = in.readInt(); 211 mPairedPrimaryFragmentToken = in.readStrongBinder(); 212 mPairedActivityToken = in.readStrongBinder(); 213 mAllowTransitionWhenEmpty = in.readBoolean(); 214 mOverrideOrientation = in.readInt(); 215 mConfigurationChangeMask = in.readInt(); 216 } 217 218 /** @hide */ 219 @Override writeToParcel(@onNull Parcel dest, int flags)220 public void writeToParcel(@NonNull Parcel dest, int flags) { 221 mOrganizer.writeToParcel(dest, flags); 222 dest.writeStrongBinder(mFragmentToken); 223 dest.writeStrongBinder(mOwnerToken); 224 mInitialRelativeBounds.writeToParcel(dest, flags); 225 dest.writeInt(mWindowingMode); 226 dest.writeStrongBinder(mPairedPrimaryFragmentToken); 227 dest.writeStrongBinder(mPairedActivityToken); 228 dest.writeBoolean(mAllowTransitionWhenEmpty); 229 dest.writeInt(mOverrideOrientation); 230 dest.writeInt(mConfigurationChangeMask); 231 } 232 233 @NonNull 234 public static final Creator<TaskFragmentCreationParams> CREATOR = 235 new Creator<TaskFragmentCreationParams>() { 236 @Override 237 public TaskFragmentCreationParams createFromParcel(Parcel in) { 238 return new TaskFragmentCreationParams(in); 239 } 240 241 @Override 242 public TaskFragmentCreationParams[] newArray(int size) { 243 return new TaskFragmentCreationParams[size]; 244 } 245 }; 246 247 @Override toString()248 public String toString() { 249 return "TaskFragmentCreationParams{" 250 + " organizer=" + mOrganizer 251 + " fragmentToken=" + mFragmentToken 252 + " ownerToken=" + mOwnerToken 253 + " initialRelativeBounds=" + mInitialRelativeBounds 254 + " windowingMode=" + mWindowingMode 255 + " pairedFragmentToken=" + mPairedPrimaryFragmentToken 256 + " pairedActivityToken=" + mPairedActivityToken 257 + " allowTransitionWhenEmpty=" + mAllowTransitionWhenEmpty 258 + " overrideOrientation=" + mOverrideOrientation 259 + " configurationChangeMask=" + mConfigurationChangeMask 260 + "}"; 261 } 262 263 /** @hide */ 264 @Override describeContents()265 public int describeContents() { 266 return 0; 267 } 268 269 /** Builder to construct the options to create TaskFragment with. */ 270 public static final class Builder { 271 272 @NonNull 273 private final TaskFragmentOrganizerToken mOrganizer; 274 275 @NonNull 276 private final IBinder mFragmentToken; 277 278 @NonNull 279 private final IBinder mOwnerToken; 280 281 @NonNull 282 private final Rect mInitialRelativeBounds = new Rect(); 283 284 @WindowingMode 285 private int mWindowingMode = WINDOWING_MODE_UNDEFINED; 286 287 @Nullable 288 private IBinder mPairedPrimaryFragmentToken; 289 290 @Nullable 291 private IBinder mPairedActivityToken; 292 293 private boolean mAllowTransitionWhenEmpty; 294 295 private @ScreenOrientation int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 296 297 private @ActivityInfo.Config int mConfigurationChangeMask = 0; 298 Builder(@onNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken)299 public Builder(@NonNull TaskFragmentOrganizerToken organizer, 300 @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { 301 mOrganizer = organizer; 302 mFragmentToken = fragmentToken; 303 mOwnerToken = ownerToken; 304 } 305 306 /** 307 * Sets the initial relative bounds for the TaskFragment in parent coordinate. 308 * Set to empty to fill parent. 309 */ 310 @NonNull setInitialRelativeBounds(@onNull Rect bounds)311 public Builder setInitialRelativeBounds(@NonNull Rect bounds) { 312 mInitialRelativeBounds.set(bounds); 313 return this; 314 } 315 316 /** Sets the initial windowing mode for the TaskFragment. */ 317 @NonNull setWindowingMode(@indowingMode int windowingMode)318 public Builder setWindowingMode(@WindowingMode int windowingMode) { 319 mWindowingMode = windowingMode; 320 return this; 321 } 322 323 /** 324 * Sets the fragment token of the paired primary TaskFragment. 325 * When it is set, the new TaskFragment will be positioned right above the paired 326 * TaskFragment. Otherwise, the new TaskFragment will be positioned on the top of the Task 327 * by default. 328 * 329 * This is needed in case we need to launch a placeholder Activity to split below a 330 * transparent always-expand Activity. 331 * 332 * This should not be used with {@link #setPairedActivityToken}. 333 * 334 * TODO(b/232476698): remove the hide with adding CTS for this in next release. 335 * @hide 336 */ 337 @NonNull setPairedPrimaryFragmentToken(@ullable IBinder fragmentToken)338 public Builder setPairedPrimaryFragmentToken(@Nullable IBinder fragmentToken) { 339 mPairedPrimaryFragmentToken = fragmentToken; 340 return this; 341 } 342 343 /** 344 * Sets the Activity token to place the new TaskFragment on top of. 345 * When it is set, the new TaskFragment will be positioned right above the target Activity. 346 * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. 347 * 348 * This is needed in case we need to place an Activity into TaskFragment to launch 349 * placeholder below a transparent always-expand Activity, or when there is another Intent 350 * being started in a TaskFragment above. 351 * 352 * This should not be used with {@link #setPairedPrimaryFragmentToken}. 353 * 354 * TODO(b/232476698): remove the hide with adding CTS for this in next release. 355 * @hide 356 */ 357 @NonNull setPairedActivityToken(@ullable IBinder activityToken)358 public Builder setPairedActivityToken(@Nullable IBinder activityToken) { 359 mPairedActivityToken = activityToken; 360 return this; 361 } 362 363 /** 364 * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, 365 * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions 366 * will wait until the TaskFragment becomes non-empty or other conditions are met. Default 367 * to {@code false}. 368 * 369 * @hide 370 */ 371 @NonNull setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty)372 public Builder setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { 373 mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; 374 return this; 375 } 376 377 /** 378 * Sets the override orientation for the TaskFragment. This is effective only for a system 379 * organizer. The value is ignored otherwise. Default to 380 * {@code SCREEN_ORIENTATION_UNSPECIFIED}. 381 * 382 * @see TaskFragmentOrganizer#registerOrganizer(boolean) 383 * 384 * @hide 385 */ 386 @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS) 387 @NonNull setOverrideOrientation(@creenOrientation int overrideOrientation)388 public Builder setOverrideOrientation(@ScreenOrientation int overrideOrientation) { 389 mOverrideOrientation = overrideOrientation; 390 return this; 391 } 392 393 /** 394 * Sets {@link android.content.pm.ActivityInfo.Config} mask that specifies which 395 * configuration changes should trigger TaskFragment info change callbacks. 396 * 397 * Only system organizers are allowed to configure this value. This value is ignored for 398 * non-system organizers. 399 * 400 * @see android.content.pm.ActivityInfo.Config 401 * @hide 402 */ 403 @NonNull setConfigurationChangeMask( @ctivityInfo.Config int configurationChangeMask)404 public Builder setConfigurationChangeMask( 405 @ActivityInfo.Config int configurationChangeMask) { 406 mConfigurationChangeMask = configurationChangeMask; 407 return this; 408 } 409 410 /** Constructs the options to create TaskFragment with. */ 411 @NonNull build()412 public TaskFragmentCreationParams build() { 413 return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, 414 mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken, 415 mPairedActivityToken, mAllowTransitionWhenEmpty, mOverrideOrientation, 416 mConfigurationChangeMask); 417 } 418 } 419 } 420