1ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko/* 2ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Copyright (C) 2015 The Android Open Source Project 3ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 4ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 5ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * you may not use this file except in compliance with the License. 6ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * You may obtain a copy of the License at 7ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 8ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 9ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 10ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Unless required by applicable law or agreed to in writing, software 11ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 12ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * See the License for the specific language governing permissions and 14ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * limitations under the License. 15ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 16ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 17ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkopackage com.android.tv.common.ui.setup; 18ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 19ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.app.Activity; 20ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.app.Fragment; 21ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.app.FragmentTransaction; 22ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.os.Bundle; 23ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.os.Handler; 24ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.os.Looper; 25ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.os.Message; 26ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.NonNull; 27ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.transition.Transition; 28ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.transition.TransitionInflater; 29ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.view.View; 30ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.view.ViewTreeObserver.OnPreDrawListener; 31ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 32ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.R; 33ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.WeakHandler; 34ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.ui.setup.animation.SetupAnimationHelper; 35ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 36ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko/** 37ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Setup activity for onboarding screens or TIS. 38ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 39ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * <p>The inherited class should add theme {@code Theme.Setup.GuidedStep} to its definition in 40ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * AndroidManifest.xml. 41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 42ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkopublic abstract class SetupActivity extends Activity implements OnActionClickListener { 43ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final int MSG_EXECUTE_ACTION = 1; 44ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 45ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private boolean mShowInitialFragment = true; 46ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private long mFragmentTransitionDuration; 47ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final Handler mHandler = new SetupActivityHandler(this); 48ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 49ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 50ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void onCreate(Bundle savedInstanceState) { 51ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onCreate(savedInstanceState); 5265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko SetupAnimationHelper.initialize(this); 53ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko setContentView(R.layout.activity_setup); 54ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mFragmentTransitionDuration = getResources().getInteger( 55ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko R.integer.setup_fragment_transition_duration); 56ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Show initial fragment only when the saved state is not restored, because the last 57ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // fragment is restored if savesInstanceState is not null. 58ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (savedInstanceState == null) { 59ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // This is the workaround to show the first fragment with delay to show the fragment 60ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // enter transition. See http://b/26255145 61ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko getWindow().getDecorView().getViewTreeObserver().addOnPreDrawListener( 62ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko new OnPreDrawListener() { 63ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 64ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko public boolean onPreDraw() { 65ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko getWindow().getDecorView().getViewTreeObserver() 66ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .removeOnPreDrawListener(this); 67ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko showInitialFragment(); 68ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return true; 69ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 70ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko }); 71ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 72ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mShowInitialFragment = false; 73ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 74ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 75ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 76ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 77ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * The inherited class should provide the initial fragment to show. 78ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 79ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * <p>If this method returns {@code null} during {@link #onCreate}, then call 80ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * {@link #showInitialFragment} explicitly later with non null initial fragment. 81ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 82ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected abstract Fragment onCreateInitialFragment(); 83ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 84ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 85ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Shows the initial fragment. 86ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 87ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * <p>The inherited class can call this method later explicitly if it doesn't want the initial 88ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * fragment to be shown in onCreate(). 89ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 90ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void showInitialFragment() { 91ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (!mShowInitialFragment) { 92ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return; 93ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 94ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Fragment fragment = onCreateInitialFragment(); 95ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (fragment != null) { 96ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko showFragment(fragment, false); 97ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mShowInitialFragment = false; 98ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 99ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 100ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 101ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 102ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Shows the given fragment. 103ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 104ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected FragmentTransaction showFragment(Fragment fragment, boolean addToBackStack) { 105ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko FragmentTransaction ft = getFragmentManager().beginTransaction(); 106ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (fragment instanceof SetupFragment) { 107ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko int[] sharedElements = ((SetupFragment) fragment).getSharedElementIds(); 108ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (sharedElements != null && sharedElements.length > 0) { 109ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Transition sharedTransition = TransitionInflater.from(this) 110ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko .inflateTransition(R.transition.transition_action_background); 111ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko sharedTransition.setDuration(getSharedElementTransitionDuration()); 112ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko SetupAnimationHelper.applyAnimationTimeScale(sharedTransition); 113ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko fragment.setSharedElementEnterTransition(sharedTransition); 114ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko fragment.setSharedElementReturnTransition(sharedTransition); 115ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (int id : sharedElements) { 116ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko View sharedView = findViewById(id); 117ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (sharedView != null) { 118ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ft.addSharedElement(sharedView, sharedView.getTransitionName()); 119ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 120ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 121ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 122ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 123ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko String tag = fragment.getClass().getCanonicalName(); 124ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (addToBackStack) { 125ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ft.addToBackStack(tag); 126ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 127ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ft.replace(R.id.fragment_container, fragment, tag).commit(); 128ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 129ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return ft; 130ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 131ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 132ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 13365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public boolean onActionClick(String category, int actionId, Bundle params) { 134ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (mHandler.hasMessages(MSG_EXECUTE_ACTION)) { 13565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return false; 136ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 13765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return executeAction(category, actionId, params); 138ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 139ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 140ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void executeActionWithDelay(Runnable action, int delayMs) { 141ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_EXECUTE_ACTION, action), delayMs); 142ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 143ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 14465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 14565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Override this method if the inherited class wants to handle the action. 14665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * <p> 14765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * The override method should return {@code true} if the action is handled, otherwise 14865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * {@code false}. 14965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 15065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko protected boolean executeAction(String category, int actionId, Bundle params) { 15165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return false; 15265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 153ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 154ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko /** 155ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Returns the duration of the shared element transition. 156ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * 157ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * <p>It's (exit transition) + (delayed animation) + (enter transition). 158ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */ 159ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private long getSharedElementTransitionDuration() { 160ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return (mFragmentTransitionDuration + SetupAnimationHelper.DELAY_BETWEEN_SIBLINGS_MS) * 2; 161ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 162ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 163ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static class SetupActivityHandler extends WeakHandler<SetupActivity> { 164ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko SetupActivityHandler(SetupActivity activity) { 165ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko // Should run on main thread because onAc3SupportChanged will be called on main thread. 166ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super(Looper.getMainLooper(), activity); 167ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 168ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 169ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 170ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void handleMessage(Message msg, @NonNull SetupActivity activity) { 171ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (msg.what == MSG_EXECUTE_ACTION) { 172ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko ((Runnable) msg.obj).run(); 173ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 174ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 175ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 176ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko} 177