1// CHECKSTYLE:OFF Generated code
2/* This file is auto-generated from BaseSupportFragment.java.  DO NOT MODIFY. */
3
4/*
5 * Copyright (C) 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software distributed under the License
13 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 * or implied. See the License for the specific language governing permissions and limitations under
15 * the License.
16 */
17package android.support.v17.leanback.app;
18
19import android.annotation.SuppressLint;
20import android.os.Bundle;
21import android.support.v17.leanback.transition.TransitionHelper;
22import android.support.v17.leanback.transition.TransitionListener;
23import android.support.v17.leanback.util.StateMachine;
24import android.support.v17.leanback.util.StateMachine.Condition;
25import android.support.v17.leanback.util.StateMachine.Event;
26import android.support.v17.leanback.util.StateMachine.State;
27import android.view.View;
28import android.view.ViewTreeObserver;
29
30/**
31 * Base class for leanback Fragments. This class is not intended to be subclassed by apps.
32 */
33@SuppressWarnings("FragmentNotInstantiable")
34public class BaseFragment extends BrandedFragment {
35
36    /**
37     * The start state for all
38     */
39    final State STATE_START = new State("START", true, false);
40
41    /**
42     * Initial State for ENTRNACE transition.
43     */
44    final State STATE_ENTRANCE_INIT = new State("ENTRANCE_INIT");
45
46    /**
47     * prepareEntranceTransition is just called, but view not ready yet. We can enable the
48     * busy spinner.
49     */
50    final State STATE_ENTRANCE_ON_PREPARED = new State("ENTRANCE_ON_PREPARED", true, false) {
51        @Override
52        public void run() {
53            mProgressBarManager.show();
54        }
55    };
56
57    /**
58     * prepareEntranceTransition is called and main content view to slide in was created, so we can
59     * call {@link #onEntranceTransitionPrepare}. Note that we dont set initial content to invisible
60     * in this State, the process is very different in subclass, e.g. BrowseFragment hide header
61     * views and hide main fragment view in two steps.
62     */
63    final State STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW = new State(
64            "ENTRANCE_ON_PREPARED_ON_CREATEVIEW") {
65        @Override
66        public void run() {
67            onEntranceTransitionPrepare();
68        }
69    };
70
71    /**
72     * execute the entrance transition.
73     */
74    final State STATE_ENTRANCE_PERFORM = new State("STATE_ENTRANCE_PERFORM") {
75        @Override
76        public void run() {
77            mProgressBarManager.hide();
78            onExecuteEntranceTransition();
79        }
80    };
81
82    /**
83     * execute onEntranceTransitionEnd.
84     */
85    final State STATE_ENTRANCE_ON_ENDED = new State("ENTRANCE_ON_ENDED") {
86        @Override
87        public void run() {
88            onEntranceTransitionEnd();
89        }
90    };
91
92    /**
93     * either entrance transition completed or skipped
94     */
95    final State STATE_ENTRANCE_COMPLETE = new State("ENTRANCE_COMPLETE", true, false);
96
97    /**
98     * Event fragment.onCreate()
99     */
100    final Event EVT_ON_CREATE = new Event("onCreate");
101
102    /**
103     * Event fragment.onViewCreated()
104     */
105    final Event EVT_ON_CREATEVIEW = new Event("onCreateView");
106
107    /**
108     * Event for {@link #prepareEntranceTransition()} is called.
109     */
110    final Event EVT_PREPARE_ENTRANCE = new Event("prepareEntranceTransition");
111
112    /**
113     * Event for {@link #startEntranceTransition()} is called.
114     */
115    final Event EVT_START_ENTRANCE = new Event("startEntranceTransition");
116
117    /**
118     * Event for entrance transition is ended through Transition listener.
119     */
120    final Event EVT_ENTRANCE_END = new Event("onEntranceTransitionEnd");
121
122    /**
123     * Event for skipping entrance transition if not supported.
124     */
125    final Condition COND_TRANSITION_NOT_SUPPORTED = new Condition("EntranceTransitionNotSupport") {
126        @Override
127        public boolean canProceed() {
128            return !TransitionHelper.systemSupportsEntranceTransitions();
129        }
130    };
131
132    final StateMachine mStateMachine = new StateMachine();
133
134    Object mEntranceTransition;
135    final ProgressBarManager mProgressBarManager = new ProgressBarManager();
136
137    @SuppressLint("ValidFragment")
138    BaseFragment() {
139    }
140
141    @Override
142    public void onCreate(Bundle savedInstanceState) {
143        createStateMachineStates();
144        createStateMachineTransitions();
145        mStateMachine.start();
146        super.onCreate(savedInstanceState);
147        mStateMachine.fireEvent(EVT_ON_CREATE);
148    }
149
150    void createStateMachineStates() {
151        mStateMachine.addState(STATE_START);
152        mStateMachine.addState(STATE_ENTRANCE_INIT);
153        mStateMachine.addState(STATE_ENTRANCE_ON_PREPARED);
154        mStateMachine.addState(STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW);
155        mStateMachine.addState(STATE_ENTRANCE_PERFORM);
156        mStateMachine.addState(STATE_ENTRANCE_ON_ENDED);
157        mStateMachine.addState(STATE_ENTRANCE_COMPLETE);
158    }
159
160    void createStateMachineTransitions() {
161        mStateMachine.addTransition(STATE_START, STATE_ENTRANCE_INIT, EVT_ON_CREATE);
162        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_COMPLETE,
163                COND_TRANSITION_NOT_SUPPORTED);
164        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_COMPLETE,
165                EVT_ON_CREATEVIEW);
166        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_ON_PREPARED,
167                EVT_PREPARE_ENTRANCE);
168        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
169                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
170                EVT_ON_CREATEVIEW);
171        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
172                STATE_ENTRANCE_PERFORM,
173                EVT_START_ENTRANCE);
174        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
175                STATE_ENTRANCE_PERFORM);
176        mStateMachine.addTransition(STATE_ENTRANCE_PERFORM,
177                STATE_ENTRANCE_ON_ENDED,
178                EVT_ENTRANCE_END);
179        mStateMachine.addTransition(STATE_ENTRANCE_ON_ENDED, STATE_ENTRANCE_COMPLETE);
180    }
181
182    @Override
183    public void onViewCreated(View view, Bundle savedInstanceState) {
184        super.onViewCreated(view, savedInstanceState);
185        mStateMachine.fireEvent(EVT_ON_CREATEVIEW);
186    }
187
188    /**
189     * Enables entrance transition.<p>
190     * Entrance transition is the standard slide-in transition that shows rows of data in
191     * browse screen and details screen.
192     * <p>
193     * The method is ignored before LOLLIPOP (API21).
194     * <p>
195     * This method must be called in or
196     * before onCreate().  Typically entrance transition should be enabled when savedInstance is
197     * null so that fragment restored from instanceState does not run an extra entrance transition.
198     * When the entrance transition is enabled, the fragment will make headers and content
199     * hidden initially.
200     * When data of rows are ready, app must call {@link #startEntranceTransition()} to kick off
201     * the transition, otherwise the rows will be invisible forever.
202     * <p>
203     * It is similar to android:windowsEnterTransition and can be considered a late-executed
204     * android:windowsEnterTransition controlled by app.  There are two reasons that app needs it:
205     * <li> Workaround the problem that activity transition is not available between launcher and
206     * app.  Browse activity must programmatically start the slide-in transition.</li>
207     * <li> Separates DetailsOverviewRow transition from other rows transition.  So that
208     * the DetailsOverviewRow transition can be executed earlier without waiting for all rows
209     * to be loaded.</li>
210     * <p>
211     * Transition object is returned by createEntranceTransition().  Typically the app does not need
212     * override the default transition that browse and details provides.
213     */
214    public void prepareEntranceTransition() {
215        mStateMachine.fireEvent(EVT_PREPARE_ENTRANCE);
216    }
217
218    /**
219     * Create entrance transition.  Subclass can override to load transition from
220     * resource or construct manually.  Typically app does not need to
221     * override the default transition that browse and details provides.
222     */
223    protected Object createEntranceTransition() {
224        return null;
225    }
226
227    /**
228     * Run entrance transition.  Subclass may use TransitionManager to perform
229     * go(Scene) or beginDelayedTransition().  App should not override the default
230     * implementation of browse and details fragment.
231     */
232    protected void runEntranceTransition(Object entranceTransition) {
233    }
234
235    /**
236     * Callback when entrance transition is prepared.  This is when fragment should
237     * stop user input and animations.
238     */
239    protected void onEntranceTransitionPrepare() {
240    }
241
242    /**
243     * Callback when entrance transition is started.  This is when fragment should
244     * stop processing layout.
245     */
246    protected void onEntranceTransitionStart() {
247    }
248
249    /**
250     * Callback when entrance transition is ended.
251     */
252    protected void onEntranceTransitionEnd() {
253    }
254
255    /**
256     * When fragment finishes loading data, it should call startEntranceTransition()
257     * to execute the entrance transition.
258     * startEntranceTransition() will start transition only if both two conditions
259     * are satisfied:
260     * <li> prepareEntranceTransition() was called.</li>
261     * <li> has not executed entrance transition yet.</li>
262     * <p>
263     * If startEntranceTransition() is called before onViewCreated(), it will be pending
264     * and executed when view is created.
265     */
266    public void startEntranceTransition() {
267        mStateMachine.fireEvent(EVT_START_ENTRANCE);
268    }
269
270    void onExecuteEntranceTransition() {
271        // wait till views get their initial position before start transition
272        final View view = getView();
273        if (view == null) {
274            // fragment view destroyed, transition not needed
275            return;
276        }
277        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
278            @Override
279            public boolean onPreDraw() {
280                view.getViewTreeObserver().removeOnPreDrawListener(this);
281                if (FragmentUtil.getContext(BaseFragment.this) == null || getView() == null) {
282                    // bail out if fragment is destroyed immediately after startEntranceTransition
283                    return true;
284                }
285                internalCreateEntranceTransition();
286                onEntranceTransitionStart();
287                if (mEntranceTransition != null) {
288                    runEntranceTransition(mEntranceTransition);
289                } else {
290                    mStateMachine.fireEvent(EVT_ENTRANCE_END);
291                }
292                return false;
293            }
294        });
295        view.invalidate();
296    }
297
298    void internalCreateEntranceTransition() {
299        mEntranceTransition = createEntranceTransition();
300        if (mEntranceTransition == null) {
301            return;
302        }
303        TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
304            @Override
305            public void onTransitionEnd(Object transition) {
306                mEntranceTransition = null;
307                mStateMachine.fireEvent(EVT_ENTRANCE_END);
308            }
309        });
310    }
311
312    /**
313     * Returns the {@link ProgressBarManager}.
314     * @return The {@link ProgressBarManager}.
315     */
316    public final ProgressBarManager getProgressBarManager() {
317        return mProgressBarManager;
318    }
319}
320