1/* This file is auto-generated from BaseFragment.java.  DO NOT MODIFY. */
2
3/*
4 * Copyright (C) 2014 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7 * in compliance with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software distributed under the License
12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package android.support.v17.leanback.app;
17
18import android.os.Bundle;
19import android.support.v17.leanback.R;
20import android.support.v17.leanback.transition.TransitionHelper;
21import android.support.v17.leanback.transition.TransitionListener;
22import android.view.View;
23import android.view.ViewTreeObserver;
24
25import android.support.v17.leanback.util.StateMachine;
26import android.support.v17.leanback.util.StateMachine.State;
27
28import static android.support.v17.leanback.util.StateMachine.*;
29
30/**
31 * @hide
32 */
33class BaseSupportFragment extends BrandedSupportFragment {
34
35    /**
36     * Condition: {@link TransitionHelper#systemSupportsEntranceTransitions()} is true
37     * Action: none
38     */
39    private final State STATE_ALLOWED = new State() {
40        @Override
41        public boolean canRun() {
42            return TransitionHelper.systemSupportsEntranceTransitions();
43        }
44
45        @Override
46        public void run() {
47            mProgressBarManager.show();
48        }
49    };
50
51    /**
52     * Condition: {@link #isReadyForPrepareEntranceTransition()} is true
53     * Action: {@link #onEntranceTransitionPrepare()} }
54     */
55    private final State STATE_PREPARE = new State() {
56        @Override
57        public boolean canRun() {
58            return isReadyForPrepareEntranceTransition();
59        }
60
61        @Override
62        public void run() {
63            onEntranceTransitionPrepare();
64        }
65    };
66
67    /**
68     * Condition: {@link #isReadyForStartEntranceTransition()} is true
69     * Action: {@link #onExecuteEntranceTransition()} }
70     */
71    private final State STATE_START = new State() {
72        @Override
73        public boolean canRun() {
74            return isReadyForStartEntranceTransition();
75        }
76
77        @Override
78        public void run() {
79            mProgressBarManager.hide();
80            onExecuteEntranceTransition();
81        }
82    };
83
84    final StateMachine mEnterTransitionStates;
85
86    private Object mEntranceTransition;
87    private final ProgressBarManager mProgressBarManager = new ProgressBarManager();
88
89    BaseSupportFragment() {
90        mEnterTransitionStates = new StateMachine();
91        mEnterTransitionStates.addState(STATE_ALLOWED);
92        mEnterTransitionStates.addState(STATE_PREPARE);
93        mEnterTransitionStates.addState(STATE_START);
94    }
95
96    @Override
97    public void onViewCreated(View view, Bundle savedInstanceState) {
98        super.onViewCreated(view, savedInstanceState);
99        performPendingStates();
100    }
101
102    final void performPendingStates() {
103        mEnterTransitionStates.runPendingStates();
104    }
105
106    /**
107     * Enables entrance transition.<p>
108     * Entrance transition is the standard slide-in transition that shows rows of data in
109     * browse screen and details screen.
110     * <p>
111     * The method is ignored before LOLLIPOP (API21).
112     * <p>
113     * This method must be called in or
114     * before onCreate().  Typically entrance transition should be enabled when savedInstance is
115     * null so that fragment restored from instanceState does not run an extra entrance transition.
116     * When the entrance transition is enabled, the fragment will make headers and content
117     * hidden initially.
118     * When data of rows are ready, app must call {@link #startEntranceTransition()} to kick off
119     * the transition, otherwise the rows will be invisible forever.
120     * <p>
121     * It is similar to android:windowsEnterTransition and can be considered a late-executed
122     * android:windowsEnterTransition controlled by app.  There are two reasons that app needs it:
123     * <li> Workaround the problem that activity transition is not available between launcher and
124     * app.  Browse activity must programmatically start the slide-in transition.</li>
125     * <li> Separates DetailsOverviewRow transition from other rows transition.  So that
126     * the DetailsOverviewRow transition can be executed earlier without waiting for all rows
127     * to be loaded.</li>
128     * <p>
129     * Transition object is returned by createEntranceTransition().  Typically the app does not need
130     * override the default transition that browse and details provides.
131     */
132    public void prepareEntranceTransition() {
133        mEnterTransitionStates.runState(STATE_ALLOWED);
134        mEnterTransitionStates.runState(STATE_PREPARE);
135    }
136
137    /**
138     * Return true if entrance transition is enabled and not started yet.
139     * Entrance transition can only be executed once and isEntranceTransitionEnabled()
140     * is reset to false after entrance transition is started.
141     */
142    boolean isEntranceTransitionEnabled() {
143        // Enabled when passed STATE_ALLOWED in prepareEntranceTransition call.
144        return STATE_ALLOWED.getStatus() == STATUS_EXECUTED;
145    }
146
147    /**
148     * Create entrance transition.  Subclass can override to load transition from
149     * resource or construct manually.  Typically app does not need to
150     * override the default transition that browse and details provides.
151     */
152    protected Object createEntranceTransition() {
153        return null;
154    }
155
156    /**
157     * Run entrance transition.  Subclass may use TransitionManager to perform
158     * go(Scene) or beginDelayedTransition().  App should not override the default
159     * implementation of browse and details fragment.
160     */
161    protected void runEntranceTransition(Object entranceTransition) {
162    }
163
164    /**
165     * Callback when entrance transition is prepared.  This is when fragment should
166     * stop user input and animations.
167     */
168    protected void onEntranceTransitionPrepare() {
169    }
170
171    /**
172     * Callback when entrance transition is started.  This is when fragment should
173     * stop processing layout.
174     */
175    protected void onEntranceTransitionStart() {
176    }
177
178    /**
179     * Callback when entrance transition is ended.
180     */
181    protected void onEntranceTransitionEnd() {
182    }
183
184    /**
185     * Returns true if it is ready to perform {@link #prepareEntranceTransition()}, false otherwise.
186     * Subclass may override and add additional conditions.
187     * @return True if it is ready to perform {@link #prepareEntranceTransition()}, false otherwise.
188     * Subclass may override and add additional conditions.
189     */
190    boolean isReadyForPrepareEntranceTransition() {
191        return getView() != null;
192    }
193
194    /**
195     * Returns true if it is ready to perform {@link #startEntranceTransition()}, false otherwise.
196     * Subclass may override and add additional conditions.
197     * @return True if it is ready to perform {@link #startEntranceTransition()}, false otherwise.
198     * Subclass may override and add additional conditions.
199     */
200    boolean isReadyForStartEntranceTransition() {
201        return getView() != null;
202    }
203
204    /**
205     * When fragment finishes loading data, it should call startEntranceTransition()
206     * to execute the entrance transition.
207     * startEntranceTransition() will start transition only if both two conditions
208     * are satisfied:
209     * <li> prepareEntranceTransition() was called.</li>
210     * <li> has not executed entrance transition yet.</li>
211     * <p>
212     * If startEntranceTransition() is called before onViewCreated(), it will be pending
213     * and executed when view is created.
214     */
215    public void startEntranceTransition() {
216        mEnterTransitionStates.runState(STATE_START);
217    }
218
219    void onExecuteEntranceTransition() {
220        // wait till views get their initial position before start transition
221        final View view = getView();
222        view.getViewTreeObserver().addOnPreDrawListener(
223                new ViewTreeObserver.OnPreDrawListener() {
224            @Override
225            public boolean onPreDraw() {
226                view.getViewTreeObserver().removeOnPreDrawListener(this);
227                internalCreateEntranceTransition();
228                if (mEntranceTransition != null) {
229                    onEntranceTransitionStart();
230                    runEntranceTransition(mEntranceTransition);
231                }
232                return false;
233            }
234        });
235        view.invalidate();
236    }
237
238    void internalCreateEntranceTransition() {
239        mEntranceTransition = createEntranceTransition();
240        if (mEntranceTransition == null) {
241            return;
242        }
243        TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
244            @Override
245            public void onTransitionEnd(Object transition) {
246                mEntranceTransition = null;
247                onEntranceTransitionEnd();
248                mEnterTransitionStates.resetStatus();
249            }
250        });
251    }
252
253    /**
254     * Returns the {@link ProgressBarManager}.
255     */
256    public final ProgressBarManager getProgressBarManager() {
257        return mProgressBarManager;
258    }
259}
260