1 /* 2 * Copyright (C) 2020 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 com.google.android.setupdesign.transition; 18 19 import android.annotation.TargetApi; 20 import android.app.Activity; 21 import android.app.ActivityOptions; 22 import android.app.Fragment; 23 import android.content.ActivityNotFoundException; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.res.TypedArray; 27 import android.os.Build.VERSION_CODES; 28 import android.os.Bundle; 29 import android.util.Log; 30 import androidx.annotation.IntDef; 31 import androidx.annotation.Nullable; 32 import androidx.annotation.VisibleForTesting; 33 import com.google.android.setupcompat.partnerconfig.PartnerConfig; 34 import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper; 35 import com.google.android.setupcompat.util.BuildCompatUtils; 36 import com.google.android.setupdesign.R; 37 import com.google.android.setupdesign.util.ThemeHelper; 38 import com.google.errorprone.annotations.InlineMe; 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 42 /** Helper class for apply the transition to the pages which uses platform version. */ 43 public class TransitionHelper { 44 45 private static final String TAG = "TransitionHelper"; 46 47 /* 48 * In Setup Wizard, all Just-a-sec style screens (i.e. screens that has an indeterminate 49 * progress bar and automatically finishes itself), should do a cross-fade when entering or 50 * exiting the screen. For all other screens, the transition should be a slide-in-from-right 51 * or customized. 52 * 53 * We use two different ways to override the transitions. The first is calling 54 * overridePendingTransition in code, and the second is using windowAnimationStyle in the theme. 55 * They have the following priority when framework is figuring out what transition to use: 56 * 1. overridePendingTransition, entering activity (highest priority) 57 * 2. overridePendingTransition, exiting activity 58 * 3. windowAnimationStyle, entering activity 59 * 4. windowAnimationStyle, exiting activity 60 * 61 * This is why, in general, overridePendingTransition is used to specify the fade animation, 62 * while windowAnimationStyle is used to specify the slide transition. This way fade animation 63 * will take priority over the slide animation. 64 * 65 * Below are types of animation when switching activities. These are return values for 66 * {@link #getTransition()}. Each of these values represents 4 animations: (backward exit, 67 * backward enter, forward exit, forward enter). 68 * 69 * We override the transition in the following flow 70 * +--------------+-------------------------+--------------------------+ 71 * | | going forward | going backward | 72 * +--------------+-------------------------+--------------------------+ 73 * | old activity | startActivity(OnResult) | onActivityResult | 74 * +--------------+-------------------------+--------------------------+ 75 * | new activity | onStart | finish (RESULT_CANCELED) | 76 * +--------------+-------------------------+--------------------------+ 77 */ 78 79 /** The constant of transition type. */ 80 @Retention(RetentionPolicy.SOURCE) 81 @IntDef({ 82 TRANSITION_NONE, 83 TRANSITION_NO_OVERRIDE, 84 TRANSITION_FRAMEWORK_DEFAULT, 85 TRANSITION_SLIDE, 86 TRANSITION_FADE, 87 TRANSITION_FRAMEWORK_DEFAULT_PRE_P, 88 TRANSITION_CAPTIVE, 89 TRANSITION_FADE_THROUGH, 90 }) 91 public @interface TransitionType {} 92 93 /** No transition, as in overridePendingTransition(0, 0). */ 94 public static final int TRANSITION_NONE = -1; 95 96 /** 97 * No override. If this is specified as the transition, overridePendingTransition will not be 98 * called. 99 */ 100 public static final int TRANSITION_NO_OVERRIDE = 0; 101 102 /** 103 * Override the transition to the framework default. This values are read from {@link 104 * android.R.style#Animation_Activity}. 105 */ 106 public static final int TRANSITION_FRAMEWORK_DEFAULT = 1; 107 108 /** Override the transition to a slide-in-from-right (or from-left for RTL locales). */ 109 public static final int TRANSITION_SLIDE = 2; 110 111 /** 112 * Override the transition to fade in the new activity, while keeping the old activity. Setup 113 * wizard does not use cross fade to avoid the bright-dim-bright effect when transitioning between 114 * two screens that look similar. 115 */ 116 public static final int TRANSITION_FADE = 3; 117 118 /** Override the transition to the old framework default pre P. */ 119 public static final int TRANSITION_FRAMEWORK_DEFAULT_PRE_P = 4; 120 121 /** 122 * Override the transition to the specific transition and the transition type will depends on the 123 * partner resource. 124 */ 125 // TODO: Add new partner resource to determine which transition type would be apply. 126 public static final int TRANSITION_CAPTIVE = 5; 127 128 /** Override the transition to a fade-through-from-right (or from-left for RTL locales). */ 129 public static final int TRANSITION_FADE_THROUGH = 6; 130 131 /** 132 * No override. If this is specified as the transition, the enter/exit transition of the window 133 * will not be set and keep original behavior. 134 */ 135 public static final int CONFIG_TRANSITION_NONE = 0; 136 137 /** Override the transition to the specific type that will depend on the partner resource. */ 138 public static final int CONFIG_TRANSITION_SHARED_X_AXIS = 1; 139 140 /** 141 * Passed in an intent as EXTRA_ACTIVITY_OPTIONS. This is the {@link ActivityOptions} of the 142 * transition used in {@link Activity#startActivity} or {@link Activity#startActivityForResult}. 143 * 144 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 145 * activity options input. 146 */ 147 @Deprecated public static final String EXTRA_ACTIVITY_OPTIONS = "sud:activity_options"; 148 149 /** A flag to avoid the {@link Activity#finish} been called more than once. */ 150 @VisibleForTesting static boolean isFinishCalled = false; 151 152 /** A flag to avoid the {@link Activity#startActivity} called more than once. */ 153 @VisibleForTesting static boolean isStartActivity = false; 154 155 /** A flag to avoid the {@link Activity#startActivityForResult} called more than once. */ 156 @VisibleForTesting static boolean isStartActivityForResult = false; 157 TransitionHelper()158 private TransitionHelper() {} 159 160 /** 161 * Apply the transition for going forward which is decided by {@code Animation.SudWindowAnimation} 162 * theme if the API level is equal or higher than {@link android.os.Build.VERSION_CODES#U}. 163 * 164 * <p>Otherwise, apply the transition for going forward which is decided by partner resource 165 * {@link PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code 166 * setupwizard.transition_type} if the API level is equal or lower than {@link 167 * android.os.Build.VERSION_CODES#T}. The default transition that will be applied is {@link 168 * #TRANSITION_SLIDE}. 169 * 170 * <p>The timing to apply the transition is going forward from the previous activity to this, or 171 * going forward from this activity to the next. 172 * 173 * <p>For example, in the flow below, the forward transitions will be applied to all arrows 174 * pointing to the right. Previous screen --> This screen --> Next screen 175 */ 176 @TargetApi(VERSION_CODES.LOLLIPOP) applyForwardTransition(Activity activity)177 public static void applyForwardTransition(Activity activity) { 178 applyForwardTransition(activity, TRANSITION_CAPTIVE); 179 } 180 181 /** 182 * Apply the transition for going forward which is decided by partner resource {@link 183 * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}. 184 * The default transition that will be applied is {@link #CONFIG_TRANSITION_NONE}. The timing to 185 * apply the transition is going forward from the previous {@link Fragment} to this, or going 186 * forward from this {@link Fragment} to the next. 187 * 188 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 189 * activity options input, should start the activity directly. 190 */ 191 @TargetApi(VERSION_CODES.M) 192 @Deprecated applyForwardTransition(Fragment fragment)193 public static void applyForwardTransition(Fragment fragment) { 194 // Do nothing 195 } 196 197 /** 198 * Apply the transition for going forward which is decided by {@code Animation.SudWindowAnimation} 199 * theme if the API level is equal or higher than {@link android.os.Build.VERSION_CODES#U}. 200 * 201 * <p>Otherwise, apply the transition for going forward which is decided by the argument {@code 202 * transitionId} if the API level is equal or lower than {@link android.os.Build.VERSION_CODES#T}. 203 * 204 * <p>The timing to apply the transition is going forward from the previous activity to this, or 205 * going forward from this activity to the next. 206 */ 207 @TargetApi(VERSION_CODES.LOLLIPOP) applyForwardTransition(Activity activity, @TransitionType int transitionId)208 public static void applyForwardTransition(Activity activity, @TransitionType int transitionId) { 209 applyForwardTransition(activity, transitionId, /* useClientTransitionSettings= */ false); 210 } 211 212 /** 213 * Apply the transition for going forward which is decided by {@code Animation.SudWindowAnimation} 214 * theme if the API level is equal or higher than {@link android.os.Build.VERSION_CODES#U}, and 215 * argument {@code useClientTransitionSettings} is false, and System property {@code 216 * suw_apply_glif_theme_controlled_transition} is true, and {@code TRANSITION_FADE_THOUGH} 217 * transition is not specified. 218 * 219 * <p>Otherwise, apply the transition for going forward which is decided by the argument {@code 220 * transitionId}, {@code shared_x_axis_activity} transition is used only when {@code 221 * TRANSITION_FADE_TROUGH} transition is specified, and System property {@code * 222 * suw_apply_glif_theme_controlled_transition} is true, and the API level is equal or more than 223 * {@link android.os.Build.VERSION_CODES#U}, other {@code transitionId} can be specified if the 224 * API level is equal or lower than {@link android.os.Build.VERSION_CODES#T}, or argument {@code 225 * useClientTransitionSettings} is true, or System property {@code 226 * suw_apply_glif_theme_controlled_transition} is false. The default transition that will be 227 * applied is {@link #TRANSITION_SLIDE}. 228 * 229 * <p>The timing to apply the transition is going forward from the previous activity to this, or 230 * going forward from this activity to the next. 231 * 232 * <p>For example, in the flow below, the forward transitions will be applied to all arrows 233 * pointing to the right. Previous screen --> This screen --> Next screen 234 */ 235 @TargetApi(VERSION_CODES.LOLLIPOP) applyForwardTransition( Activity activity, @TransitionType int transitionId, boolean useClientTransitionSettings)236 public static void applyForwardTransition( 237 Activity activity, @TransitionType int transitionId, boolean useClientTransitionSettings) { 238 if (BuildCompatUtils.isAtLeastU() 239 && !useClientTransitionSettings 240 && PartnerConfigHelper.isGlifThemeControlledTransitionApplied(activity) 241 && transitionId != TRANSITION_FADE_THROUGH) { 242 // Do nothing 243 } else if (BuildCompatUtils.isAtLeastU() && transitionId == TRANSITION_FADE_THROUGH) { 244 if (PartnerConfigHelper.isGlifThemeControlledTransitionApplied(activity)) { 245 int openEnterTransition = 246 ThemeHelper.shouldApplyDynamicColor(activity) 247 ? R.anim.shared_x_axis_activity_open_enter_dynamic_color 248 : R.anim.shared_x_axis_activity_open_enter; 249 activity.overridePendingTransition( 250 openEnterTransition, R.anim.shared_x_axis_activity_open_exit); 251 } else { 252 activity.overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); 253 } 254 } else if (transitionId == TRANSITION_SLIDE) { 255 activity.overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); 256 } else if (transitionId == TRANSITION_FADE) { 257 activity.overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay); 258 } else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT) { 259 TypedArray typedArray = 260 activity.obtainStyledAttributes( 261 android.R.style.Animation_Activity, 262 new int[] { 263 android.R.attr.activityOpenEnterAnimation, android.R.attr.activityOpenExitAnimation 264 }); 265 activity.overridePendingTransition( 266 typedArray.getResourceId(/* index= */ 0, /* defValue= */ 0), 267 typedArray.getResourceId(/* index= */ 1, /* defValue= */ 0)); 268 typedArray.recycle(); 269 } else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT_PRE_P) { 270 activity.overridePendingTransition( 271 R.anim.sud_pre_p_activity_open_enter, R.anim.sud_pre_p_activity_open_exit); 272 } else if (transitionId == TRANSITION_NONE) { 273 // For TRANSITION_NONE, turn off the transition 274 activity.overridePendingTransition(/* enterAnim= */ 0, /* exitAnim= */ 0); 275 } 276 // For TRANSITION_NO_OVERRIDE or other values, do not override the transition 277 } 278 279 /** 280 * Apply the transition for going backward which is decided by {@code 281 * Animation.SudWindowAnimation} theme if the API level is equal or higher than {@link 282 * android.os.Build.VERSION_CODES#U}. 283 * 284 * <p>Otherwise, apply the transition for going backward which is decided by partner resource 285 * {@link PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code 286 * setupwizard.transition_type} if the API level is equal or lower than {@link 287 * android.os.Build.VERSION_CODES#T}. The default transition that will be applied is {@link 288 * #TRANSITION_SLIDE}. 289 * 290 * <p>The timing to apply the transition is going backward from the next activity to this, or 291 * going backward from this activity to the previous. 292 * 293 * <p>For example, in the flow below, the backward transitions will be applied to all arrows 294 * pointing to the left. Previous screen <-- This screen <-- Next screen. 295 */ 296 @TargetApi(VERSION_CODES.LOLLIPOP) applyBackwardTransition(Activity activity)297 public static void applyBackwardTransition(Activity activity) { 298 applyBackwardTransition(activity, TRANSITION_CAPTIVE); 299 } 300 301 /** 302 * Apply the transition for going backward which is decided by partner resource {@link 303 * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}. 304 * The default transition that will be applied is {@link #CONFIG_TRANSITION_NONE}. The timing to 305 * apply the transition is going backward from the next {@link Fragment} to this, or going 306 * backward from this {@link Fragment} to the previous. 307 * 308 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 309 * activity options input, should start the activity directly. 310 */ 311 @TargetApi(VERSION_CODES.M) 312 @Deprecated applyBackwardTransition(Fragment fragment)313 public static void applyBackwardTransition(Fragment fragment) { 314 // Do nothing 315 } 316 317 /** 318 * Apply the transition for going backward which is decided by {@code 319 * Animation.SudWindowAnimation} theme if the API level is equal or higher than {@link 320 * android.os.Build.VERSION_CODES#U}. 321 * 322 * <p>Otherwise, apply the transition for going backward which is decided by the argument {@code 323 * transitionId} if the API level is equal or lower than {@link android.os.Build.VERSION_CODES#T}. 324 * 325 * <p>The timing to apply the transition is going backward from the next activity to this, or 326 * going backward from this activity to the previous. 327 */ 328 @TargetApi(VERSION_CODES.LOLLIPOP) applyBackwardTransition(Activity activity, @TransitionType int transitionId)329 public static void applyBackwardTransition(Activity activity, @TransitionType int transitionId) { 330 applyBackwardTransition(activity, transitionId, /* useClientTransitionSettings= */ false); 331 } 332 333 /** 334 * Apply the transition for going backward which is decided by {@code 335 * Animation.SudWindowAnimation} theme if the API level is equal or higher than {@link 336 * android.os.Build.VERSION_CODES#U}, and argument {@code useClientTransitionSettings} is false, 337 * and System property {@code suw_apply_glif_theme_controlled_transition} is true, and {@code 338 * TRANSITION_FADE_THOUGH} transition is not specified. 339 * 340 * <p>Otherwise, apply the transition for going backward which is decided by the argument {@code 341 * transitionId}, {@code shared_x_axis_activity} transition is used only when {@code 342 * TRANSITION_FADE_TROUGH} transition is specified, and System property {@code * 343 * suw_apply_glif_theme_controlled_transition} is true, and the API level is equal or more than 344 * {@link android.os.Build.VERSION_CODES#U}, other {@code transitionId} can be specified if the 345 * API level is equal or lower than {@link android.os.Build.VERSION_CODES#T}, or argument {@code 346 * useClientTransitionSettings} is true, or System property {@code 347 * suw_apply_glif_theme_controlled_transition} is false. The default transition that will be 348 * applied is {@link #TRANSITION_SLIDE}. 349 * 350 * <p>The timing to apply the transition is going backward from the next activity to this, or 351 * going backward from this activity to the previous. 352 * 353 * <p>For example, in the flow below, the backward transitions will be applied to all arrows 354 * pointing to the left. Previous screen <-- This screen <-- Next screen 355 */ 356 @TargetApi(VERSION_CODES.LOLLIPOP) applyBackwardTransition( Activity activity, @TransitionType int transitionId, boolean useClientTransitionSettings)357 public static void applyBackwardTransition( 358 Activity activity, @TransitionType int transitionId, boolean useClientTransitionSettings) { 359 if (BuildCompatUtils.isAtLeastU() 360 && !useClientTransitionSettings 361 && PartnerConfigHelper.isGlifThemeControlledTransitionApplied(activity) 362 && transitionId != TRANSITION_FADE_THROUGH) { 363 // Do nothing 364 } else if (BuildCompatUtils.isAtLeastU() && transitionId == TRANSITION_FADE_THROUGH) { 365 if (PartnerConfigHelper.isGlifThemeControlledTransitionApplied(activity)) { 366 int closeEnterTransition = 367 ThemeHelper.shouldApplyDynamicColor(activity) 368 ? R.anim.shared_x_axis_activity_close_enter_dynamic_color 369 : R.anim.shared_x_axis_activity_close_enter; 370 activity.overridePendingTransition( 371 closeEnterTransition, R.anim.shared_x_axis_activity_close_exit); 372 } else { 373 activity.overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out); 374 } 375 } else if (transitionId == TRANSITION_SLIDE) { 376 activity.overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out); 377 } else if (transitionId == TRANSITION_FADE) { 378 activity.overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out); 379 } else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT) { 380 TypedArray typedArray = 381 activity.obtainStyledAttributes( 382 android.R.style.Animation_Activity, 383 new int[] { 384 android.R.attr.activityCloseEnterAnimation, 385 android.R.attr.activityCloseExitAnimation 386 }); 387 activity.overridePendingTransition( 388 typedArray.getResourceId(/* index= */ 0, /* defValue= */ 0), 389 typedArray.getResourceId(/* index= */ 1, /* defValue= */ 0)); 390 typedArray.recycle(); 391 } else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT_PRE_P) { 392 activity.overridePendingTransition( 393 R.anim.sud_pre_p_activity_close_enter, R.anim.sud_pre_p_activity_close_exit); 394 } else if (transitionId == TRANSITION_NONE) { 395 // For TRANSITION_NONE, turn off the transition 396 activity.overridePendingTransition(/* enterAnim= */ 0, /* exitAnim= */ 0); 397 } 398 } 399 400 /** 401 * A wrapper method, create an {@link android.app.ActivityOptions} to transition between 402 * activities as the {@link ActivityOptions} parameter of {@link Activity#startActivity}. 403 * 404 * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null. 405 * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run 406 * the given Intent. 407 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 408 * activity options input, should start the activity directly. 409 */ 410 @InlineMe(replacement = "activity.startActivity(intent)") 411 @Deprecated startActivityWithTransition(Activity activity, Intent intent)412 public static void startActivityWithTransition(Activity activity, Intent intent) { 413 activity.startActivity(intent); 414 } 415 416 /** 417 * A wrapper method, create an {@link android.app.ActivityOptions} to transition between 418 * activities as the {@link ActivityOptions} parameter of {@link Activity#startActivity}. 419 * 420 * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null. 421 * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run 422 * the given Intent. 423 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 424 * activity options input, should start the activity directly. 425 */ 426 @Deprecated startActivityWithTransition( Activity activity, Intent intent, Bundle overrideActivityOptions)427 public static void startActivityWithTransition( 428 Activity activity, Intent intent, Bundle overrideActivityOptions) { 429 if (activity == null) { 430 throw new IllegalArgumentException("Invalid activity=" + activity); 431 } 432 433 if (intent == null) { 434 throw new IllegalArgumentException("Invalid intent=" + intent); 435 } 436 437 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == Intent.FLAG_ACTIVITY_NEW_TASK) { 438 Log.e( 439 TAG, 440 "The transition won't take effect since the WindowManager does not allow override new" 441 + " task transitions"); 442 } 443 444 if (!isStartActivity) { 445 isStartActivity = true; 446 activity.startActivity(intent); 447 } 448 isStartActivity = false; 449 } 450 451 /** 452 * A wrapper method, create an {@link android.app.ActivityOptions} to transition between 453 * activities as the {@code activityOptions} parameter of {@link Activity#startActivityForResult}. 454 * 455 * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null. 456 * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run 457 * the given Intent. 458 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 459 * activity options input, should start the activity directly. 460 */ 461 @InlineMe(replacement = "activity.startActivityForResult(intent, requestCode)") 462 @Deprecated startActivityForResultWithTransition( Activity activity, Intent intent, int requestCode)463 public static void startActivityForResultWithTransition( 464 Activity activity, Intent intent, int requestCode) { 465 activity.startActivityForResult(intent, requestCode); 466 } 467 468 /** 469 * A wrapper method, create an {@link android.app.ActivityOptions} to transition between 470 * activities as the {@code activityOptions} parameter of {@link Activity#startActivityForResult}. 471 * 472 * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null. 473 * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run 474 * the given Intent. 475 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 476 * activity options input, should start the activity directly. 477 */ 478 @Deprecated startActivityForResultWithTransition( Activity activity, Intent intent, int requestCode, Bundle overrideActivityOptions)479 public static void startActivityForResultWithTransition( 480 Activity activity, Intent intent, int requestCode, Bundle overrideActivityOptions) { 481 if (activity == null) { 482 throw new IllegalArgumentException("Invalid activity=" + activity); 483 } 484 485 if (intent == null) { 486 throw new IllegalArgumentException("Invalid intent=" + intent); 487 } 488 489 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == Intent.FLAG_ACTIVITY_NEW_TASK) { 490 Log.e( 491 TAG, 492 "The transition won't take effect since the WindowManager does not allow override new" 493 + " task transitions"); 494 } 495 496 if (!isStartActivityForResult) { 497 try { 498 isStartActivityForResult = true; 499 activity.startActivityForResult(intent, requestCode); 500 } catch (ActivityNotFoundException e) { 501 Log.w(TAG, "Activity not found when startActivityForResult with transition."); 502 throw e; 503 } finally { 504 // Allow to start next activity. 505 isStartActivityForResult = false; 506 } 507 } 508 } 509 510 /** 511 * A wrapper method, calling {@link Activity#finishAfterTransition()} to trigger exit transition 512 * when running in Android S and the transition type {link #CONFIG_TRANSITION_SHARED_X_AXIS}. 513 * 514 * @throws IllegalArgumentException is thrown when {@code activity} is null. 515 */ finishActivity(Activity activity)516 public static void finishActivity(Activity activity) { 517 if (activity == null) { 518 throw new IllegalArgumentException("Invalid activity=" + activity); 519 } 520 521 // Avoids finish been called more than once. 522 if (!isFinishCalled) { 523 isFinishCalled = true; 524 Log.w( 525 TAG, 526 "Fallback to using Activity#finish() due to the" 527 + " Activity#finishAfterTransition() is supported from Android Sdk " 528 + VERSION_CODES.LOLLIPOP); 529 activity.finish(); 530 } 531 isFinishCalled = false; 532 } 533 534 /** 535 * Returns the transition type from the {@link PartnerConfig#CONFIG_TRANSITION_TYPE} partner 536 * resource on Android S, otherwise returns {@link #CONFIG_TRANSITION_NONE}. 537 */ getConfigTransitionType(Context context)538 public static int getConfigTransitionType(Context context) { 539 return BuildCompatUtils.isAtLeastS() && ThemeHelper.shouldApplyExtendedPartnerConfig(context) 540 ? PartnerConfigHelper.get(context) 541 .getInteger(context, PartnerConfig.CONFIG_TRANSITION_TYPE, CONFIG_TRANSITION_NONE) 542 : CONFIG_TRANSITION_NONE; 543 } 544 545 /** 546 * A wrapper method, create a {@link Bundle} from {@link ActivityOptions} to transition between 547 * Activities using cross-Activity scene animations. This {@link Bundle} that can be used with 548 * {@link Context#startActivity(Intent, Bundle)} and related methods. 549 * 550 * <p>Example usage: 551 * 552 * <pre>{@code 553 * Intent intent = new Intent("com.example.NEXT_ACTIVITY"); 554 * activity.startActivity(intent, TransitionHelper.makeActivityOptions(activity, intent, null); 555 * }</pre> 556 * 557 * <p>Unexpected usage: 558 * 559 * <pre>{@code 560 * Intent intent = new Intent("com.example.NEXT_ACTIVITY"); 561 * Intent intent2 = new Intent("com.example.NEXT_ACTIVITY"); 562 * activity.startActivity(intent, TransitionHelper.makeActivityOptions(activity, intent2, null); 563 * }</pre> 564 * 565 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 566 * activity options input, should start the activity directly. 567 */ 568 @InlineMe(replacement = "null") 569 @Nullable 570 @Deprecated makeActivityOptions(Activity activity, Intent intent)571 public static Bundle makeActivityOptions(Activity activity, Intent intent) { 572 return null; 573 } 574 575 /** 576 * A wrapper method, create a {@link Bundle} from {@link ActivityOptions} to transition between 577 * Activities using cross-Activity scene animations. This {@link Bundle} that can be used with 578 * {@link Context#startActivity(Intent, Bundle)} and related methods. When this {@code activity} 579 * is a no UI activity(the activity doesn't inflate any layouts), you will need to pass the bundle 580 * coming from previous UI activity as the {@link ActivityOptions}, otherwise, the transition 581 * won't be take effect. The {@code overrideActivityOptionsFromIntent} is supporting this purpose 582 * to return the {@link ActivityOptions} instead of creating from this no UI activity while the 583 * transition is apply {@link #CONFIG_TRANSITION_SHARED_X_AXIS} config. Moreover, the 584 * startActivity*WithTransition relative methods and {@link #makeActivityOptions} will put {@link 585 * ActivityOptions} to the {@code intent} by default, you can get the {@link ActivityOptions} 586 * which makes from previous activity by accessing {@link #EXTRA_ACTIVITY_OPTIONS} extra from 587 * {@link Activity#getIntent()}. 588 * 589 * <p>Example usage of a no UI activity: 590 * 591 * <pre>{@code 592 * Intent intent = new Intent("com.example.NEXT_ACTIVITY"); 593 * activity.startActivity(intent, TransitionHelper.makeActivityOptions(activity, intent, true); 594 * }</pre> 595 * 596 * @deprecated Deprecated to use CONFIG_TRANSITION_SHARED_X_AXIS transition, so it never have 597 * activity options input, should start the activity directly. 598 */ 599 @InlineMe(replacement = "null") 600 @Nullable 601 @Deprecated makeActivityOptions( Activity activity, Intent intent, boolean overrideActivityOptionsFromIntent)602 public static Bundle makeActivityOptions( 603 Activity activity, Intent intent, boolean overrideActivityOptionsFromIntent) { 604 return null; 605 } 606 } 607