[go: nahoru, domu]

1ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing/*
2ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Copyright (C) 2015 The Android Open Source Project
3ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing *
4ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * in compliance with the License. You may obtain a copy of the License at
6ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing *
7ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * http://www.apache.org/licenses/LICENSE-2.0
8ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing *
9ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Unless required by applicable law or agreed to in writing, software distributed under the License
10ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * or implied. See the License for the specific language governing permissions and limitations under
12ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the License.
13ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */
14ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingpackage android.support.v17.leanback.app;
15ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
16ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.Animator;
17ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.animation.AnimatorSet;
18ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.app.Activity;
19ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.app.Fragment;
20ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.app.FragmentManager;
2137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Guimport android.app.FragmentManager.BackStackEntry;
22ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.app.FragmentTransaction;
23ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.content.Context;
2442ae32908312e63b474963fef789017c75feae37Dake Guimport android.os.Build;
25ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.os.Bundle;
26ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.annotation.NonNull;
27ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.R;
2868d693985e85ee5eed18f78beaaadbfd9b8a4f13susnataimport android.support.v17.leanback.transition.TransitionHelper;
29ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.widget.GuidanceStylist;
30ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.widget.GuidanceStylist.Guidance;
31ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.widget.GuidedAction;
32be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Guimport android.support.v17.leanback.widget.GuidedActionAdapter;
33be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Guimport android.support.v17.leanback.widget.GuidedActionAdapterGroup;
34ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.support.v17.leanback.widget.GuidedActionsStylist;
35be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Guimport android.support.v17.leanback.widget.ViewHolderTask;
3637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Guimport android.support.v4.app.ActivityCompat;
37d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Guimport android.support.v7.widget.RecyclerView;
38ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.util.Log;
39ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.util.TypedValue;
40ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ContextThemeWrapper;
4142ae32908312e63b474963fef789017c75feae37Dake Guimport android.view.Gravity;
42ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.LayoutInflater;
43ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.View;
44ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport android.view.ViewGroup;
4568d693985e85ee5eed18f78beaaadbfd9b8a4f13susnataimport android.widget.FrameLayout;
46d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Guimport android.widget.LinearLayout;
47ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
48ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport java.util.ArrayList;
49ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesingimport java.util.List;
50ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
51ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing/**
52ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * A GuidedStepFragment is used to guide the user through a decision or series of decisions.
53751fc58ffff0614288c610fbd0767969abb9365fKris Giesing * It is composed of a guidance view on the left and a view on the right containing a list of
54751fc58ffff0614288c610fbd0767969abb9365fKris Giesing * possible actions.
55ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
56ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <h3>Basic Usage</h3>
57ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
5842ae32908312e63b474963fef789017c75feae37Dake Gu * Clients of GuidedStepFragment must create a custom subclass to attach to their Activities.
59ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * This custom subclass provides the information necessary to construct the user interface and
60ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * respond to user actions. At a minimum, subclasses should override:
61ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <ul>
62ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link #onCreateGuidance}, to provide instructions to the user</li>
63ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link #onCreateActions}, to provide a set of {@link GuidedAction}s the user can take</li>
64ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>{@link #onGuidedActionClicked}, to respond to those actions</li>
65ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * </ul>
66ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
6742ae32908312e63b474963fef789017c75feae37Dake Gu * Clients use following helper functions to add GuidedStepFragment to Activity or FragmentManager:
6842ae32908312e63b474963fef789017c75feae37Dake Gu * <ul>
6942ae32908312e63b474963fef789017c75feae37Dake Gu * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}, to be called during Activity onCreate,
7042ae32908312e63b474963fef789017c75feae37Dake Gu * adds GuidedStepFragment as the first Fragment in activity.</li>
7142ae32908312e63b474963fef789017c75feae37Dake Gu * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
7242ae32908312e63b474963fef789017c75feae37Dake Gu * GuidedStepFragment, int)}, to add GuidedStepFragment on top of existing Fragments or
7342ae32908312e63b474963fef789017c75feae37Dake Gu * replacing existing GuidedStepFragment when moving forward to next step.</li>
74517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu * <li>{@link #finishGuidedStepFragments()} can either finish the activity or pop all
75517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu * GuidedStepFragment from stack.
76517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu * <li>If app chooses not to use the helper function, it is the app's responsibility to call
77517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
78517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu * need pops to.
7942ae32908312e63b474963fef789017c75feae37Dake Gu * </ul>
80ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <h3>Theming and Stylists</h3>
81ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
82ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedStepFragment delegates its visual styling to classes called stylists. The {@link
83ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidanceStylist} is responsible for the left guidance view, while the {@link
84ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedActionsStylist} is responsible for the right actions view. The stylists use theme
85ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * attributes to derive values associated with the presentation, such as colors, animations, etc.
86ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Most simple visual aspects of GuidanceStylist and GuidedActionsStylist can be customized
87ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * via theming; see their documentation for more information.
88ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
89ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedStepFragments must have access to an appropriate theme in order for the stylists to
90ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * function properly.  Specifically, the fragment must receive {@link
91ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * android.support.v17.leanback.R.style#Theme_Leanback_GuidedStep}, or a theme whose parent is
92ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * is set to that theme. Themes can be provided in one of three ways:
93ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <ul>
94ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>The simplest way is to set the theme for the host Activity to the GuidedStep theme or a
95ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * theme that derives from it.</li>
96ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>If the Activity already has a theme and setting its parent theme is inconvenient, the
97ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * existing Activity theme can have an entry added for the attribute {@link
98ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme}. If present,
99ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * this theme will be used by GuidedStepFragment as an overlay to the Activity's theme.</li>
100ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <li>Finally, custom subclasses of GuidedStepFragment may provide a theme through the {@link
101ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * #onProvideTheme} method. This can be useful if a subclass is used across multiple
102ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * Activities.</li>
103ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * </ul>
104ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
105ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * If the theme is provided in multiple ways, the onProvideTheme override has priority, followed by
106ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the Activty's theme.  (Themes whose parent theme is already set to the guided step theme do not
107ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * need to set the guidedStepTheme attribute; if set, it will be ignored.)
108ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
109ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * If themes do not provide enough customizability, the stylists themselves may be subclassed and
110ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * provided to the GuidedStepFragment through the {@link #onCreateGuidanceStylist} and {@link
111ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * #onCreateActionsStylist} methods.  The stylists have simple hooks so that subclasses
112ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * may override layout files; subclasses may also have more complex logic to determine styling.
113ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
114ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <h3>Guided sequences</h3>
115ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
116ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * GuidedStepFragments can be grouped together to provide a guided sequence. GuidedStepFragments
117ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * grouped as a sequence use custom animations provided by {@link GuidanceStylist} and
118ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * {@link GuidedActionsStylist} (or subclasses) during transitions between steps. Clients
119ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * should use {@link #add} to place subsequent GuidedFragments onto the fragment stack so that
120ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * custom animations are properly configured. (Custom animations are triggered automatically when
121ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * the fragment stack is subsequently popped by any normal mechanism.)
122ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <p>
123ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * <i>Note: Currently GuidedStepFragments grouped in this way must all be defined programmatically,
124ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * rather than in XML. This restriction may be removed in the future.</i>
12542ae32908312e63b474963fef789017c75feae37Dake Gu *
126ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme
12742ae32908312e63b474963fef789017c75feae37Dake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepBackground
128d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeight
129d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeightTwoPanels
130d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackground
1317f43e18536eae40705d5c63830e9edb283f196adDake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackgroundDark
132a97810e4e2ec2552f8247ebdadf323dae70d9e3fDake Gu * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsElevation
133ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidanceStylist
134ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidanceStylist.Guidance
135ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedAction
136ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing * @see GuidedActionsStylist
137ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing */
138be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gupublic class GuidedStepFragment extends Fragment implements GuidedActionAdapter.FocusListener {
139ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
140ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepFragment";
141ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
1429050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    private static final String EXTRA_ACTION_PREFIX = "action_";
1439050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    private static final String EXTRA_BUTTON_ACTION_PREFIX = "buttonaction_";
14442ae32908312e63b474963fef789017c75feae37Dake Gu
145517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu    private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
14637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
14737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
14837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
149e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu    private static final boolean IS_FRAMEWORK_FRAGMENT = true;
150e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu
15142ae32908312e63b474963fef789017c75feae37Dake Gu    /**
152fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * Fragment argument name for UI style.  The argument value is persisted in fragment state and
153fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * used to select fragment transition. The value is initially {@link #UI_STYLE_ENTRANCE} and
154fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * might be changed in one of the three helper functions:
15542ae32908312e63b474963fef789017c75feae37Dake Gu     * <ul>
156fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)} sets to
157fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * {@link #UI_STYLE_ACTIVITY_ROOT}</li>
15842ae32908312e63b474963fef789017c75feae37Dake Gu     * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
159fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * GuidedStepFragment, int)} sets it to {@link #UI_STYLE_REPLACE} if there is already a
160fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * GuidedStepFragment on stack.</li>
161fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * <li>{@link #finishGuidedStepFragments()} changes current GuidedStepFragment to
162fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * {@link #UI_STYLE_ENTRANCE} for the non activity case.  This is a special case that changes
163fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * the transition settings after fragment has been created,  in order to force current
164fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * GuidedStepFragment run a return transition of {@link #UI_STYLE_ENTRANCE}</li>
16542ae32908312e63b474963fef789017c75feae37Dake Gu     * </ul>
16642ae32908312e63b474963fef789017c75feae37Dake Gu     * <p>
16742ae32908312e63b474963fef789017c75feae37Dake Gu     * Argument value can be either:
16842ae32908312e63b474963fef789017c75feae37Dake Gu     * <ul>
169517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>{@link #UI_STYLE_REPLACE}</li>
17042ae32908312e63b474963fef789017c75feae37Dake Gu     * <li>{@link #UI_STYLE_ENTRANCE}</li>
17142ae32908312e63b474963fef789017c75feae37Dake Gu     * <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
17242ae32908312e63b474963fef789017c75feae37Dake Gu     * </ul>
17342ae32908312e63b474963fef789017c75feae37Dake Gu     */
17442ae32908312e63b474963fef789017c75feae37Dake Gu    public static final String EXTRA_UI_STYLE = "uiStyle";
17542ae32908312e63b474963fef789017c75feae37Dake Gu
17642ae32908312e63b474963fef789017c75feae37Dake Gu    /**
177517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * This is the case that we use GuidedStepFragment to replace another existing
178517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * GuidedStepFragment when moving forward to next step. Default behavior of this style is:
17942ae32908312e63b474963fef789017c75feae37Dake Gu     * <ul>
180517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>Enter transition slides in from END(right), exit transition same as
181517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * {@link #UI_STYLE_ENTRANCE}.
18242ae32908312e63b474963fef789017c75feae37Dake Gu     * </li>
18342ae32908312e63b474963fef789017c75feae37Dake Gu     * </ul>
18442ae32908312e63b474963fef789017c75feae37Dake Gu     */
185517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu    public static final int UI_STYLE_REPLACE = 0;
18642ae32908312e63b474963fef789017c75feae37Dake Gu
18742ae32908312e63b474963fef789017c75feae37Dake Gu    /**
188c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu     * @deprecated Same value as {@link #UI_STYLE_REPLACE}.
189c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu     */
190c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu    @Deprecated
191c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu    public static final int UI_STYLE_DEFAULT = 0;
192c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu
193c3d11aea44660bf77326f6f07ebf11c6a19f7e1fDake Gu    /**
194517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
195517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * GuidedStepFragment constructor. This is the case that we show GuidedStepFragment on top of
196517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * other content. The default behavior of this style:
19742ae32908312e63b474963fef789017c75feae37Dake Gu     * <ul>
198517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
199517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Background will be faded in. Note: Changing exit transition by UI style is not working
200517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * because fragment transition asks for exit transition before UI style is restored in Fragment
20142ae32908312e63b474963fef789017c75feae37Dake Gu     * .onCreate().</li>
20242ae32908312e63b474963fef789017c75feae37Dake Gu     * </ul>
203fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * When popping multiple GuidedStepFragment, {@link #finishGuidedStepFragments()} also changes
204fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * the top GuidedStepFragment to UI_STYLE_ENTRANCE in order to run the return transition
205fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * (reverse of enter transition) of UI_STYLE_ENTRANCE.
20642ae32908312e63b474963fef789017c75feae37Dake Gu     */
20742ae32908312e63b474963fef789017c75feae37Dake Gu    public static final int UI_STYLE_ENTRANCE = 1;
20842ae32908312e63b474963fef789017c75feae37Dake Gu
20942ae32908312e63b474963fef789017c75feae37Dake Gu    /**
210517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
211517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * GuidedStepFragment in a separate activity. The default behavior of this style:
21242ae32908312e63b474963fef789017c75feae37Dake Gu     * <ul>
213517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
214517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
215ce4c2014042fe6e4723bab30741039848adcf4beDake Gu     * because fragment transition asks for exit transition before UI style is restored in
21642ae32908312e63b474963fef789017c75feae37Dake Gu     * Fragment.onCreate().</li>
21742ae32908312e63b474963fef789017c75feae37Dake Gu     * </ul>
21842ae32908312e63b474963fef789017c75feae37Dake Gu     */
21942ae32908312e63b474963fef789017c75feae37Dake Gu    public static final int UI_STYLE_ACTIVITY_ROOT = 2;
22042ae32908312e63b474963fef789017c75feae37Dake Gu
221e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    /**
222e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * Animation to slide the contents from the side (left/right).
223e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * @hide
224e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     */
225e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    public static final int SLIDE_FROM_SIDE = 0;
226e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata
227e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    /**
228e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * Animation to slide the contents from the bottom.
229e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * @hide
230e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     */
231e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    public static final int SLIDE_FROM_BOTTOM = 1;
232e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata
233ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private static final String TAG = "GuidedStepFragment";
23442ae32908312e63b474963fef789017c75feae37Dake Gu    private static final boolean DEBUG = false;
235ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
236e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu    /**
237e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu     * @hide
238e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu     */
239e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu    public static class DummyFragment extends Fragment {
240e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu        @Override
241e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu        public View onCreateView(LayoutInflater inflater, ViewGroup container,
242e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu                Bundle savedInstanceState) {
243e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu            final View v = new View(inflater.getContext());
244e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu            v.setVisibility(View.GONE);
245e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu            return v;
246e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu        }
247e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu    }
248e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu
249ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private int mTheme;
25042ae32908312e63b474963fef789017c75feae37Dake Gu    private ContextThemeWrapper mThemeWrapper;
251ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private GuidanceStylist mGuidanceStylist;
252ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private GuidedActionsStylist mActionsStylist;
253d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    private GuidedActionsStylist mButtonActionsStylist;
254ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private GuidedActionAdapter mAdapter;
255be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    private GuidedActionAdapter mSubAdapter;
256d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    private GuidedActionAdapter mButtonAdapter;
25743e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu    private GuidedActionAdapterGroup mAdapterGroup;
258ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
259d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
260ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private int mSelectedIndex = -1;
261d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    private int mButtonSelectedIndex = -1;
262e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    private int entranceTransitionType = SLIDE_FROM_SIDE;
263ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
264ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public GuidedStepFragment() {
265ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        // We need to supply the theme before any potential call to onInflate in order
266ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        // for the defaulting to work properly.
267ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        mTheme = onProvideTheme();
268ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        mGuidanceStylist = onCreateGuidanceStylist();
269ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        mActionsStylist = onCreateActionsStylist();
270d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mButtonActionsStylist = onCreateButtonActionsStylist();
27142ae32908312e63b474963fef789017c75feae37Dake Gu        onProvideFragmentTransitions();
272ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
273ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
274ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
275ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Creates the presenter used to style the guidance panel. The default implementation returns
276ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * a basic GuidanceStylist.
277ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The GuidanceStylist used in this fragment.
278ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
279ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public GuidanceStylist onCreateGuidanceStylist() {
280ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return new GuidanceStylist();
281ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
282ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
283ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
284ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Creates the presenter used to style the guided actions panel. The default implementation
285ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * returns a basic GuidedActionsStylist.
286ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The GuidedActionsStylist used in this fragment.
287ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
288ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public GuidedActionsStylist onCreateActionsStylist() {
289ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return new GuidedActionsStylist();
290ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
291ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
292ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
293d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Creates the presenter used to style a sided actions panel for button only.
294d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * The default implementation returns a basic GuidedActionsStylist.
295d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return The GuidedActionsStylist used in this fragment.
296d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
297d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public GuidedActionsStylist onCreateButtonActionsStylist() {
298be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        GuidedActionsStylist stylist = new GuidedActionsStylist();
299be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        stylist.setAsButtonActions();
300be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        return stylist;
301d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
302d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
303d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
304ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the theme used for styling the fragment. The default returns -1, indicating that the
305ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * host Activity's theme should be used.
306ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The theme resource ID of the theme to use in this fragment, or -1 to use the
307ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * host Activity's theme.
308ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
309ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public int onProvideTheme() {
310ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return -1;
311ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
312ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
313ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
314ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the information required to provide guidance to the user. This hook is called during
315ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * {@link #onCreateView}.  May be overridden to return a custom subclass of {@link
316ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * GuidanceStylist.Guidance} for use in a subclass of {@link GuidanceStylist}. The default
317ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * returns a Guidance object with empty fields; subclasses should override.
318ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param savedInstanceState The saved instance state from onCreateView.
319ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The Guidance object representing the information used to guide the user.
320ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
321ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public @NonNull Guidance onCreateGuidance(Bundle savedInstanceState) {
322ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return new Guidance("", "", "", null);
323ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
324ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
325ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
326ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Fills out the set of actions available to the user. This hook is called during {@link
327ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * #onCreate}. The default leaves the list of actions empty; subclasses should override.
328ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param actions A non-null, empty list ready to be populated.
329ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param savedInstanceState The saved instance state from onCreate.
330ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
331ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
332ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
333ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
334ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
335d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Fills out the set of actions shown at right available to the user. This hook is called during
336d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * {@link #onCreate}. The default leaves the list of actions empty; subclasses may override.
337d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param actions A non-null, empty list ready to be populated.
338d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param savedInstanceState The saved instance state from onCreate.
339d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
340d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public void onCreateButtonActions(@NonNull List<GuidedAction> actions,
341d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            Bundle savedInstanceState) {
342d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
343d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
344d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
345ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Callback invoked when an action is taken by the user. Subclasses should override in
346ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * order to act on the user's decisions.
347ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param action The chosen action.
348ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
349ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void onGuidedActionClicked(GuidedAction action) {
350ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
351ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
352ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
353be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * Callback invoked when an action in sub actions is taken by the user. Subclasses should
354be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * override in order to act on the user's decisions.  Default return value is true to close
355be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * the sub actions list.
356be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @param action The chosen action.
357be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @return true to collapse the sub actions list, false to keep it expanded.
358be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     */
359be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    public boolean onSubGuidedActionClicked(GuidedAction action) {
360be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        return true;
361be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    }
362be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu
363be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    /**
364be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @return True if the sub actions list is expanded, false otherwise.
365be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     */
366be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    public boolean isSubActionsExpanded() {
367be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        return mActionsStylist.isSubActionsExpanded();
368be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    }
369be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu
370be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    /**
371be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * Expand a given action's sub actions list.
372be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @param action GuidedAction to expand.
373be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @see GuidedAction#getSubActions()
374be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     */
375be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    public void expandSubActions(GuidedAction action) {
376be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        final int actionPosition = mActions.indexOf(action);
377be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        if (actionPosition < 0) {
378be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            return;
379be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        }
380be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mActionsStylist.getActionsGridView().setSelectedPositionSmooth(actionPosition,
381be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                new ViewHolderTask() {
382be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            @Override
383be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            public void run(RecyclerView.ViewHolder vh) {
384be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                GuidedActionsStylist.ViewHolder avh = (GuidedActionsStylist.ViewHolder) vh;
385be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                mActionsStylist.setExpandedViewHolder(avh);
386be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            }
387be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        });
388be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    }
389be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu
390be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    /**
391be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * Collapse sub actions list.
392be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     * @see GuidedAction#getSubActions()
393be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu     */
394be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    public void collapseSubActions() {
395be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mActionsStylist.setExpandedViewHolder(null);
396be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    }
397be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu
398be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu    /**
399ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Callback invoked when an action is focused (made to be the current selection) by the user.
400ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
401ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    @Override
402ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void onGuidedActionFocused(GuidedAction action) {
403ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
404ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
405ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
406bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu     * Callback invoked when an action's title or description has been edited, this happens either
407bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu     * when user clicks confirm button in IME or user closes IME window by BACK key.
40816ab389e0bd11594059f8164a1477045ee625154Dake Gu     * @deprecated Override {@link #onGuidedActionEditedAndProceed(GuidedAction)} and/or
40916ab389e0bd11594059f8164a1477045ee625154Dake Gu     *             {@link #onGuidedActionEditCanceled(GuidedAction)}.
4104158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing     */
41116ab389e0bd11594059f8164a1477045ee625154Dake Gu    @Deprecated
4124158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing    public void onGuidedActionEdited(GuidedAction action) {
4134158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing    }
4144158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing
4154158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing    /**
41616ab389e0bd11594059f8164a1477045ee625154Dake Gu     * Callback invoked when an action has been canceled editing, for example when user closes
41716ab389e0bd11594059f8164a1477045ee625154Dake Gu     * IME window by BACK key.  Default implementation calls deprecated method
41816ab389e0bd11594059f8164a1477045ee625154Dake Gu     * {@link #onGuidedActionEdited(GuidedAction)}.
41916ab389e0bd11594059f8164a1477045ee625154Dake Gu     * @param action The action which has been canceled editing.
42016ab389e0bd11594059f8164a1477045ee625154Dake Gu     */
42116ab389e0bd11594059f8164a1477045ee625154Dake Gu    public void onGuidedActionEditCanceled(GuidedAction action) {
42216ab389e0bd11594059f8164a1477045ee625154Dake Gu        onGuidedActionEdited(action);
42316ab389e0bd11594059f8164a1477045ee625154Dake Gu    }
42416ab389e0bd11594059f8164a1477045ee625154Dake Gu
42516ab389e0bd11594059f8164a1477045ee625154Dake Gu    /**
42616ab389e0bd11594059f8164a1477045ee625154Dake Gu     * Callback invoked when an action has been edited, for example when user clicks confirm button
42716ab389e0bd11594059f8164a1477045ee625154Dake Gu     * in IME window.  Default implementation calls deprecated method
428bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu     * {@link #onGuidedActionEdited(GuidedAction)} and returns {@link GuidedAction#ACTION_ID_NEXT}.
429c1741246af607f6be2389056da0182c40f938348Dake Gu     *
430c1741246af607f6be2389056da0182c40f938348Dake Gu     * @param action The action that has been edited.
431c1741246af607f6be2389056da0182c40f938348Dake Gu     * @return ID of the action will be focused or {@link GuidedAction#ACTION_ID_NEXT},
432c1741246af607f6be2389056da0182c40f938348Dake Gu     * {@link GuidedAction#ACTION_ID_CURRENT}.
433c1741246af607f6be2389056da0182c40f938348Dake Gu     */
434c1741246af607f6be2389056da0182c40f938348Dake Gu    public long onGuidedActionEditedAndProceed(GuidedAction action) {
435c1741246af607f6be2389056da0182c40f938348Dake Gu        onGuidedActionEdited(action);
436c1741246af607f6be2389056da0182c40f938348Dake Gu        return GuidedAction.ACTION_ID_NEXT;
437c1741246af607f6be2389056da0182c40f938348Dake Gu    }
438c1741246af607f6be2389056da0182c40f938348Dake Gu
439c1741246af607f6be2389056da0182c40f938348Dake Gu    /**
440ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
44142ae32908312e63b474963fef789017c75feae37Dake Gu     * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
442bd0afce433ec8c219627522a5233d61bf27f7397Dake Gu     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
443bd0afce433ec8c219627522a5233d61bf27f7397Dake Gu     * is pressed.
444517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE}
44542ae32908312e63b474963fef789017c75feae37Dake Gu     * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
446ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * <p>
447ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Note: currently fragments added using this method must be created programmatically rather
448ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * than via XML.
449ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param fragmentManager The FragmentManager to be used in the transaction.
450ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
45168a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * @return The ID returned by the call FragmentTransaction.commit.
452ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
453ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public static int add(FragmentManager fragmentManager, GuidedStepFragment fragment) {
454ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return add(fragmentManager, fragment, android.R.id.content);
455ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
456ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
45742ae32908312e63b474963fef789017c75feae37Dake Gu    /**
45842ae32908312e63b474963fef789017c75feae37Dake Gu     * Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
45942ae32908312e63b474963fef789017c75feae37Dake Gu     * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
460bd0afce433ec8c219627522a5233d61bf27f7397Dake Gu     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
461bd0afce433ec8c219627522a5233d61bf27f7397Dake Gu     * is pressed.
462517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE} and
4630b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepFragment)} will be called
4640b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * to perform shared element transition between GuidedStepFragments.
46542ae32908312e63b474963fef789017c75feae37Dake Gu     * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
46642ae32908312e63b474963fef789017c75feae37Dake Gu     * <p>
46742ae32908312e63b474963fef789017c75feae37Dake Gu     * Note: currently fragments added using this method must be created programmatically rather
46842ae32908312e63b474963fef789017c75feae37Dake Gu     * than via XML.
46942ae32908312e63b474963fef789017c75feae37Dake Gu     * @param fragmentManager The FragmentManager to be used in the transaction.
47042ae32908312e63b474963fef789017c75feae37Dake Gu     * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
47142ae32908312e63b474963fef789017c75feae37Dake Gu     * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
47268a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * @return The ID returned by the call FragmentTransaction.commit.
47342ae32908312e63b474963fef789017c75feae37Dake Gu     */
47442ae32908312e63b474963fef789017c75feae37Dake Gu    public static int add(FragmentManager fragmentManager, GuidedStepFragment fragment, int id) {
4750b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu        GuidedStepFragment current = getCurrentGuidedStepFragment(fragmentManager);
4760b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu        boolean inGuidedStep = current != null;
477e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu        if (IS_FRAMEWORK_FRAGMENT && Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23
478e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu                && !inGuidedStep) {
479e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu            // workaround b/22631964 for framework fragment
480e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu            fragmentManager.beginTransaction()
481e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu                .replace(id, new DummyFragment(), TAG_LEAN_BACK_ACTIONS_FRAGMENT)
482e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu                .commit();
483e9401be71ad141fe76dc6064c58f8c64054fde8dDake Gu        }
48442ae32908312e63b474963fef789017c75feae37Dake Gu        FragmentTransaction ft = fragmentManager.beginTransaction();
485ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
486517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
48737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        ft.addToBackStack(fragment.generateStackEntryName());
4880b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu        if (current != null) {
4890b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            fragment.onAddSharedElementTransition(ft, current);
4900b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu        }
49142ae32908312e63b474963fef789017c75feae37Dake Gu        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
49242ae32908312e63b474963fef789017c75feae37Dake Gu    }
49342ae32908312e63b474963fef789017c75feae37Dake Gu
49442ae32908312e63b474963fef789017c75feae37Dake Gu    /**
495517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
496517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * when the GuidedStepFragment replacing an existing GuidedStepFragment). Default implementation
497517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * establishes connections between action background views to morph action background bounds
498517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * change from disappearing GuidedStepFragment into this GuidedStepFragment. The default
4990b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
5000b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * method when modifying the default layout of {@link GuidedActionsStylist}.
501517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     *
5020b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * @see GuidedActionsStylist
5030b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * @see #onProvideFragmentTransitions()
5040b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * @param ft The FragmentTransaction to add shared element.
5050b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * @param disappearing The disappearing fragment.
5060b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     */
5070b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu    protected void onAddSharedElementTransition(FragmentTransaction ft, GuidedStepFragment
5080b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            disappearing) {
5098bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        View fragmentView = disappearing.getView();
5108bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5110b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                R.id.action_fragment_root), "action_fragment_root");
5128bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5130b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                R.id.action_fragment_background), "action_fragment_background");
5148bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5150b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                R.id.action_fragment), "action_fragment");
5168bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5170b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                R.id.guidedactions_root), "guidedactions_root");
5188bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5198e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu                R.id.guidedactions_content), "guidedactions_content");
5208bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5218e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu                R.id.guidedactions_list_background), "guidedactions_list_background");
5228bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5230b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                R.id.guidedactions_root2), "guidedactions_root2");
5248bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5258e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu                R.id.guidedactions_content2), "guidedactions_content2");
5268bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        addNonNullSharedElementTransition(ft, fragmentView.findViewById(
5278e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu                R.id.guidedactions_list_background2), "guidedactions_list_background2");
5280b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu    }
5290b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu
5308bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri    private static void addNonNullSharedElementTransition (FragmentTransaction ft, View subView,
5318bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri                                                           String transitionName)
5328bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri    {
5338bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri        if (subView != null)
5348bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri            TransitionHelper.addSharedElement(ft, subView, transitionName);
5358bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri    }
5368bfa8f6a659c1188a955ee185b13e777d29fb4d9Keyvan Amiri
5370b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu    /**
53837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * Returns BackStackEntry name for the GuidedStepFragment or empty String if no entry is
53937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} will return empty String.  The method
54037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * returns undefined value if the fragment is not in FragmentManager.
54137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
54237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * associated.
54337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
544fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu    String generateStackEntryName() {
54537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        return generateStackEntryName(getUiStyle(), getClass());
54637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
54737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
54837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
54937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * Generates BackStackEntry name for GuidedStepFragment class or empty String if no entry is
55037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
551517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
55237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
55337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * associated.
55437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
555fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu    static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
55637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
55737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return "";
55837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
55937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        switch (uiStyle) {
560517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        case UI_STYLE_REPLACE:
561517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
56237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        case UI_STYLE_ENTRANCE:
56337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
56437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        case UI_STYLE_ACTIVITY_ROOT:
56537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        default:
56637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return "";
56737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
56837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
56937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
57037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
571fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * Returns true if the backstack entry represents GuidedStepFragment with
572fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * {@link #UI_STYLE_ENTRANCE}, i.e. this is the first GuidedStepFragment pushed to stack; false
573fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * otherwise.
574fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu     * @see #generateStackEntryName(int, Class)
57537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @param backStackEntryName Name of BackStackEntry.
57637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_ENTRANCE};
57737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * false otherwise.
57837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
579fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu    static boolean isStackEntryUiStyleEntrance(String backStackEntryName) {
58037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE);
58137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
58237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
58337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
58437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * Extract Class name from BackStackEntry name.
58537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @param backStackEntryName Name of BackStackEntry.
58637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @return Class name of GuidedStepFragment.
58737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
588fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu    static String getGuidedStepFragmentClassName(String backStackEntryName) {
589517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
590517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
59137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        } else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
59237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
59337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        } else {
59437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return "";
59537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
59637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
59737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
59837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
599bd0afce433ec8c219627522a5233d61bf27f7397Dake Gu     * Adds the specified GuidedStepFragment as content of Activity; no backstack entry is added so
60068a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * the activity will be dismissed when BACK key is pressed.  The method is typically called in
60168a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * Activity.onCreate() when savedInstanceState is null.  When savedInstanceState is not null,
60268a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * the Activity is being restored,  do not call addAsRoot() to duplicate the Fragment restored
60368a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * by FragmentManager.
60442ae32908312e63b474963fef789017c75feae37Dake Gu     * {@link #UI_STYLE_ACTIVITY_ROOT} is assigned.
60542ae32908312e63b474963fef789017c75feae37Dake Gu     *
60642ae32908312e63b474963fef789017c75feae37Dake Gu     * Note: currently fragments added using this method must be created programmatically rather
60742ae32908312e63b474963fef789017c75feae37Dake Gu     * than via XML.
60842ae32908312e63b474963fef789017c75feae37Dake Gu     * @param activity The Activity to be used to insert GuidedstepFragment.
60942ae32908312e63b474963fef789017c75feae37Dake Gu     * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
61042ae32908312e63b474963fef789017c75feae37Dake Gu     * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
61168a94e5c24b85f071fb57727954510fff0224d9cDake Gu     * @return The ID returned by the call FragmentTransaction.commit, or -1 there is already
61268a94e5c24b85f071fb57727954510fff0224d9cDake Gu     *         GuidedStepFragment.
61342ae32908312e63b474963fef789017c75feae37Dake Gu     */
61442ae32908312e63b474963fef789017c75feae37Dake Gu    public static int addAsRoot(Activity activity, GuidedStepFragment fragment, int id) {
61542ae32908312e63b474963fef789017c75feae37Dake Gu        // Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
61642ae32908312e63b474963fef789017c75feae37Dake Gu        activity.getWindow().getDecorView();
61742ae32908312e63b474963fef789017c75feae37Dake Gu        FragmentManager fragmentManager = activity.getFragmentManager();
61868a94e5c24b85f071fb57727954510fff0224d9cDake Gu        if (fragmentManager.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT) != null) {
61968a94e5c24b85f071fb57727954510fff0224d9cDake Gu            Log.w(TAG, "Fragment is already exists, likely calling " +
62068a94e5c24b85f071fb57727954510fff0224d9cDake Gu                    "addAsRoot() when savedInstanceState is not null in Activity.onCreate().");
62168a94e5c24b85f071fb57727954510fff0224d9cDake Gu            return -1;
62268a94e5c24b85f071fb57727954510fff0224d9cDake Gu        }
62342ae32908312e63b474963fef789017c75feae37Dake Gu        FragmentTransaction ft = fragmentManager.beginTransaction();
62442ae32908312e63b474963fef789017c75feae37Dake Gu        fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
62542ae32908312e63b474963fef789017c75feae37Dake Gu        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
62642ae32908312e63b474963fef789017c75feae37Dake Gu    }
62742ae32908312e63b474963fef789017c75feae37Dake Gu
628ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
629ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the current GuidedStepFragment on the fragment transaction stack.
630ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The current GuidedStepFragment, if any, on the fragment transaction stack.
631ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
632ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public static GuidedStepFragment getCurrentGuidedStepFragment(FragmentManager fm) {
633ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        Fragment f = fm.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT);
634ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (f instanceof GuidedStepFragment) {
635ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            return (GuidedStepFragment) f;
636ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
637ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return null;
638ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
639ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
640ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
641ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the GuidanceStylist that displays guidance information for the user.
642ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The GuidanceStylist for this fragment.
643ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
644ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public GuidanceStylist getGuidanceStylist() {
645ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return mGuidanceStylist;
646ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
647ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
648ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
649ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the GuidedActionsStylist that displays the actions the user may take.
650ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The GuidedActionsStylist for this fragment.
651ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
652ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public GuidedActionsStylist getGuidedActionsStylist() {
653ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return mActionsStylist;
654ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
655ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
656ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
657d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Returns the list of button GuidedActions that the user may take in this fragment.
658d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return The list of button GuidedActions for this fragment.
659d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
660d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public List<GuidedAction> getButtonActions() {
661d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return mButtonActions;
662d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
663d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
664d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
665d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Find button GuidedAction by Id.
666d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param id  Id of the button action to search.
667d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return  GuidedAction object or null if not found.
668d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
669d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public GuidedAction findButtonActionById(long id) {
670d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        int index = findButtonActionPositionById(id);
671d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return index >= 0 ? mButtonActions.get(index) : null;
672d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
673d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
674d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
675d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Find button GuidedAction position in array by Id.
676d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param id  Id of the button action to search.
677d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return  position of GuidedAction object in array or -1 if not found.
678d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
679d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public int findButtonActionPositionById(long id) {
680d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        if (mButtonActions != null) {
681d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            for (int i = 0; i < mButtonActions.size(); i++) {
682d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                GuidedAction action = mButtonActions.get(i);
683d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                if (mButtonActions.get(i).getId() == id) {
684d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                    return i;
685d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                }
686d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            }
687d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        }
688d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return -1;
689d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
690d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
691d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
692d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Returns the GuidedActionsStylist that displays the button actions the user may take.
693d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return The GuidedActionsStylist for this fragment.
694d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
695d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public GuidedActionsStylist getGuidedButtonActionsStylist() {
696d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return mButtonActionsStylist;
697d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
698d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
699d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
700d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Sets the list of button GuidedActions that the user may take in this fragment.
701d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param actions The list of button GuidedActions for this fragment.
702d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
703d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public void setButtonActions(List<GuidedAction> actions) {
704d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mButtonActions = actions;
705d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        if (mButtonAdapter != null) {
706d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            mButtonAdapter.setActions(mButtonActions);
707d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        }
708d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
709d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
710d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
711d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Notify an button action has changed and update its UI.
712d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param position Position of the button GuidedAction in array.
713d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
714d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public void notifyButtonActionChanged(int position) {
715d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        if (mButtonAdapter != null) {
716d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            mButtonAdapter.notifyItemChanged(position);
717d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        }
718d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
719d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
720d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
721d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Returns the view corresponding to the button action at the indicated position in the list of
722d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * actions for this fragment.
723d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param position The integer position of the button action of interest.
724d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return The View corresponding to the button action at the indicated position, or null if
725d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * that action is not currently onscreen.
726d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
727d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public View getButtonActionItemView(int position) {
728d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        final RecyclerView.ViewHolder holder = mButtonActionsStylist.getActionsGridView()
729d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                    .findViewHolderForPosition(position);
730d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return holder == null ? null : holder.itemView;
731d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
732d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
733d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
734d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Scrolls the action list to the position indicated, selecting that button action's view.
735d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @param position The integer position of the button action of interest.
736d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
737d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public void setSelectedButtonActionPosition(int position) {
738d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mButtonActionsStylist.getActionsGridView().setSelectedPosition(position);
739d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
740d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
741d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
742d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * Returns the position if the currently selected button GuidedAction.
743d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * @return position The integer position of the currently selected button action.
744d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
745d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public int getSelectedButtonActionPosition() {
746d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return mButtonActionsStylist.getActionsGridView().getSelectedPosition();
747d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
748d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
749d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
750ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the list of GuidedActions that the user may take in this fragment.
751ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The list of GuidedActions for this fragment.
752ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
753ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public List<GuidedAction> getActions() {
754ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return mActions;
755ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
756ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
757ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
758c1741246af607f6be2389056da0182c40f938348Dake Gu     * Find GuidedAction by Id.
759c1741246af607f6be2389056da0182c40f938348Dake Gu     * @param id  Id of the action to search.
760c1741246af607f6be2389056da0182c40f938348Dake Gu     * @return  GuidedAction object or null if not found.
761c1741246af607f6be2389056da0182c40f938348Dake Gu     */
762c1741246af607f6be2389056da0182c40f938348Dake Gu    public GuidedAction findActionById(long id) {
763c1741246af607f6be2389056da0182c40f938348Dake Gu        int index = findActionPositionById(id);
764c1741246af607f6be2389056da0182c40f938348Dake Gu        return index >= 0 ? mActions.get(index) : null;
765c1741246af607f6be2389056da0182c40f938348Dake Gu    }
766c1741246af607f6be2389056da0182c40f938348Dake Gu
767c1741246af607f6be2389056da0182c40f938348Dake Gu    /**
768c1741246af607f6be2389056da0182c40f938348Dake Gu     * Find GuidedAction position in array by Id.
769c1741246af607f6be2389056da0182c40f938348Dake Gu     * @param id  Id of the action to search.
770c1741246af607f6be2389056da0182c40f938348Dake Gu     * @return  position of GuidedAction object in array or -1 if not found.
771c1741246af607f6be2389056da0182c40f938348Dake Gu     */
772c1741246af607f6be2389056da0182c40f938348Dake Gu    public int findActionPositionById(long id) {
773c1741246af607f6be2389056da0182c40f938348Dake Gu        if (mActions != null) {
774c1741246af607f6be2389056da0182c40f938348Dake Gu            for (int i = 0; i < mActions.size(); i++) {
775c1741246af607f6be2389056da0182c40f938348Dake Gu                GuidedAction action = mActions.get(i);
776c1741246af607f6be2389056da0182c40f938348Dake Gu                if (mActions.get(i).getId() == id) {
777c1741246af607f6be2389056da0182c40f938348Dake Gu                    return i;
778c1741246af607f6be2389056da0182c40f938348Dake Gu                }
779c1741246af607f6be2389056da0182c40f938348Dake Gu            }
780c1741246af607f6be2389056da0182c40f938348Dake Gu        }
781c1741246af607f6be2389056da0182c40f938348Dake Gu        return -1;
782c1741246af607f6be2389056da0182c40f938348Dake Gu    }
783c1741246af607f6be2389056da0182c40f938348Dake Gu
784c1741246af607f6be2389056da0182c40f938348Dake Gu    /**
785ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Sets the list of GuidedActions that the user may take in this fragment.
786ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param actions The list of GuidedActions for this fragment.
787ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
788ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void setActions(List<GuidedAction> actions) {
789ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        mActions = actions;
790ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (mAdapter != null) {
791ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            mAdapter.setActions(mActions);
792ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
793ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
794ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
795ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
796c1741246af607f6be2389056da0182c40f938348Dake Gu     * Notify an action has changed and update its UI.
797c1741246af607f6be2389056da0182c40f938348Dake Gu     * @param position Position of the GuidedAction in array.
798c1741246af607f6be2389056da0182c40f938348Dake Gu     */
799c1741246af607f6be2389056da0182c40f938348Dake Gu    public void notifyActionChanged(int position) {
800c1741246af607f6be2389056da0182c40f938348Dake Gu        if (mAdapter != null) {
801c1741246af607f6be2389056da0182c40f938348Dake Gu            mAdapter.notifyItemChanged(position);
802c1741246af607f6be2389056da0182c40f938348Dake Gu        }
803c1741246af607f6be2389056da0182c40f938348Dake Gu    }
804c1741246af607f6be2389056da0182c40f938348Dake Gu
805c1741246af607f6be2389056da0182c40f938348Dake Gu    /**
806ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the view corresponding to the action at the indicated position in the list of
807ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * actions for this fragment.
808ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param position The integer position of the action of interest.
809ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return The View corresponding to the action at the indicated position, or null if that
810ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * action is not currently onscreen.
811ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
812ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public View getActionItemView(int position) {
813d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        final RecyclerView.ViewHolder holder = mActionsStylist.getActionsGridView()
814d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                    .findViewHolderForPosition(position);
815d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return holder == null ? null : holder.itemView;
816ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
817ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
818ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
819ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Scrolls the action list to the position indicated, selecting that action's view.
820ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @param position The integer position of the action of interest.
821ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
822ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void setSelectedActionPosition(int position) {
823d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mActionsStylist.getActionsGridView().setSelectedPosition(position);
824ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
825ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
826ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
827ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * Returns the position if the currently selected GuidedAction.
828ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * @return position The integer position of the currently selected action.
829ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
830ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public int getSelectedActionPosition() {
831d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        return mActionsStylist.getActionsGridView().getSelectedPosition();
832ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
833ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
834ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
8350b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * Called by Constructor to provide fragment transitions.  The default implementation assigns
8360b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * transitions based on {@link #getUiStyle()}:
8370b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * <ul>
838517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
8390b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * start(left) for exit transition, shared element enter transition is set to ChangeBounds.
8400b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
841517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
8420b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
843517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
8440b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * enter transition.
8450b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * </ul>
8460b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * <p>
8470b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * The default implementation heavily relies on {@link GuidedActionsStylist} and
8480b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * {@link GuidanceStylist} layout, app may override this method when modifying the default
8490b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * layout of {@link GuidedActionsStylist} or {@link GuidanceStylist}.
85042ae32908312e63b474963fef789017c75feae37Dake Gu     * <p>
8510b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * TIP: because the fragment view is removed during fragment transition, in general app cannot
8520b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * use two Visibility transition together. Workaround is to create your own Visibility
8530b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * transition that controls multiple animators (e.g. slide and fade animation in one Transition
8540b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu     * class).
85542ae32908312e63b474963fef789017c75feae37Dake Gu     */
85642ae32908312e63b474963fef789017c75feae37Dake Gu    protected void onProvideFragmentTransitions() {
85742ae32908312e63b474963fef789017c75feae37Dake Gu        if (Build.VERSION.SDK_INT >= 21) {
858517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            final int uiStyle = getUiStyle();
859517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            if (uiStyle == UI_STYLE_REPLACE) {
8608403619efebe94666c0615c3fc85080a303acf80Dake Gu                Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
861517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu                TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
8628403619efebe94666c0615c3fc85080a303acf80Dake Gu                TransitionHelper.setEnterTransition(this, enterTransition);
863517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu
864517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu                Object changeBounds = TransitionHelper.createChangeBounds(false);
865517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu                TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
866517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            } else if (uiStyle == UI_STYLE_ENTRANCE) {
867e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                if (entranceTransitionType == SLIDE_FROM_SIDE) {
868e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
869e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                            TransitionHelper.FADE_OUT);
870e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.include(fade, R.id.guidedstep_background);
871e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    Object slideFromSide = TransitionHelper.createFadeAndShortSlide(Gravity.END | Gravity.START);
872e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.include(slideFromSide, R.id.content_fragment);
873e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.include(slideFromSide, R.id.action_fragment_root);
874e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    Object enterTransition = TransitionHelper.createTransitionSet(false);
875e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.addTransition(enterTransition, fade);
876e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.addTransition(enterTransition, slideFromSide);
877e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.setEnterTransition(this, enterTransition);
878e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                } else {
879e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    Object slideFromBottom = TransitionHelper.createFadeAndShortSlide(Gravity.BOTTOM);
880e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.include(slideFromBottom, R.id.guidedstep_background_view_root);
881e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    Object enterTransition = TransitionHelper.createTransitionSet(false);
882e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.addTransition(enterTransition, slideFromBottom);
883e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                    TransitionHelper.setEnterTransition(this, enterTransition);
884e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata                }
8850b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                // No shared element transition
8860b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                TransitionHelper.setSharedElementEnterTransition(this, null);
887517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
88842ae32908312e63b474963fef789017c75feae37Dake Gu                // for Activity root, we dont need enter transition, use activity transition
8898403619efebe94666c0615c3fc85080a303acf80Dake Gu                TransitionHelper.setEnterTransition(this, null);
8900b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                // No shared element transition
8910b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                TransitionHelper.setSharedElementEnterTransition(this, null);
89242ae32908312e63b474963fef789017c75feae37Dake Gu            }
8938e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu            // exitTransition is same for all style
8948e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu            Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
8958e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu            TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
8968e5ae27d6db125867640b672cc97d4a158fdfd48Dake Gu            TransitionHelper.setExitTransition(this, exitTransition);
89742ae32908312e63b474963fef789017c75feae37Dake Gu        }
89842ae32908312e63b474963fef789017c75feae37Dake Gu    }
89942ae32908312e63b474963fef789017c75feae37Dake Gu
90042ae32908312e63b474963fef789017c75feae37Dake Gu    /**
901517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Called by onCreateView to inflate background view.  Default implementation loads view
902517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * from {@link R.layout#lb_guidedstep_background} which holds a reference to
903517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * guidedStepBackground.
904517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @param inflater LayoutInflater to load background view.
905517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @param container Parent view of background view.
906517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @param savedInstanceState
907517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @return Created background view or null if no background.
90842ae32908312e63b474963fef789017c75feae37Dake Gu     */
909517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu    public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
910517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu            Bundle savedInstanceState) {
911517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
91242ae32908312e63b474963fef789017c75feae37Dake Gu    }
91342ae32908312e63b474963fef789017c75feae37Dake Gu
91442ae32908312e63b474963fef789017c75feae37Dake Gu    /**
915517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
916517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * is first initialized. UI style is used to choose different fragment transition animations and
917517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * determine if this is the first GuidedStepFragment on backstack. In most cases app does not
918517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * directly call this method, app calls helper function
919517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * {@link #add(FragmentManager, GuidedStepFragment, int)}. However if the app creates Fragment
920517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * transaction and controls backstack by itself, it would need call setUiStyle() to select the
921517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * fragment transition to use.
92242ae32908312e63b474963fef789017c75feae37Dake Gu     *
923517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
924517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     *        {@link #UI_STYLE_ENTRANCE}.
92542ae32908312e63b474963fef789017c75feae37Dake Gu     */
92642ae32908312e63b474963fef789017c75feae37Dake Gu    public void setUiStyle(int style) {
92742ae32908312e63b474963fef789017c75feae37Dake Gu        int oldStyle = getUiStyle();
92842ae32908312e63b474963fef789017c75feae37Dake Gu        Bundle arguments = getArguments();
929fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu        boolean isNew = false;
93042ae32908312e63b474963fef789017c75feae37Dake Gu        if (arguments == null) {
93142ae32908312e63b474963fef789017c75feae37Dake Gu            arguments = new Bundle();
932fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu            isNew = true;
93342ae32908312e63b474963fef789017c75feae37Dake Gu        }
93442ae32908312e63b474963fef789017c75feae37Dake Gu        arguments.putInt(EXTRA_UI_STYLE, style);
93542ae32908312e63b474963fef789017c75feae37Dake Gu        // call setArgument() will validate if the fragment is already added.
936fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu        if (isNew) {
937fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu            setArguments(arguments);
938fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu        }
93942ae32908312e63b474963fef789017c75feae37Dake Gu        if (style != oldStyle) {
94042ae32908312e63b474963fef789017c75feae37Dake Gu            onProvideFragmentTransitions();
94142ae32908312e63b474963fef789017c75feae37Dake Gu        }
94242ae32908312e63b474963fef789017c75feae37Dake Gu    }
94342ae32908312e63b474963fef789017c75feae37Dake Gu
94442ae32908312e63b474963fef789017c75feae37Dake Gu    /**
945517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Read UI style from fragment arguments.  Default value is {@link #UI_STYLE_ENTRANCE} when
946517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * fragment is first initialized.  UI style is used to choose different fragment transition
947517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * animations and determine if this is the first GuidedStepFragment on backstack.
94842ae32908312e63b474963fef789017c75feae37Dake Gu     *
949517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
95042ae32908312e63b474963fef789017c75feae37Dake Gu     * {@link #UI_STYLE_ENTRANCE}.
951517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * @see #onProvideFragmentTransitions()
95242ae32908312e63b474963fef789017c75feae37Dake Gu     */
95342ae32908312e63b474963fef789017c75feae37Dake Gu    public int getUiStyle() {
95442ae32908312e63b474963fef789017c75feae37Dake Gu        Bundle b = getArguments();
955517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        if (b == null) return UI_STYLE_ENTRANCE;
956517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
95742ae32908312e63b474963fef789017c75feae37Dake Gu    }
95842ae32908312e63b474963fef789017c75feae37Dake Gu
95942ae32908312e63b474963fef789017c75feae37Dake Gu    /**
960ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * {@inheritDoc}
961ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
962ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    @Override
963ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void onCreate(Bundle savedInstanceState) {
964ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        super.onCreate(savedInstanceState);
965ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (DEBUG) Log.v(TAG, "onCreate");
96642ae32908312e63b474963fef789017c75feae37Dake Gu        // Set correct transition from saved arguments.
96742ae32908312e63b474963fef789017c75feae37Dake Gu        onProvideFragmentTransitions();
968ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
969ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (state != null) {
970ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            if (mSelectedIndex == -1) {
971ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
972ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            }
973ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
974d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
975d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        onCreateActions(actions, savedInstanceState);
9769050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        if (savedInstanceState != null) {
9779050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            onRestoreActions(actions, savedInstanceState);
9789050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
979d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        setActions(actions);
980d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        ArrayList<GuidedAction> buttonActions = new ArrayList<GuidedAction>();
981d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        onCreateButtonActions(buttonActions, savedInstanceState);
9829050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        if (savedInstanceState != null) {
9839050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            onRestoreButtonActions(buttonActions, savedInstanceState);
9849050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
985d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        setButtonActions(buttonActions);
986d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    }
987d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
988d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    /**
989d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     * {@inheritDoc}
990d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu     */
991d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    @Override
992d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu    public void onDestroyView() {
993d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mGuidanceStylist.onDestroyView();
994d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mActionsStylist.onDestroyView();
995d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mButtonActionsStylist.onDestroyView();
99643e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu        mAdapter = null;
997be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mSubAdapter =  null;
99843e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu        mButtonAdapter = null;
99943e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu        mAdapterGroup = null;
1000d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        super.onDestroyView();
1001ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1002ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1003ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
1004ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * {@inheritDoc}
1005ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
1006ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    @Override
1007ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public View onCreateView(LayoutInflater inflater, ViewGroup container,
1008ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            Bundle savedInstanceState) {
1009ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (DEBUG) Log.v(TAG, "onCreateView");
1010ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1011ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        resolveTheme();
1012ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        inflater = getThemeInflater(inflater);
1013ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1014b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu        GuidedStepRootLayout root = (GuidedStepRootLayout) inflater.inflate(
1015b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu                R.layout.lb_guidedstep_fragment, container, false);
101668d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata
1017b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu        root.setFocusOutStart(isFocusOutStartAllowed());
1018b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu        root.setFocusOutEnd(isFocusOutEndAllowed());
101968d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata
1020517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
1021517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
1022ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1023ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        Guidance guidance = onCreateGuidance(savedInstanceState);
1024ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
1025ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        guidanceContainer.addView(guidanceView);
1026ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1027ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        View actionsView = mActionsStylist.onCreateView(inflater, actionContainer);
1028ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        actionContainer.addView(actionsView);
1029ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1030d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        View buttonActionsView = mButtonActionsStylist.onCreateView(inflater, actionContainer);
1031d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        actionContainer.addView(buttonActionsView);
1032d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
10334158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        GuidedActionAdapter.EditListener editListener = new GuidedActionAdapter.EditListener() {
1034c1741246af607f6be2389056da0182c40f938348Dake Gu
10354158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing                @Override
1036c1741246af607f6be2389056da0182c40f938348Dake Gu                public void onImeOpen() {
1037c1741246af607f6be2389056da0182c40f938348Dake Gu                    runImeAnimations(true);
1038c1741246af607f6be2389056da0182c40f938348Dake Gu                }
1039c1741246af607f6be2389056da0182c40f938348Dake Gu
1040c1741246af607f6be2389056da0182c40f938348Dake Gu                @Override
1041c1741246af607f6be2389056da0182c40f938348Dake Gu                public void onImeClose() {
1042c1741246af607f6be2389056da0182c40f938348Dake Gu                    runImeAnimations(false);
1043c1741246af607f6be2389056da0182c40f938348Dake Gu                }
1044c1741246af607f6be2389056da0182c40f938348Dake Gu
1045c1741246af607f6be2389056da0182c40f938348Dake Gu                @Override
1046bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu                public long onGuidedActionEditedAndProceed(GuidedAction action) {
1047c1741246af607f6be2389056da0182c40f938348Dake Gu                    return GuidedStepFragment.this.onGuidedActionEditedAndProceed(action);
10484158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing                }
1049bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu
1050bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu                @Override
105116ab389e0bd11594059f8164a1477045ee625154Dake Gu                public void onGuidedActionEditCanceled(GuidedAction action) {
105216ab389e0bd11594059f8164a1477045ee625154Dake Gu                    GuidedStepFragment.this.onGuidedActionEditCanceled(action);
1053bcc19824dc43bc2e1bf23bccb1263f8de87ac013Dake Gu                }
10544158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        };
10554158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing
1056be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mAdapter = new GuidedActionAdapter(mActions, new GuidedActionAdapter.ClickListener() {
1057be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            @Override
1058be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            public void onGuidedActionClicked(GuidedAction action) {
1059be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                GuidedStepFragment.this.onGuidedActionClicked(action);
1060be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                if (isSubActionsExpanded()) {
1061be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    collapseSubActions();
1062be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                } else if (action.hasSubActions()) {
1063be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    expandSubActions(action);
1064be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                }
1065be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            }
1066be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        }, this, mActionsStylist, false);
1067be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mButtonAdapter =
1068be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                new GuidedActionAdapter(mButtonActions, new GuidedActionAdapter.ClickListener() {
1069be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    @Override
1070be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    public void onGuidedActionClicked(GuidedAction action) {
1071be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                        GuidedStepFragment.this.onGuidedActionClicked(action);
1072be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    }
1073be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                }, this, mButtonActionsStylist, false);
1074be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mSubAdapter = new GuidedActionAdapter(null, new GuidedActionAdapter.ClickListener() {
1075be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            @Override
1076be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            public void onGuidedActionClicked(GuidedAction action) {
10771ed9dc77616514e20c51baa67a04adab42e4135eDake Gu                if (mActionsStylist.isInExpandTransition()) {
10781ed9dc77616514e20c51baa67a04adab42e4135eDake Gu                    return;
10791ed9dc77616514e20c51baa67a04adab42e4135eDake Gu                }
1080be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                if (GuidedStepFragment.this.onSubGuidedActionClicked(action)) {
1081be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                    collapseSubActions();
1082be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu                }
1083be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            }
1084be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        }, this, mActionsStylist, true);
108543e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu        mAdapterGroup = new GuidedActionAdapterGroup();
1086be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mAdapterGroup.addAdpter(mAdapter, mButtonAdapter);
1087be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        mAdapterGroup.addAdpter(mSubAdapter, null);
108843e10e99e55c1c2eeca31fa13e9cc84160850f59Dake Gu        mAdapterGroup.setEditListener(editListener);
1089b88b36aa081a500eb0e9d4be0bac85b33cd57ddeDake Gu        mActionsStylist.setEditListener(editListener);
1090d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
1091d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mActionsStylist.getActionsGridView().setAdapter(mAdapter);
1092be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        if (mActionsStylist.getSubActionsGridView() != null) {
1093be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu            mActionsStylist.getSubActionsGridView().setAdapter(mSubAdapter);
1094be6eb618b4ba8a74d69fa04c77c717b1fcbea818Dake Gu        }
1095d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
1096d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        if (mButtonActions.size() == 0) {
10970b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            // when there is no button actions, we dont need show the second panel, but keep
10980b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            // the width zero to run ChangeBounds transition.
10990b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
11000b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu                    buttonActionsView.getLayoutParams();
11010b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            lp.weight = 0;
11020b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            buttonActionsView.setLayoutParams(lp);
1103d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        } else {
11040b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            // when there are two actions panel, we need adjust the weight of action to
11050b3811639349fd5791a3f330b23b7e4b1c099c27Dake Gu            // guidedActionContentWidthWeightTwoPanels.
1106d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
1107d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            TypedValue typedValue = new TypedValue();
1108d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
1109d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                    typedValue, true)) {
1110517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu                View actionsRoot = root.findViewById(R.id.action_fragment_root);
1111d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                float weight = typedValue.getFloat();
1112d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
1113d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                        .getLayoutParams();
1114d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                lp.weight = weight;
1115d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                actionsRoot.setLayoutParams(lp);
1116d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            }
1117d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        }
1118ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1119ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
1120ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                mSelectedIndex : getFirstCheckedAction();
1121d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        setSelectedActionPosition(pos);
1122d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu
1123d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu        setSelectedButtonActionPosition(0);
1124ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
112568d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata        // Add the background view.
1126517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
1127517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        if (backgroundView != null) {
112868d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata            FrameLayout backgroundViewRoot = (FrameLayout)root.findViewById(
112968d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata                R.id.guidedstep_background_view_root);
113068d693985e85ee5eed18f78beaaadbfd9b8a4f13susnata            backgroundViewRoot.addView(backgroundView, 0);
1131517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        }
1132517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu        return root;
1133ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1134ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
11355b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu    @Override
11365b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu    public void onResume() {
11375b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu        super.onResume();
11385b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu        getView().findViewById(R.id.action_fragment).requestFocus();
11395b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu    }
11405b20ee9a8d24e70f5e9f2d134440885241a00586Dake Gu
1141ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    /**
11429050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * Get the key will be used to save GuidedAction with Fragment.
11439050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * @param action GuidedAction to get key.
11449050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * @return Key to save the GuidedAction.
11459050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     */
11469050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final String getAutoRestoreKey(GuidedAction action) {
11479050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        return EXTRA_ACTION_PREFIX + action.getId();
11489050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11499050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11509050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    /**
11519050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * Get the key will be used to save GuidedAction with Fragment.
11529050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * @param action GuidedAction to get key.
11539050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     * @return Key to save the GuidedAction.
11549050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu     */
11559050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final String getButtonAutoRestoreKey(GuidedAction action) {
11569050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        return EXTRA_BUTTON_ACTION_PREFIX + action.getId();
11579050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11589050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11599050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final static boolean isSaveEnabled(GuidedAction action) {
11609050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        return action.isAutoSaveRestoreEnabled() && action.getId() != GuidedAction.NO_ID;
11619050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11629050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11639050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final void onRestoreActions(List<GuidedAction> actions, Bundle savedInstanceState) {
11649050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        for (int i = 0, size = actions.size(); i < size; i++) {
11659050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            GuidedAction action = actions.get(i);
11669050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            if (isSaveEnabled(action)) {
11679050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu                action.onRestoreInstanceState(savedInstanceState, getAutoRestoreKey(action));
11689050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            }
11699050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
11709050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11719050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11729050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final void onRestoreButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
11739050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        for (int i = 0, size = actions.size(); i < size; i++) {
11749050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            GuidedAction action = actions.get(i);
11759050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            if (isSaveEnabled(action)) {
11769050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu                action.onRestoreInstanceState(savedInstanceState, getButtonAutoRestoreKey(action));
11779050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            }
11789050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
11799050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11809050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11819050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final void onSaveActions(List<GuidedAction> actions, Bundle outState) {
11829050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        for (int i = 0, size = actions.size(); i < size; i++) {
11839050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            GuidedAction action = actions.get(i);
11849050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            if (isSaveEnabled(action)) {
11859050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu                action.onSaveInstanceState(outState, getAutoRestoreKey(action));
11869050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            }
11879050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
11889050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11899050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11909050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    final void onSaveButtonActions(List<GuidedAction> actions, Bundle outState) {
11919050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        for (int i = 0, size = actions.size(); i < size; i++) {
11929050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            GuidedAction action = actions.get(i);
11939050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            if (isSaveEnabled(action)) {
11949050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu                action.onSaveInstanceState(outState, getButtonAutoRestoreKey(action));
11959050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu            }
11969050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        }
11979050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    }
11989050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu
11999050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu    /**
1200ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     * {@inheritDoc}
1201ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing     */
1202ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    @Override
1203ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    public void onSaveInstanceState(Bundle outState) {
1204ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        super.onSaveInstanceState(outState);
12059050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        onSaveActions(mActions, outState);
12069050c0fc8fbcd8ffe794915375efd5d2b96a0b2dDake Gu        onSaveButtonActions(mButtonActions, outState);
1207ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
1208d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                (mActionsStylist.getActionsGridView() != null) ?
1209d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu                        getSelectedActionPosition() : mSelectedIndex);
1210ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1211ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
121242ae32908312e63b474963fef789017c75feae37Dake Gu    private static boolean isGuidedStepTheme(Context context) {
1213ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        int resId = R.attr.guidedStepThemeFlag;
1214ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        TypedValue typedValue = new TypedValue();
1215ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
1216ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (DEBUG) Log.v(TAG, "Found guided step theme flag? " + found);
1217ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return found && typedValue.type == TypedValue.TYPE_INT_BOOLEAN && typedValue.data != 0;
1218ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1219ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
122037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
122137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * Convenient method to close GuidedStepFragments on top of other content or finish Activity if
122237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * GuidedStepFragments were started in a separate activity.  Pops all stack entries including
122337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
1224517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepFragment,
1225517a5ef1716efc7696a78dc9e0fff0312c47612dDake Gu     * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
122637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
122737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    public void finishGuidedStepFragments() {
122837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        final FragmentManager fragmentManager = getFragmentManager();
122937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        final int entryCount = fragmentManager.getBackStackEntryCount();
123037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        if (entryCount > 0) {
123137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            for (int i = entryCount - 1; i >= 0; i--) {
123237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
1233fd3fc2de015a0771537ff5100668941eb7c0ea00Dake Gu                if (isStackEntryUiStyleEntrance(entry.getName())) {
1234fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu                    GuidedStepFragment top = getCurrentGuidedStepFragment(fragmentManager);
1235fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu                    if (top != null) {
1236fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu                        top.setUiStyle(UI_STYLE_ENTRANCE);
1237fd23a2faf77c66a405a2b2974f719041feda9177Dake Gu                    }
123837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                    fragmentManager.popBackStack(entry.getId(),
123937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                            FragmentManager.POP_BACK_STACK_INCLUSIVE);
124037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                    return;
124137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                }
124237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            }
124337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
124437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        ActivityCompat.finishAfterTransition(getActivity());
124537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
124637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
124737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    /**
124837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * Convenient method to pop to fragment with Given class.
124937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @param  guidedStepFragmentClass  Name of the Class of GuidedStepFragment to pop to.
125037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     * @param flags Either 0 or {@link FragmentManager#POP_BACK_STACK_INCLUSIVE}.
125137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu     */
125237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    public void popBackStackToGuidedStepFragment(Class guidedStepFragmentClass, int flags) {
125337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
125437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            return;
125537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
125637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        final FragmentManager fragmentManager = getFragmentManager();
125737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        final int entryCount = fragmentManager.getBackStackEntryCount();
125837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        String className = guidedStepFragmentClass.getName();
125937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        if (entryCount > 0) {
126037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            for (int i = entryCount - 1; i >= 0; i--) {
126137d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
126237d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                String entryClassName = getGuidedStepFragmentClassName(entry.getName());
126337d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                if (className.equals(entryClassName)) {
126437d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                    fragmentManager.popBackStack(entry.getId(), flags);
126537d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                    return;
126637d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu                }
126737d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu            }
126837d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu        }
126937d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu    }
127037d4ed50ac446f9f8ad033fe56888dd6eb602d4dDake Gu
1271b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    /**
1272b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * Returns true if allows focus out of start edge of GuidedStepFragment, false otherwise.
1273b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * Default value is false, the reason is to disable FocusFinder to find focusable views
1274b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * beneath content of GuidedStepFragment.  Subclass may override.
1275b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * @return True if allows focus out of start edge of GuidedStepFragment.
1276b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     */
1277b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    public boolean isFocusOutStartAllowed() {
1278b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu        return false;
1279b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    }
1280b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu
1281b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    /**
1282b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * Returns true if allows focus out of end edge of GuidedStepFragment, false otherwise.
1283b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * Default value is false, the reason is to disable FocusFinder to find focusable views
1284b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * beneath content of GuidedStepFragment.  Subclass may override.
1285b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     * @return True if allows focus out of end edge of GuidedStepFragment.
1286b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu     */
1287b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    public boolean isFocusOutEndAllowed() {
1288b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu        return false;
1289b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu    }
1290b5ba5532e1ece8fd051ad1066c8efb0d2c32936cDake Gu
1291e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    /**
1292e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * Sets the transition type to be used for {@link #UI_STYLE_ENTRANCE} animation.
1293e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * Currently we provide 2 different variations for animation - slide in from
1294e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * side (default) or bottom.
1295e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     *
1296e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * Ideally we can retireve the screen mode settings from the theme attribute
1297e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * {@code Theme.Leanback.GuidedStep#guidedStepHeightWeight} and use that to
1298e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * determine the transition. But the fragment context to retrieve the theme
1299e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * isn't available on platform v23 or earlier.
1300e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     *
1301e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * For now clients(subclasses) can call this method inside the contructor.
1302e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     * @hide
1303e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata     */
1304e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    public void setEntranceTransitionType(int transitionType) {
1305e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata      this.entranceTransitionType = transitionType;
1306e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata    }
1307e03d465a8a7b3e7c63a3487f2c05b99f28b8bec9susnata
1308ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private void resolveTheme() {
1309ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        // Look up the guidedStepTheme in the currently specified theme.  If it exists,
1310ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        // replace the theme with its value.
1311ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        Activity activity = getActivity();
1312ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (mTheme == -1 && !isGuidedStepTheme(activity)) {
1313ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            // Look up the guidedStepTheme in the activity's currently specified theme.  If it
1314ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            // exists, replace the theme with its value.
1315ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            int resId = R.attr.guidedStepTheme;
1316ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            TypedValue typedValue = new TypedValue();
1317ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
1318ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
1319ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            if (found) {
132042ae32908312e63b474963fef789017c75feae37Dake Gu                ContextThemeWrapper themeWrapper =
132142ae32908312e63b474963fef789017c75feae37Dake Gu                        new ContextThemeWrapper(activity, typedValue.resourceId);
132242ae32908312e63b474963fef789017c75feae37Dake Gu                if (isGuidedStepTheme(themeWrapper)) {
1323ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                    mTheme = typedValue.resourceId;
132442ae32908312e63b474963fef789017c75feae37Dake Gu                    mThemeWrapper = themeWrapper;
1325ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                } else {
1326ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                    found = false;
132742ae32908312e63b474963fef789017c75feae37Dake Gu                    mThemeWrapper = null;
1328ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                }
1329ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            }
1330ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            if (!found) {
1331ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                Log.e(TAG, "GuidedStepFragment does not have an appropriate theme set.");
1332ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            }
133342ae32908312e63b474963fef789017c75feae37Dake Gu        } else if (mTheme != -1) {
133442ae32908312e63b474963fef789017c75feae37Dake Gu            mThemeWrapper = new ContextThemeWrapper(activity, mTheme);
1335ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
1336ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1337ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1338ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private LayoutInflater getThemeInflater(LayoutInflater inflater) {
1339ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        if (mTheme == -1) {
1340ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            return inflater;
1341ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        } else {
134242ae32908312e63b474963fef789017c75feae37Dake Gu            return inflater.cloneInContext(mThemeWrapper);
1343ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
1344ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1345ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
1346ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    private int getFirstCheckedAction() {
1347ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        for (int i = 0, size = mActions.size(); i < size; i++) {
1348ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            if (mActions.get(i).isChecked()) {
1349ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing                return i;
1350ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing            }
1351ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        }
1352ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing        return 0;
1353ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing    }
1354ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing
13554158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing    private void runImeAnimations(boolean entering) {
13564158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        ArrayList<Animator> animators = new ArrayList<Animator>();
13574158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        if (entering) {
13584158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing            mGuidanceStylist.onImeAppearing(animators);
13594158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing            mActionsStylist.onImeAppearing(animators);
1360d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            mButtonActionsStylist.onImeAppearing(animators);
13614158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        } else {
13624158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing            mGuidanceStylist.onImeDisappearing(animators);
13634158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing            mActionsStylist.onImeDisappearing(animators);
1364d14724d33d61385c27a00c31bbc67ad8eeb57b3cDake Gu            mButtonActionsStylist.onImeDisappearing(animators);
13654158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        }
13664158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        AnimatorSet set = new AnimatorSet();
13674158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        set.playTogether(animators);
13684158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing        set.start();
13694158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing    }
13704158705d3f0751d419a08c47a659abeae5f6c196Kris Giesing
1371ebd3d9078dbaebd10a9506ca086435eb63e8a2d2Kris Giesing}
1372