1bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee/* This file is auto-generated from OnboardingFragment.java.  DO NOT MODIFY. */
2bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
3bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee/*
4bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * Copyright (C) 2015 The Android Open Source Project
5bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee *
6bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * Licensed under the Apache License, Version 2.0 (the "License");
7bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * you may not use this file except in compliance with the License.
8bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * You may obtain a copy of the License at
9bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee *
10bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee *      http://www.apache.org/licenses/LICENSE-2.0
11bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee *
12bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * Unless required by applicable law or agreed to in writing, software
13bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * distributed under the License is distributed on an "AS IS" BASIS,
14bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * See the License for the specific language governing permissions and
16bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * limitations under the License.
17bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee */
18bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
19bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leepackage android.support.v17.leanback.app;
20bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
21bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.Animator;
22bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.AnimatorInflater;
23bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.AnimatorListenerAdapter;
24bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.AnimatorSet;
25bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.ObjectAnimator;
26bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.animation.TimeInterpolator;
27e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Leeimport android.support.v4.app.FragmentActivity;
28bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.support.v4.app.Fragment;
29bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.os.Bundle;
30bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.support.annotation.Nullable;
31bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.support.v17.leanback.R;
32bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.support.v17.leanback.widget.PagingIndicator;
33e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Leeimport android.util.Log;
34e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Leeimport android.util.TypedValue;
35e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Leeimport android.view.ContextThemeWrapper;
36bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.Gravity;
37bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.KeyEvent;
38bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.LayoutInflater;
39bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.View;
40bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.View.OnClickListener;
41bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.View.OnKeyListener;
42bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.ViewGroup;
43bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.ViewTreeObserver.OnPreDrawListener;
44bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.animation.AccelerateInterpolator;
45bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.view.animation.DecelerateInterpolator;
46bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.widget.ImageView;
47bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport android.widget.TextView;
48bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
49bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport java.util.ArrayList;
50bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeimport java.util.List;
51bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
52bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee/**
53dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * An OnboardingSupportFragment provides a common and simple way to build onboarding screen for
54dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * applications.
55bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
56bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <h3>Building the screen</h3>
57bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * The view structure of onboarding screen is composed of the common parts and custom parts. The
58bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * common parts are composed of title, description and page navigator and the custom parts are
59bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * composed of background, contents and foreground.
60bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
61bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * To build the screen views, the inherited class should override:
62bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <ul>
63bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #onCreateBackgroundView} to provide the background view. Background view has the same
64bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * size as the screen and the lowest z-order.</li>
65bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #onCreateContentView} to provide the contents view. The content view is located in
66bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * the content area at the center of the screen.</li>
67bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #onCreateForegroundView} to provide the foreground view. Foreground view has the same
68bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * size as the screen and the highest z-order</li>
69bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * </ul>
70bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
71bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * Each of these methods can return {@code null} if the application doesn't want to provide it.
72bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
73bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <h3>Page information</h3>
74bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * The onboarding screen may have several pages which explain the functionality of the application.
75bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * The inherited class should provide the page information by overriding the methods:
76bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
77bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <ul>
78bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #getPageCount} to provide the number of pages.</li>
79bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #getPageTitle} to provide the title of the page.</li>
80bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <li>{@link #getPageDescription} to provide the description of the page.</li>
81bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * </ul>
82bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
83dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * Note that the information is used in {@link #onCreateView}, so should be initialized before
84ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * calling {@code super.onCreateView}.
85bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
86bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <h3>Animation</h3>
87dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * Onboarding screen has three kinds of animations:
88dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <p>
89dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <h4>Logo Splash Animation</a></h4>
90dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * When onboarding screen appears, the logo splash animation is played by default. The animation
91dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * fades in the logo image, pauses in a few seconds and fades it out.
92bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
93dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * In most cases, the logo animation needs to be customized because the logo images of applications
94dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * are different from each other, or some applications may want to show their own animations.
95dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <p>
96dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * The logo animation can be customized in two ways:
97bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <ul>
98dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <li>The simplest way is to provide the logo image by calling {@link #setLogoResourceId} to show
99dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * the default logo animation. This method should be called in {@link Fragment#onCreateView}.</li>
100dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <li>If the logo animation is complex, then override {@link #onCreateLogoAnimation} and return the
101dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * {@link Animator} object to run.</li>
102bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * </ul>
103bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
104dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * If the inherited class provides neither the logo image nor the animation, the logo animation will
105dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * be omitted.
106dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <h4>Page enter animation</h4>
107dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * After logo animation finishes, page enter animation starts. The application can provide the
108dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * animations of custom views by overriding {@link #onCreateEnterAnimation}.
109dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <h4>Page change animation</h4>
110dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * When the page changes, the default animations of the title and description are played. The
111dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * inherited class can override {@link #onPageChanged} to start the custom animations.
112dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee * <p>
113bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <h3>Finishing the screen</h3>
114bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * <p>
115bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * If the user finishes the onboarding screen after navigating all the pages,
116bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * {@link #onFinishFragment} is called. The inherited class can override this method to show another
117bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee * fragment or activity, or just remove this fragment.
118e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <p>
119e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <h3>Theming</h3>
120e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <p>
121e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * OnboardingSupportFragment must have access to an appropriate theme. Specifically, the fragment must
122e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * receive  {@link R.style#Theme_Leanback_Onboarding}, or a theme whose parent is set to that theme.
123e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * Themes can be provided in one of three ways:
124e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <ul>
125e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <li>The simplest way is to set the theme for the host Activity to the Onboarding theme or a theme
126e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * that derives from it.</li>
127e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <li>If the Activity already has a theme and setting its parent theme is inconvenient, the
128e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * existing Activity theme can have an entry added for the attribute
129e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * {@link R.styleable#LeanbackOnboardingTheme_onboardingTheme}. If present, this theme will be used
130e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * by OnboardingSupportFragment as an overlay to the Activity's theme.</li>
131e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <li>Finally, custom subclasses of OnboardingSupportFragment may provide a theme through the
132e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * {@link #onProvideTheme} method. This can be useful if a subclass is used across multiple
133e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * Activities.</li>
134e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * </ul>
135e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * <p>
136e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * If the theme is provided in multiple ways, the onProvideTheme override has priority, followed by
137e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * the Activity's theme. (Themes whose parent theme is already set to the onboarding theme do not
138e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee * need to set the onboardingTheme attribute; if set, it will be ignored.)
139bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee *
140ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingTheme
141ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingHeaderStyle
142ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingTitleStyle
143ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingDescriptionStyle
144ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingNavigatorContainerStyle
145ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingPageIndicatorStyle
146ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingStartButtonStyle
147ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee * @attr ref R.styleable#LeanbackOnboardingTheme_onboardingLogoStyle
148bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee */
149bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Leeabstract public class OnboardingSupportFragment extends Fragment {
150e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    private static final String TAG = "OnboardingSupportFragment";
151e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    private static final boolean DEBUG = false;
152e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
153bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long LOGO_SPLASH_PAUSE_DURATION_MS = 1333;
154bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long START_DELAY_TITLE_MS = 33;
155bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long START_DELAY_DESCRIPTION_MS = 33;
156bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
157bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long HEADER_ANIMATION_DURATION_MS = 417;
158bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long DESCRIPTION_START_DELAY_MS = 33;
159bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final long HEADER_APPEAR_DELAY_MS = 500;
160bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final int SLIDE_DISTANCE = 60;
161bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
162bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static int sSlideDistance;
163bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
164bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final TimeInterpolator HEADER_APPEAR_INTERPOLATOR = new DecelerateInterpolator();
165bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private static final TimeInterpolator HEADER_DISAPPEAR_INTERPOLATOR
166bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            = new AccelerateInterpolator();
167bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
168dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    // Keys used to save and restore the states.
169dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private static final String KEY_CURRENT_PAGE_INDEX = "leanback.onboarding.current_page_index";
170dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
171e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    private ContextThemeWrapper mThemeWrapper;
172e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
173bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private PagingIndicator mPageIndicator;
174bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private View mStartButton;
175bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private ImageView mLogoView;
176bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private TextView mTitleView;
177bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private TextView mDescriptionView;
178bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
1796cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee    private boolean mIsLtr;
180e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
181dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    // No need to save/restore the logo resource ID, because the logo animation will not appear when
182dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    // the fragment is restored.
183dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private int mLogoResourceId;
184bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private boolean mEnterTransitionFinished;
185bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private int mCurrentPageIndex;
186bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
187bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private AnimatorSet mAnimator;
188bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
189bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private final OnClickListener mOnClickListener = new OnClickListener() {
190bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        @Override
191bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        public void onClick(View view) {
192bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            if (!mEnterTransitionFinished) {
193bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                // Do not change page until the enter transition finishes.
194bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                return;
195bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
196bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            if (mCurrentPageIndex == getPageCount() - 1) {
197bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                onFinishFragment();
198bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            } else {
1996cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                moveToNextPage();
200bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
201bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
202bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    };
203bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
204bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private final OnKeyListener mOnKeyListener = new OnKeyListener() {
205bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        @Override
206bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        public boolean onKey(View v, int keyCode, KeyEvent event) {
207bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            if (!mEnterTransitionFinished) {
208bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                // Ignore key event until the enter transition finishes.
209bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                return keyCode != KeyEvent.KEYCODE_BACK;
210bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
211bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            if (event.getAction() == KeyEvent.ACTION_DOWN) {
212bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                return false;
213bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
214bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            switch (keyCode) {
215bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                case KeyEvent.KEYCODE_BACK:
216bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    if (mCurrentPageIndex == 0) {
217bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                        return false;
218bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    }
2196cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    moveToPreviousPage();
2206cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    return true;
221bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                case KeyEvent.KEYCODE_DPAD_LEFT:
2226cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    if (mIsLtr) {
2236cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                        moveToPreviousPage();
2246cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    } else {
2256cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                        moveToNextPage();
226bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    }
227bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    return true;
228bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                case KeyEvent.KEYCODE_DPAD_RIGHT:
2296cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    if (mIsLtr) {
2306cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                        moveToNextPage();
2316cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                    } else {
2326cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                        moveToPreviousPage();
233bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    }
234bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    return true;
235bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
236bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            return false;
237bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
238bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    };
239bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
2406cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee    private void moveToPreviousPage() {
2416cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee        if (mCurrentPageIndex > 0) {
2426cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee            --mCurrentPageIndex;
2436cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee            onPageChangedInternal(mCurrentPageIndex + 1);
2446cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee        }
2456cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee    }
2466cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee    private void moveToNextPage() {
2476cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee        if (mCurrentPageIndex < getPageCount() - 1) {
2486cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee            ++mCurrentPageIndex;
2496cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee            onPageChangedInternal(mCurrentPageIndex - 1);
2506cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee        }
2516cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee    }
2526cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee
253bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    @Nullable
254bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    @Override
255bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
256bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            Bundle savedInstanceState) {
257e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        resolveTheme();
258e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        LayoutInflater localInflater = getThemeInflater(inflater);
2591e0f144c00c249ce3673ae10c1398537cd354f15Chulwoo Lee        final ViewGroup view = (ViewGroup) localInflater.inflate(R.layout.lb_onboarding_fragment,
260e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee                container, false);
2616cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee        mIsLtr = getResources().getConfiguration().getLayoutDirection()
2626cb24d438e700ceb0a8b7d5a93683b19eae6c1b5Chulwoo Lee                == View.LAYOUT_DIRECTION_LTR;
263bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mPageIndicator = (PagingIndicator) view.findViewById(R.id.page_indicator);
264bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mPageIndicator.setOnClickListener(mOnClickListener);
265bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mPageIndicator.setOnKeyListener(mOnKeyListener);
266bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mStartButton = view.findViewById(R.id.button_start);
267bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mStartButton.setOnClickListener(mOnClickListener);
268bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mStartButton.setOnKeyListener(mOnKeyListener);
269bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mLogoView = (ImageView) view.findViewById(R.id.logo);
270bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mTitleView = (TextView) view.findViewById(R.id.title);
271bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mDescriptionView = (TextView) view.findViewById(R.id.description);
272bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (sSlideDistance == 0) {
273bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            sSlideDistance = (int) (SLIDE_DISTANCE * getActivity().getResources()
274bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    .getDisplayMetrics().scaledDensity);
275bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
276dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (savedInstanceState == null) {
277dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mCurrentPageIndex = 0;
278dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mEnterTransitionFinished = false;
279dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mPageIndicator.onPageSelected(0, false);
2801e0f144c00c249ce3673ae10c1398537cd354f15Chulwoo Lee            view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
281bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                @Override
282bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                public boolean onPreDraw() {
2831e0f144c00c249ce3673ae10c1398537cd354f15Chulwoo Lee                    view.getViewTreeObserver().removeOnPreDrawListener(this);
284dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    if (!startLogoAnimation()) {
285dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                        startEnterAnimation();
286dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    }
287bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    return true;
288bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                }
289bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            });
290bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        } else {
291dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mEnterTransitionFinished = true;
292dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mCurrentPageIndex = savedInstanceState.getInt(KEY_CURRENT_PAGE_INDEX);
293dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            initializeViews(view);
294bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
295dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        view.requestFocus();
296bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        return view;
297bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
298bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
299dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    @Override
300dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    public void onSaveInstanceState(Bundle outState) {
301dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        super.onSaveInstanceState(outState);
302dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        outState.putInt(KEY_CURRENT_PAGE_INDEX, mCurrentPageIndex);
303dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
304dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
305dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    /**
306e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     * Returns the theme used for styling the fragment. The default returns -1, indicating that the
307e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     * host Activity's theme should be used.
308e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     *
309e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     * @return The theme resource ID of the theme to use in this fragment, or -1 to use the host
310e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     *         Activity's theme.
311e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee     */
312e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    public int onProvideTheme() {
313e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        return -1;
314e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    }
315e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
316e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    private void resolveTheme() {
317e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        FragmentActivity activity = getActivity();
318e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        int theme = onProvideTheme();
319e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        if (theme == -1) {
320e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            // Look up the onboardingTheme in the activity's currently specified theme. If it
321e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            // exists, wrap the theme with its value.
322e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            int resId = R.attr.onboardingTheme;
323e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            TypedValue typedValue = new TypedValue();
324e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
325e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            if (DEBUG) Log.v(TAG, "Found onboarding theme reference? " + found);
326e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            if (found) {
327e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee                mThemeWrapper = new ContextThemeWrapper(activity, typedValue.resourceId);
328e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            }
329e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        } else {
330e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee            mThemeWrapper = new ContextThemeWrapper(activity, theme);
331e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        }
332e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    }
333e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
334e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    private LayoutInflater getThemeInflater(LayoutInflater inflater) {
335e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        return mThemeWrapper == null ? inflater : inflater.cloneInContext(mThemeWrapper);
336e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    }
337e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee
338e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee    /**
339dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * Sets the resource ID of the splash logo image. If the logo resource id set, the default logo
340dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * splash animation will be played.
341dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     *
342dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @param id The resource ID of the logo image.
343dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     */
344dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    public final void setLogoResourceId(int id) {
345dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        mLogoResourceId = id;
346dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
347dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
348dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    /**
349dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * Returns the resource ID of the splash logo image.
350dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     *
351dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @return The resource ID of the splash logo image.
352dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     */
353dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    public final int getLogoResourceId() {
354dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        return mLogoResourceId;
355dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
356dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
357dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    /**
358dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * Called to have the inherited class create its own logo animation.
359dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * <p>
360dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * This is called only if the logo image resource ID is not set by {@link #setLogoResourceId}.
361dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * If this returns {@code null}, the logo animation is skipped.
362dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     *
363dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @return The {@link Animator} object which runs the logo animation.
364dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     */
365dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    @Nullable
366dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    protected Animator onCreateLogoAnimation() {
367dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        return null;
368dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
369dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
370dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private boolean startLogoAnimation() {
371dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        Animator animator = null;
372dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (mLogoResourceId != 0) {
373dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mLogoView.setVisibility(View.VISIBLE);
374dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mLogoView.setImageResource(mLogoResourceId);
375dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            Animator inAnimator = AnimatorInflater.loadAnimator(getActivity(),
376dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    R.animator.lb_onboarding_logo_enter);
377dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            Animator outAnimator = AnimatorInflater.loadAnimator(getActivity(),
378dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    R.animator.lb_onboarding_logo_exit);
379dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            outAnimator.setStartDelay(LOGO_SPLASH_PAUSE_DURATION_MS);
380dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            AnimatorSet logoAnimator = new AnimatorSet();
381dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            logoAnimator.playSequentially(inAnimator, outAnimator);
382dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            logoAnimator.setTarget(mLogoView);
383dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            animator = logoAnimator;
384dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        } else {
385dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            animator = onCreateLogoAnimation();
386dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        }
387dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (animator != null) {
388dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            animator.addListener(new AnimatorListenerAdapter() {
389dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                @Override
390dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                public void onAnimationEnd(Animator animation) {
391dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    if (getActivity() != null) {
392dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                        startEnterAnimation();
393dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                    }
394bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                }
395dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            });
396dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            animator.start();
397dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            return true;
398dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        }
399dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        return false;
400dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
401dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
402dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    /**
403dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * Called to have the inherited class create its enter animation. The start animation runs after
404dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * logo animation ends.
405dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     *
406dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @return The {@link Animator} object which runs the page enter animation.
407dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     */
408dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    @Nullable
409dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    protected Animator onCreateEnterAnimation() {
410dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        return null;
411bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
412bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
413dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private void initializeViews(View container) {
414bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mLogoView.setVisibility(View.GONE);
415bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Create custom views.
416e22092227572db7e749e5cbb8139aa79a18fecd5Chulwoo Lee        LayoutInflater inflater = getThemeInflater(LayoutInflater.from(getActivity()));
417dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        ViewGroup backgroundContainer = (ViewGroup) container.findViewById(
418bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                R.id.background_container);
419bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        View background = onCreateBackgroundView(inflater, backgroundContainer);
420bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (background != null) {
421bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            backgroundContainer.setVisibility(View.VISIBLE);
422bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            backgroundContainer.addView(background);
423bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
424dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        ViewGroup contentContainer = (ViewGroup) container.findViewById(R.id.content_container);
425bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        View content = onCreateContentView(inflater, contentContainer);
426bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (content != null) {
427bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            contentContainer.setVisibility(View.VISIBLE);
428bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            contentContainer.addView(content);
429bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
430dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        ViewGroup foregroundContainer = (ViewGroup) container.findViewById(
431bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                R.id.foreground_container);
432bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        View foreground = onCreateForegroundView(inflater, foregroundContainer);
433bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (foreground != null) {
434bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            foregroundContainer.setVisibility(View.VISIBLE);
435bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            foregroundContainer.addView(foreground);
436bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
437bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Make views visible which were invisible while logo animation is running.
438dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        container.findViewById(R.id.page_container).setVisibility(View.VISIBLE);
439dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        container.findViewById(R.id.content_container).setVisibility(View.VISIBLE);
440dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (getPageCount() > 1) {
441dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mPageIndicator.setPageCount(getPageCount());
442dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            mPageIndicator.onPageSelected(mCurrentPageIndex, false);
443dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        }
444dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (mCurrentPageIndex == getPageCount() - 1) {
445bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            mStartButton.setVisibility(View.VISIBLE);
446bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        } else {
447bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            mPageIndicator.setVisibility(View.VISIBLE);
448bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
449dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        // Header views.
450dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        mTitleView.setText(getPageTitle(mCurrentPageIndex));
451dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        mDescriptionView.setText(getPageDescription(mCurrentPageIndex));
452dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    }
453dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
454dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private void startEnterAnimation() {
455dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        mEnterTransitionFinished = true;
456dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        initializeViews(getView());
457dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        List<Animator> animators = new ArrayList<>();
458dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        Animator animator = AnimatorInflater.loadAnimator(getActivity(),
459dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee                R.animator.lb_onboarding_page_indicator_enter);
460dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
461bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animators.add(animator);
462bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Header title
463bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        View view = getActivity().findViewById(R.id.title);
464bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        view.setAlpha(0);
465bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator = AnimatorInflater.loadAnimator(getActivity(),
466bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                R.animator.lb_onboarding_title_enter);
467bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator.setStartDelay(START_DELAY_TITLE_MS);
468bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator.setTarget(view);
469bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animators.add(animator);
470bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Header description
471bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        view = getActivity().findViewById(R.id.description);
472bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        view.setAlpha(0);
473bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator = AnimatorInflater.loadAnimator(getActivity(),
474bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                R.animator.lb_onboarding_description_enter);
475bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
476bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator.setTarget(view);
477bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animators.add(animator);
478dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        // Customized animation by the inherited class.
479dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        Animator customAnimator = onCreateEnterAnimation();
480dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        if (customAnimator != null) {
481dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee            animators.add(customAnimator);
482dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        }
483bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator = new AnimatorSet();
484bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator.playTogether(animators);
485bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator.start();
486bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Search focus and give the focus to the appropriate child which has become visible.
487bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        getView().requestFocus();
488bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
489bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
490bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
491bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Returns the page count.
492bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
493bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The page count.
494bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
495bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    abstract protected int getPageCount();
496bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
497bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
498bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Returns the title of the given page.
499bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
500bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param pageIndex The page index.
501bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
502bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The title of the page.
503bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
504ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee    abstract protected CharSequence getPageTitle(int pageIndex);
505bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
506bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
507bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Returns the description of the given page.
508bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
509bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param pageIndex The page index.
510bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
511bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The description of the page.
512bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
513ebe4901e5e467a8ff9a4e2a203a589f9755de329Chulwoo Lee    abstract protected CharSequence getPageDescription(int pageIndex);
514bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
515bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
516bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Returns the index of the current page.
517bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
518bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The index of the current page.
519bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
520bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    protected final int getCurrentPageIndex() {
521bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        return mCurrentPageIndex;
522bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
523bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
524bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
525bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Called to have the inherited class create background view. This is optional and the fragment
526bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * which doesn't have the background view can return {@code null}. This is called inside
527bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * {@link #onCreateView}.
528bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
529bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param inflater The LayoutInflater object that can be used to inflate the views,
530bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param container The parent view that the additional views are attached to.The fragment
531bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *        should not add the view by itself.
532bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
533bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The background view for the onboarding screen, or {@code null}.
534bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
535bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    @Nullable
536bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    abstract protected View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container);
537bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
538bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
539bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Called to have the inherited class create content view. This is optional and the fragment
540bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * which doesn't have the content view can return {@code null}. This is called inside
541bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * {@link #onCreateView}.
542bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
543bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * <p>The content view would be located at the center of the screen.
544bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
545bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param inflater The LayoutInflater object that can be used to inflate the views,
546bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param container The parent view that the additional views are attached to.The fragment
547bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *        should not add the view by itself.
548bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
549bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The content view for the onboarding screen, or {@code null}.
550bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
551bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    @Nullable
552bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    abstract protected View onCreateContentView(LayoutInflater inflater, ViewGroup container);
553bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
554bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
555bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Called to have the inherited class create foreground view. This is optional and the fragment
556bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * which doesn't need the foreground view can return {@code null}. This is called inside
557bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * {@link #onCreateView}.
558bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
559bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * <p>This foreground view would have the highest z-order.
560bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
561bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param inflater The LayoutInflater object that can be used to inflate the views,
562bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @param container The parent view that the additional views are attached to.The fragment
563bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *        should not add the view by itself.
564bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     *
565bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * @return The foreground view for the onboarding screen, or {@code null}.
566bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
567bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    @Nullable
568bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    abstract protected View onCreateForegroundView(LayoutInflater inflater, ViewGroup container);
569bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
570bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
571bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Called when the onboarding flow finishes.
572bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
573bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    protected void onFinishFragment() { }
574bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
575bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    /**
576bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     * Called when the page changes.
577bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee     */
578dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    private void onPageChangedInternal(int previousPage) {
579bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (mAnimator != null) {
580bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            mAnimator.end();
581bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
582bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mPageIndicator.onPageSelected(mCurrentPageIndex, true);
583bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
584bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        List<Animator> animators = new ArrayList<>();
585bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Header animation
586bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        Animator fadeAnimator = null;
587bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (previousPage < getCurrentPageIndex()) {
588bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            // sliding to left
589bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mTitleView, false, Gravity.START, 0));
590bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(fadeAnimator = createAnimator(mDescriptionView, false, Gravity.START,
591bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    DESCRIPTION_START_DELAY_MS));
592bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mTitleView, true, Gravity.END,
593bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    HEADER_APPEAR_DELAY_MS));
594bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mDescriptionView, true, Gravity.END,
595bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    HEADER_APPEAR_DELAY_MS + DESCRIPTION_START_DELAY_MS));
596bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        } else {
597bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            // sliding to right
598bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mTitleView, false, Gravity.END, 0));
599bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(fadeAnimator = createAnimator(mDescriptionView, false, Gravity.END,
600bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    DESCRIPTION_START_DELAY_MS));
601bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mTitleView, true, Gravity.START,
602bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    HEADER_APPEAR_DELAY_MS));
603bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(createAnimator(mDescriptionView, true, Gravity.START,
604bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    HEADER_APPEAR_DELAY_MS + DESCRIPTION_START_DELAY_MS));
605bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
606bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        final int currentPageIndex = getCurrentPageIndex();
607bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        fadeAnimator.addListener(new AnimatorListenerAdapter() {
608bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            @Override
609bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            public void onAnimationEnd(Animator animation) {
610bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                mTitleView.setText(getPageTitle(currentPageIndex));
611bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                mDescriptionView.setText(getPageDescription(currentPageIndex));
612bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            }
613bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        });
614bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
615bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        // Animator for switching between page indicator and button.
616bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (getCurrentPageIndex() == getPageCount() - 1) {
617bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            mStartButton.setVisibility(View.VISIBLE);
618bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
619bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    R.animator.lb_onboarding_page_indicator_fade_out);
620bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            navigatorFadeOutAnimator.setTarget(mPageIndicator);
621bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            navigatorFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
622bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                @Override
623bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                public void onAnimationEnd(Animator animation) {
624bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    mPageIndicator.setVisibility(View.GONE);
625bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                }
626bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            });
6275740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee            animators.add(navigatorFadeOutAnimator);
6285740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
6295740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee                    R.animator.lb_onboarding_start_button_fade_in);
6305740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee            buttonFadeInAnimator.setTarget(mStartButton);
631bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animators.add(buttonFadeInAnimator);
632bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        } else if (previousPage == getPageCount() - 1) {
633bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            mPageIndicator.setVisibility(View.VISIBLE);
634bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
635bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    R.animator.lb_onboarding_page_indicator_fade_in);
636bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            navigatorFadeInAnimator.setTarget(mPageIndicator);
6375740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee            animators.add(navigatorFadeInAnimator);
638bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
639bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    R.animator.lb_onboarding_start_button_fade_out);
640bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            buttonFadeOutAnimator.setTarget(mStartButton);
641bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            buttonFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
642bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                @Override
643bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                public void onAnimationEnd(Animator animation) {
644bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    mStartButton.setVisibility(View.GONE);
645bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                }
646bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            });
6475740176a71133eeafeed3733c28470fbb590aac7Chulwoo Lee            animators.add(buttonFadeOutAnimator);
648bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
649bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator = new AnimatorSet();
650bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator.playTogether(animators);
651bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        mAnimator.start();
652dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee        onPageChanged(mCurrentPageIndex, previousPage);
653bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
654bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee
655dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    /**
656dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * Called when the page has been changed.
657dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     *
658dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @param newPage The new page.
659dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     * @param previousPage The previous page.
660dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee     */
661dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee    protected void onPageChanged(int newPage, int previousPage) { }
662dd667f84d7dc1c24207cb6e66ffa0e91caa640a3Chulwoo Lee
663bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    private Animator createAnimator(View view, boolean fadeIn, int slideDirection,
664bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            long startDelay) {
665bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        boolean isLtr = getView().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
666bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        boolean slideRight = (isLtr && slideDirection == Gravity.END)
667bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                || (!isLtr && slideDirection == Gravity.START)
668bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                || slideDirection == Gravity.RIGHT;
669bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        Animator fadeAnimator;
670bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        Animator slideAnimator;
671bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (fadeIn) {
672bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            fadeAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 0.0f, 1.0f);
673bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            slideAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X,
674bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    slideRight ? sSlideDistance : -sSlideDistance, 0);
675bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            fadeAnimator.setInterpolator(HEADER_APPEAR_INTERPOLATOR);
676bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            slideAnimator.setInterpolator(HEADER_APPEAR_INTERPOLATOR);
677bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        } else {
678bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            fadeAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f);
679bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            slideAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 0,
680bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee                    slideRight ? sSlideDistance : -sSlideDistance);
681bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            fadeAnimator.setInterpolator(HEADER_DISAPPEAR_INTERPOLATOR);
682bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            slideAnimator.setInterpolator(HEADER_DISAPPEAR_INTERPOLATOR);
683bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
684bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        fadeAnimator.setDuration(HEADER_ANIMATION_DURATION_MS);
685bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        fadeAnimator.setTarget(view);
686bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        slideAnimator.setDuration(HEADER_ANIMATION_DURATION_MS);
687bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        slideAnimator.setTarget(view);
688bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        AnimatorSet animator = new AnimatorSet();
689bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        animator.playTogether(fadeAnimator, slideAnimator);
690bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        if (startDelay > 0) {
691bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee            animator.setStartDelay(startDelay);
692bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        }
693bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee        return animator;
694bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee    }
695bc69c4a046bdabeaa72c28fcca0ceeb72517a81fChulwoo Lee}
696