blob: 67418ce01e4524b40b3a3edf1cd00c0dbaaf9119 [file] [log] [blame]
/*
* Copyright (C) 2015 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.tv.common.ui.setup;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import com.android.tv.common.R;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.ui.setup.animation.SetupAnimationHelper;
/**
* Setup activity for onboarding screens or TIS.
*
* <p>The inherited class should add theme {@code Theme.Setup.GuidedStep} to its definition in
* AndroidManifest.xml.
*/
public abstract class SetupActivity extends Activity implements OnActionClickListener {
private static final int MSG_EXECUTE_ACTION = 1;
private boolean mShowInitialFragment = true;
private long mFragmentTransitionDuration;
private final Handler mHandler = new SetupActivityHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SetupAnimationHelper.initialize(this);
setContentView(R.layout.activity_setup);
mFragmentTransitionDuration =
getResources().getInteger(R.integer.setup_fragment_transition_duration);
// Show initial fragment only when the saved state is not restored, because the last
// fragment is restored if savesInstanceState is not null.
if (savedInstanceState == null) {
// This is the workaround to show the first fragment with delay to show the fragment
// enter transition. See http://b/26255145
getWindow()
.getDecorView()
.getViewTreeObserver()
.addOnPreDrawListener(
new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getWindow()
.getDecorView()
.getViewTreeObserver()
.removeOnPreDrawListener(this);
showInitialFragment();
return true;
}
});
} else {
mShowInitialFragment = false;
}
}
/**
* The inherited class should provide the initial fragment to show.
*
* <p>If this method returns {@code null} during {@link #onCreate}, then call {@link
* #showInitialFragment} explicitly later with non null initial fragment.
*/
protected abstract Fragment onCreateInitialFragment();
/**
* Shows the initial fragment.
*
* <p>The inherited class can call this method later explicitly if it doesn't want the initial
* fragment to be shown in onCreate().
*/
protected void showInitialFragment() {
if (!mShowInitialFragment) {
return;
}
Fragment fragment = onCreateInitialFragment();
if (fragment != null) {
showFragment(fragment, false);
mShowInitialFragment = false;
}
}
/** Shows the given fragment. */
protected FragmentTransaction showFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (fragment instanceof SetupFragment) {
int[] sharedElements = ((SetupFragment) fragment).getSharedElementIds();
if (sharedElements != null && sharedElements.length > 0) {
Transition sharedTransition =
TransitionInflater.from(this)
.inflateTransition(R.transition.transition_action_background);
sharedTransition.setDuration(getSharedElementTransitionDuration());
SetupAnimationHelper.applyAnimationTimeScale(sharedTransition);
fragment.setSharedElementEnterTransition(sharedTransition);
fragment.setSharedElementReturnTransition(sharedTransition);
for (int id : sharedElements) {
View sharedView = findViewById(id);
if (sharedView != null) {
ft.addSharedElement(sharedView, sharedView.getTransitionName());
}
}
}
}
String tag = fragment.getClass().getCanonicalName();
if (addToBackStack) {
ft.addToBackStack(tag);
}
ft.replace(R.id.fragment_container, fragment, tag).commit();
return ft;
}
@Override
public boolean onActionClick(String category, int actionId, Bundle params) {
if (mHandler.hasMessages(MSG_EXECUTE_ACTION)) {
return false;
}
return executeAction(category, actionId, params);
}
protected void executeActionWithDelay(Runnable action, int delayMs) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_EXECUTE_ACTION, action), delayMs);
}
/**
* Override this method if the inherited class wants to handle the action.
*
* <p>The override method should return {@code true} if the action is handled, otherwise {@code
* false}.
*/
protected boolean executeAction(String category, int actionId, Bundle params) {
return false;
}
/**
* Returns the duration of the shared element transition.
*
* <p>It's (exit transition) + (delayed animation) + (enter transition).
*/
private long getSharedElementTransitionDuration() {
return (mFragmentTransitionDuration + SetupAnimationHelper.DELAY_BETWEEN_SIBLINGS_MS) * 2;
}
private static class SetupActivityHandler extends WeakHandler<SetupActivity> {
SetupActivityHandler(SetupActivity activity) {
// Should run on main thread because onAc3SupportChanged will be called on main thread.
super(Looper.getMainLooper(), activity);
}
@Override
protected void handleMessage(Message msg, @NonNull SetupActivity activity) {
if (msg.what == MSG_EXECUTE_ACTION) {
((Runnable) msg.obj).run();
}
}
}
}