summaryrefslogtreecommitdiff
path: root/main/src/com/google/android/setupdesign/transition/TransitionHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/com/google/android/setupdesign/transition/TransitionHelper.java')
-rw-r--r--main/src/com/google/android/setupdesign/transition/TransitionHelper.java257
1 files changed, 251 insertions, 6 deletions
diff --git a/main/src/com/google/android/setupdesign/transition/TransitionHelper.java b/main/src/com/google/android/setupdesign/transition/TransitionHelper.java
index 86b3dfa..1836a11 100644
--- a/main/src/com/google/android/setupdesign/transition/TransitionHelper.java
+++ b/main/src/com/google/android/setupdesign/transition/TransitionHelper.java
@@ -17,14 +17,29 @@
package com.google.android.setupdesign.transition;
import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.Fragment;
+import android.content.Intent;
import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Parcelable;
+import android.util.Log;
+import android.view.Window;
import androidx.annotation.IntDef;
+import com.google.android.material.transition.platform.MaterialSharedAxis;
+import com.google.android.setupcompat.partnerconfig.PartnerConfig;
+import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
import com.google.android.setupdesign.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+/** Helper class for apply the transition to the pages which uses platform version. */
public class TransitionHelper {
+ private static final String TAG = "TransitionHelper";
+
/*
* In Setup Wizard, all Just-a-sec style screens (i.e. screens that has an indeterminate
* progress bar and automatically finishes itself), should do a cross-fade when entering or
@@ -64,7 +79,8 @@ public class TransitionHelper {
TRANSITION_FRAMEWORK_DEFAULT,
TRANSITION_SLIDE,
TRANSITION_FADE,
- TRANSITION_FRAMEWORK_DEFAULT_PRE_P
+ TRANSITION_FRAMEWORK_DEFAULT_PRE_P,
+ TRANSITION_CAPTIVE,
})
public @interface TransitionType {}
@@ -96,9 +112,70 @@ public class TransitionHelper {
/** Override the transition to the old framework default pre P. */
public static final int TRANSITION_FRAMEWORK_DEFAULT_PRE_P = 4;
+ /**
+ * Override the transition to the specific transition and the transition type will depends on the
+ * partner resource.
+ */
+ // TODO: Add new partner resource to determine which transition type would be apply.
+ public static final int TRANSITION_CAPTIVE = 5;
+
+ /** Override the transition to the specific type that will depend on the partner resource. */
+ private static final int CONFIG_TRANSITION_SHARED_X_AXIS = 1;
+
+ /**
+ * Passed in an intent as EXTRA_ACTIVITY_OPTIONS. This is the {@link ActivityOptions} of the
+ * transition used in {@link Activity#startActivity} or {@link Activity#startActivityForResult}.
+ */
+ public static final String EXTRA_ACTIVITY_OPTIONS = "activity_options";
+
private TransitionHelper() {}
/**
+ * Apply the transition for going forward which is decided by partner resource {@link
+ * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}.
+ * The default transition that will be applied is {@link #TRANSITION_SLIDE}. The timing to apply
+ * the transition is going forward from the previous activity to this, or going forward from this
+ * activity to the next.
+ *
+ * <p>For example, in the flow below, the forward transitions will be applied to all arrows
+ * pointing to the right. Previous screen --> This screen --> Next screen
+ */
+ public static void applyForwardTransition(Activity activity) {
+ applyForwardTransition(activity, TRANSITION_CAPTIVE);
+ }
+
+ /**
+ * Apply the transition for going forward which is decided by partner resource {@link
+ * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}.
+ * The default transition that will be applied is {@link #TRANSITION_NO_OVERRIDE}. The timing to
+ * apply the transition is going forward from the previous {@link Fragment} to this, or going
+ * forward from this {@link Fragment} to the next.
+ */
+ public static void applyForwardTransition(Fragment fragment) {
+ int transitionType;
+ if (VERSION.SDK_INT > VERSION_CODES.R) {
+ transitionType =
+ PartnerConfigHelper.get(fragment.getContext())
+ .getInteger(
+ fragment.getContext(),
+ PartnerConfig.CONFIG_TRANSITION_TYPE,
+ TRANSITION_NO_OVERRIDE);
+
+ if (CONFIG_TRANSITION_SHARED_X_AXIS == transitionType) {
+ MaterialSharedAxis exitTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ true);
+ fragment.setExitTransition(exitTransition);
+
+ MaterialSharedAxis enterTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ true);
+ fragment.setEnterTransition(enterTransition);
+ }
+ } else {
+ Log.w(TAG, "Not apply the forward transition for platform fragment.");
+ }
+ }
+
+ /**
* Apply the transition for going forward. This is applied when going forward from the previous
* activity to this, or going forward from this activity to the next.
*
@@ -118,19 +195,90 @@ public class TransitionHelper {
android.R.attr.activityOpenEnterAnimation, android.R.attr.activityOpenExitAnimation
});
activity.overridePendingTransition(
- typedArray.getResourceId(0, 0), typedArray.getResourceId(1, 0));
+ typedArray.getResourceId(/* index= */ 0, /* defValue= */ 0),
+ typedArray.getResourceId(/* index= */ 1, /* defValue= */ 0));
typedArray.recycle();
} else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT_PRE_P) {
activity.overridePendingTransition(
R.anim.sud_pre_p_activity_open_enter, R.anim.sud_pre_p_activity_open_exit);
} else if (transitionId == TRANSITION_NONE) {
// For TRANSITION_NONE, turn off the transition
- activity.overridePendingTransition(0, 0);
+ activity.overridePendingTransition(/* enterAnim= */ 0, /* exitAnim= */ 0);
+ } else if (transitionId == TRANSITION_CAPTIVE) {
+ // 1. If the flag not available, apply TRANSITION_SLIDE
+ // 2. If the flag present, apply the transition from transition type
+ int configTransitionType =
+ PartnerConfigHelper.get(activity)
+ .getInteger(activity, PartnerConfig.CONFIG_TRANSITION_TYPE, TRANSITION_SLIDE);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R
+ && configTransitionType == CONFIG_TRANSITION_SHARED_X_AXIS) {
+ Window window = activity.getWindow();
+ if (window != null) {
+ MaterialSharedAxis exitTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ true);
+ window.setExitTransition(exitTransition);
+
+ window.setAllowEnterTransitionOverlap(true);
+
+ MaterialSharedAxis enterTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ true);
+ window.setEnterTransition(enterTransition);
+ } else {
+ Log.w(TAG, "applyForwardTransition: Invalid window=" + window);
+ }
+ } else {
+ activity.overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
+ }
}
// For TRANSITION_NO_OVERRIDE or other values, do not override the transition
}
/**
+ * Apply the transition for going backward which is decided by partner resource {@link
+ * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}.
+ * The default transition that will be applied is {@link #TRANSITION_SLIDE}. The timing to apply
+ * the transition is going backward from the next activity to this, or going backward from this
+ * activity to the previous.
+ *
+ * <p>For example, in the flow below, the backward transitions will be applied to all arrows
+ * pointing to the left. Previous screen <-- This screen <-- Next screen
+ */
+ public static void applyBackwardTransition(Activity activity) {
+ applyBackwardTransition(activity, TRANSITION_CAPTIVE);
+ }
+
+ /**
+ * Apply the transition for going backward which is decided by partner resource {@link
+ * PartnerConfig#CONFIG_TRANSITION_TYPE} and system property {@code setupwizard.transition_type}.
+ * The default transition that will be applied is {@link #TRANSITION_NO_OVERRIDE}. The timing to
+ * apply the transition is going backward from the next {@link Fragment} to this, or going
+ * backward from this {@link Fragment} to the previous.
+ */
+ public static void applyBackwardTransition(Fragment fragment) {
+ int transitionType;
+ if (VERSION.SDK_INT > VERSION_CODES.R) {
+ transitionType =
+ PartnerConfigHelper.get(fragment.getContext())
+ .getInteger(
+ fragment.getContext(),
+ PartnerConfig.CONFIG_TRANSITION_TYPE,
+ TRANSITION_NO_OVERRIDE);
+
+ if (CONFIG_TRANSITION_SHARED_X_AXIS == transitionType) {
+ MaterialSharedAxis returnTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ false);
+ fragment.setReturnTransition(returnTransition);
+
+ MaterialSharedAxis reenterTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ false);
+ fragment.setReenterTransition(reenterTransition);
+ }
+ } else {
+ Log.w(TAG, "Not apply the backward transition for platform fragment.");
+ }
+ }
+
+ /**
* Apply the transition for going backward. This is applied when going backward from the next
* activity to this, or going backward from this activity to the previous.
*
@@ -141,7 +289,7 @@ public class TransitionHelper {
if (transitionId == TRANSITION_SLIDE) {
activity.overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out);
} else if (transitionId == TRANSITION_FADE) {
- activity.overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay);
+ activity.overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out);
} else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT) {
TypedArray typedArray =
activity.obtainStyledAttributes(
@@ -151,15 +299,112 @@ public class TransitionHelper {
android.R.attr.activityCloseExitAnimation
});
activity.overridePendingTransition(
- typedArray.getResourceId(0, 0), typedArray.getResourceId(1, 0));
+ typedArray.getResourceId(/* index= */ 0, /* defValue= */ 0),
+ typedArray.getResourceId(/* index= */ 1, /* defValue= */ 0));
typedArray.recycle();
} else if (transitionId == TRANSITION_FRAMEWORK_DEFAULT_PRE_P) {
activity.overridePendingTransition(
R.anim.sud_pre_p_activity_close_enter, R.anim.sud_pre_p_activity_close_exit);
} else if (transitionId == TRANSITION_NONE) {
// For TRANSITION_NONE, turn off the transition
- activity.overridePendingTransition(0, 0);
+ activity.overridePendingTransition(/* enterAnim= */ 0, /* exitAnim= */ 0);
+ } else if (transitionId == TRANSITION_CAPTIVE) {
+ // 1. If the flag not available, apply TRANSITION_SLIDE
+ // 2. If the flag present, apply the transition from transition type
+ int configTransitionType =
+ PartnerConfigHelper.get(activity)
+ .getInteger(activity, PartnerConfig.CONFIG_TRANSITION_TYPE, TRANSITION_SLIDE);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R
+ && configTransitionType == CONFIG_TRANSITION_SHARED_X_AXIS) {
+ Window window = activity.getWindow();
+ if (window != null) {
+ MaterialSharedAxis reenterTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ false);
+ window.setReenterTransition(reenterTransition);
+
+ MaterialSharedAxis returnTransition =
+ new MaterialSharedAxis(MaterialSharedAxis.X, /* forward= */ false);
+ window.setReturnTransition(returnTransition);
+ } else {
+ Log.w(TAG, "applyBackwardTransition: Invalid window=" + window);
+ }
+ } else {
+ activity.overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out);
+ }
}
// For TRANSITION_NO_OVERRIDE or other values, do not override the transition
}
+
+ /**
+ * A wrapper method, create an {@link android.app.ActivityOptions} to transition between
+ * activities as the {@link ActivityOptions} parameter of {@link Activity#startActivity}.
+ *
+ * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null.
+ * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run
+ * the given Intent.
+ */
+ public static void startActivityWithTransition(Activity activity, Intent intent) {
+ if (activity == null) {
+ throw new IllegalArgumentException("Invalid activity=" + activity);
+ }
+
+ if (intent == null) {
+ throw new IllegalArgumentException("Invalid intent=" + intent);
+ }
+
+ int configTransitionType =
+ PartnerConfigHelper.get(activity)
+ .getInteger(activity, PartnerConfig.CONFIG_TRANSITION_TYPE, TRANSITION_SLIDE);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R
+ && configTransitionType == CONFIG_TRANSITION_SHARED_X_AXIS) {
+ if (activity.getWindow() != null
+ && !activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
+ Log.w(
+ TAG, "The transition won't take effect due to NO FEATURE_ACTIVITY_TRANSITIONS feature");
+ }
+
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity);
+ intent.putExtra(EXTRA_ACTIVITY_OPTIONS, (Parcelable) activityOptions.toBundle());
+ activity.startActivity(intent, activityOptions.toBundle());
+ } else {
+ activity.startActivity(intent);
+ }
+ }
+
+ /**
+ * A wrapper method, create an {@link android.app.ActivityOptions} to transition between
+ * activities as the {@code activityOptions} parameter of {@link Activity#startActivityForResult}.
+ *
+ * @throws IllegalArgumentException is thrown when {@code activity} or {@code intent} is null.
+ * @throws android.content.ActivityNotFoundException if there was no {@link Activity} found to run
+ * the given Intent.
+ */
+ public static void startActivityForResultWithTransition(
+ Activity activity, Intent intent, int requestCode) {
+ if (activity == null) {
+ throw new IllegalArgumentException("Invalid activity=" + activity);
+ }
+
+ if (intent == null) {
+ throw new IllegalArgumentException("Invalid intent=" + intent);
+ }
+
+ int configTransitionType =
+ PartnerConfigHelper.get(activity)
+ .getInteger(activity, PartnerConfig.CONFIG_TRANSITION_TYPE, TRANSITION_SLIDE);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R
+ && configTransitionType == CONFIG_TRANSITION_SHARED_X_AXIS) {
+ if (activity.getWindow() != null
+ && !activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
+ Log.w(
+ TAG, "The transition won't take effect due to NO FEATURE_ACTIVITY_TRANSITIONS feature");
+ }
+
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity);
+ intent.putExtra(EXTRA_ACTIVITY_OPTIONS, (Parcelable) activityOptions.toBundle());
+ activity.startActivityForResult(intent, requestCode, activityOptions.toBundle());
+ } else {
+ activity.startActivityForResult(intent, requestCode);
+ }
+ }
}