blob: 5d0a8395930d98bc9077230daafe3baab455dd7c [file]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.managedprovisioning.common;
import static com.android.managedprovisioning.provisioning.Constants.ENABLE_CUSTOM_TRANSITIONS;
import static com.google.android.setupdesign.transition.TransitionHelper.EXTRA_ACTIVITY_OPTIONS;
import static com.google.android.setupdesign.transition.TransitionHelper.TRANSITION_FADE;
import static com.google.android.setupdesign.transition.TransitionHelper.makeActivityOptions;
import static java.util.Objects.requireNonNull;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.view.ViewGroup;
import android.view.Window;
import androidx.annotation.Nullable;
/**
* Wrapper for {@link com.google.android.setupdesign.transition.TransitionHelper}.
*
* <p>Each {@link Activity#onCreate(Bundle)} is expected to call {@link
* TransitionHelper#applyContentScreenTransitions(Activity)}. For starting an {@link Activity}, use
* any of the {@code startActivity*WithTransition} methods provided in this class, in order to
* apply the appropriate transition. When finishing an {@link Activity}, {@link
* TransitionHelper#finishActivity(Activity)} must be used to apply the relevant transition.
*
* @see #startActivityWithTransition(Activity, Intent)
* @see #startActivityForResultWithTransition(Activity, Intent, int)
* @see #startActivityAsUserWithTransition(Activity, Intent, UserHandle)
* @see #startActivityForResultAsUserWithTransition(Activity, Intent, int, UserHandle)
*/
// TODO(b/183631247): Add tests once infrastructure is fixed
public class TransitionHelper {
private final Handler mHandler = new Handler(Looper.myLooper());
/**
* Applies the relevant {@link Activity} transitions for this content screen.
* Must be called in {@link Activity#onCreate(Bundle)}.
*
* <p>A content screen is a screen that shows content, not a spinner.
*
* <p>Also enables the {@link Window#FEATURE_ACTIVITY_TRANSITIONS} feature so that transitions
* are supported.
*
* @see #applyWaitingScreenTransitions(Activity)
*/
public void applyContentScreenTransitions(Activity activity) {
requireNonNull(activity);
if (!ENABLE_CUSTOM_TRANSITIONS) {
return;
}
activity.getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
com.google.android.setupdesign.transition.TransitionHelper.applyForwardTransition(activity);
com.google.android.setupdesign.transition.TransitionHelper
.applyBackwardTransition(activity);
}
/**
* Applies the relevant {@link Activity} transitions for this waiting screen.
* Must be called in {@link Activity#onResume()}.
*
* <p>A waiting screen is a screen that shows a spinner, not content.
*
* @see #applyContentScreenTransitions(Activity)
*/
public void applyWaitingScreenTransitions(Activity activity) {
requireNonNull(activity);
com.google.android.setupdesign.transition.TransitionHelper
.applyForwardTransition(activity, TRANSITION_FADE);
}
/**
* Calls {@link Activity#startActivity(Intent)} with an appropriate transition.
*/
public void startActivityWithTransition(Activity activity, Intent intent) {
requireNonNull(activity);
requireNonNull(intent);
if (!ENABLE_CUSTOM_TRANSITIONS) {
activity.startActivity(intent);
return;
}
// TODO(b/183537077): Remove hack to start UI-less activities using the previous activity's
// options bundle
Bundle previousBundle = getActivityOptionsForActivity(activity);
if (!hasContentView(activity) && previousBundle != null) {
mHandler.post(() -> com.google.android.setupdesign.transition.TransitionHelper
.startActivityWithTransition(activity, intent, previousBundle));
} else {
mHandler.post(() -> com.google.android.setupdesign.transition.TransitionHelper
.startActivityWithTransition(activity, intent));
}
}
/**
* Calls {@link Activity#startActivityForResult(Intent, int)} with an appropriate transition.
*/
public void startActivityForResultWithTransition(
Activity activity, Intent intent, int requestCode) {
requireNonNull(activity);
requireNonNull(intent);
if (!ENABLE_CUSTOM_TRANSITIONS) {
activity.startActivityForResult(intent, requestCode);
return;
}
// TODO(b/183537077): Remove hack to start UI-less activities using the previous activity's
// options bundle
Bundle previousBundle = getActivityOptionsForActivity(activity);
if (!hasContentView(activity) && previousBundle != null) {
mHandler.post(() -> com.google.android.setupdesign.transition.TransitionHelper
.startActivityForResultWithTransition(
activity, intent, requestCode, previousBundle));
} else {
mHandler.post(() -> com.google.android.setupdesign.transition.TransitionHelper
.startActivityForResultWithTransition(activity, intent, requestCode));
}
}
/**
* Calls {@link Activity#startActivityAsUser(Intent, UserHandle)} with an appropriate
* transition.
*/
public void startActivityAsUserWithTransition(
Activity activity, Intent intent, UserHandle userHandle) {
requireNonNull(activity);
requireNonNull(intent);
requireNonNull(userHandle);
if (!ENABLE_CUSTOM_TRANSITIONS) {
activity.startActivityAsUser(intent, userHandle);
return;
}
Bundle options = getRelevantActivityOptions(activity, intent);
mHandler.post(() -> activity.startActivityAsUser(intent, options, userHandle));
}
/**
* Calls {@link Activity#startActivityForResultAsUser(Intent, int, UserHandle)} with an
* appropriate transition.
*/
public void startActivityForResultAsUserWithTransition(
Activity activity, Intent intent, int requestCode, UserHandle userHandle) {
requireNonNull(activity);
requireNonNull(intent);
requireNonNull(userHandle);
if (!ENABLE_CUSTOM_TRANSITIONS) {
activity.startActivityForResultAsUser(intent, requestCode, userHandle);
return;
}
Bundle options = getRelevantActivityOptions(activity, intent);
mHandler.post(() ->
activity.startActivityForResultAsUser(intent, requestCode, options, userHandle));
}
/**
* Calls {@link Activity#finish()} with an appropriate transition.
*/
public void finishActivity(Activity activity) {
requireNonNull(activity);
if (!ENABLE_CUSTOM_TRANSITIONS) {
activity.finish();
return;
}
com.google.android.setupdesign.transition.TransitionHelper.finishActivity(activity);
}
@Nullable
private Bundle getActivityOptionsForActivity(Activity activity) {
if (activity.getIntent() == null) {
return null;
}
return activity.getIntent().getBundleExtra(EXTRA_ACTIVITY_OPTIONS);
}
private boolean hasContentView(Activity activity) {
if (activity.getWindow() == null) {
return false;
}
final ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().getRootView();
return rootView.getChildCount() > 0;
}
private Bundle getRelevantActivityOptions(Activity activity, Intent intent) {
// TODO(b/183537077): Remove hack to start UI-less activities using the previous activity's
// options bundle
Bundle options;
Bundle previousBundle = getActivityOptionsForActivity(activity);
if (!hasContentView(activity) && previousBundle != null) {
options = previousBundle;
} else {
options = makeActivityOptions(activity, intent);
}
return options;
}
}