13f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu/*
23f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * Copyright (C) 2014 The Android Open Source Project
33f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu *
43f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
53f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * in compliance with the License. You may obtain a copy of the License at
63f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu *
73f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
83f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu *
93f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
103f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
113f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
123f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu * the License.
133f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu */
143f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gupackage android.support.v17.leanback.app;
153f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
1649dff44ccf0cef8fc8130415fd1dae1a69e4c786Dake Guimport android.annotation.SuppressLint;
173f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Guimport android.os.Bundle;
183f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Guimport android.support.v17.leanback.transition.TransitionHelper;
193f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Guimport android.support.v17.leanback.transition.TransitionListener;
20a5a85434f936023043f074fb86eaa6d48f7f6411Dake Guimport android.support.v17.leanback.util.StateMachine;
2189097f67f988ebba714a95e10369665280db0c27Dake Guimport android.support.v17.leanback.util.StateMachine.Condition;
2289097f67f988ebba714a95e10369665280db0c27Dake Guimport android.support.v17.leanback.util.StateMachine.Event;
23a5a85434f936023043f074fb86eaa6d48f7f6411Dake Guimport android.support.v17.leanback.util.StateMachine.State;
243103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport android.view.View;
253103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport android.view.ViewTreeObserver;
26a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
273f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu/**
2849dff44ccf0cef8fc8130415fd1dae1a69e4c786Dake Gu * Base class for leanback Fragments. This class is not intended to be subclassed by apps.
293f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu */
3076c53f6a2152d31a255a36276ada145be5ec474aDake Gu@SuppressWarnings("FragmentNotInstantiable")
3149dff44ccf0cef8fc8130415fd1dae1a69e4c786Dake Gupublic class BaseSupportFragment extends BrandedSupportFragment {
323f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
33a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    /**
3489097f67f988ebba714a95e10369665280db0c27Dake Gu     * The start state for all
35a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu     */
3689097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_START = new State("START", true, false);
3789097f67f988ebba714a95e10369665280db0c27Dake Gu
3889097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
3989097f67f988ebba714a95e10369665280db0c27Dake Gu     * Initial State for ENTRNACE transition.
4089097f67f988ebba714a95e10369665280db0c27Dake Gu     */
4189097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_INIT = new State("ENTRANCE_INIT");
42684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata
4389097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
4489097f67f988ebba714a95e10369665280db0c27Dake Gu     * prepareEntranceTransition is just called, but view not ready yet. We can enable the
4589097f67f988ebba714a95e10369665280db0c27Dake Gu     * busy spinner.
4689097f67f988ebba714a95e10369665280db0c27Dake Gu     */
4789097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_ON_PREPARED = new State("ENTRANCE_ON_PREPARED", true, false) {
48684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        @Override
49684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        public void run() {
50684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata            mProgressBarManager.show();
51684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        }
52a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    };
53a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
54a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    /**
5589097f67f988ebba714a95e10369665280db0c27Dake Gu     * prepareEntranceTransition is called and main content view to slide in was created, so we can
5689097f67f988ebba714a95e10369665280db0c27Dake Gu     * call {@link #onEntranceTransitionPrepare}. Note that we dont set initial content to invisible
5789097f67f988ebba714a95e10369665280db0c27Dake Gu     * in this State, the process is very different in subclass, e.g. BrowseSupportFragment hide header
5889097f67f988ebba714a95e10369665280db0c27Dake Gu     * views and hide main fragment view in two steps.
59a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu     */
6089097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW = new State(
6189097f67f988ebba714a95e10369665280db0c27Dake Gu            "ENTRANCE_ON_PREPARED_ON_CREATEVIEW") {
62a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        @Override
6389097f67f988ebba714a95e10369665280db0c27Dake Gu        public void run() {
6489097f67f988ebba714a95e10369665280db0c27Dake Gu            onEntranceTransitionPrepare();
65a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        }
6689097f67f988ebba714a95e10369665280db0c27Dake Gu    };
67a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
6889097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
6989097f67f988ebba714a95e10369665280db0c27Dake Gu     * execute the entrance transition.
7089097f67f988ebba714a95e10369665280db0c27Dake Gu     */
7189097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_PERFORM = new State("STATE_ENTRANCE_PERFORM") {
72a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        @Override
73a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        public void run() {
7489097f67f988ebba714a95e10369665280db0c27Dake Gu            mProgressBarManager.hide();
7589097f67f988ebba714a95e10369665280db0c27Dake Gu            onExecuteEntranceTransition();
76a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        }
77a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    };
78a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
79a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    /**
8089097f67f988ebba714a95e10369665280db0c27Dake Gu     * execute onEntranceTransitionEnd.
81a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu     */
8289097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_ON_ENDED = new State("ENTRANCE_ON_ENDED") {
83a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        @Override
8489097f67f988ebba714a95e10369665280db0c27Dake Gu        public void run() {
8589097f67f988ebba714a95e10369665280db0c27Dake Gu            onEntranceTransitionEnd();
86a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        }
8789097f67f988ebba714a95e10369665280db0c27Dake Gu    };
8889097f67f988ebba714a95e10369665280db0c27Dake Gu
8989097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
9089097f67f988ebba714a95e10369665280db0c27Dake Gu     * either entrance transition completed or skipped
9189097f67f988ebba714a95e10369665280db0c27Dake Gu     */
9289097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_ENTRANCE_COMPLETE = new State("ENTRANCE_COMPLETE", true, false);
9389097f67f988ebba714a95e10369665280db0c27Dake Gu
9489097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
9589097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event fragment.onCreate()
9689097f67f988ebba714a95e10369665280db0c27Dake Gu     */
9789097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_ON_CREATE = new Event("onCreate");
9889097f67f988ebba714a95e10369665280db0c27Dake Gu
9989097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
10089097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event fragment.onViewCreated()
10189097f67f988ebba714a95e10369665280db0c27Dake Gu     */
10289097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_ON_CREATEVIEW = new Event("onCreateView");
10389097f67f988ebba714a95e10369665280db0c27Dake Gu
10489097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
10589097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for {@link #prepareEntranceTransition()} is called.
10689097f67f988ebba714a95e10369665280db0c27Dake Gu     */
10789097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_PREPARE_ENTRANCE = new Event("prepareEntranceTransition");
10889097f67f988ebba714a95e10369665280db0c27Dake Gu
10989097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
11089097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for {@link #startEntranceTransition()} is called.
11189097f67f988ebba714a95e10369665280db0c27Dake Gu     */
11289097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_START_ENTRANCE = new Event("startEntranceTransition");
11389097f67f988ebba714a95e10369665280db0c27Dake Gu
11489097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
11589097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for entrance transition is ended through Transition listener.
11689097f67f988ebba714a95e10369665280db0c27Dake Gu     */
11789097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_ENTRANCE_END = new Event("onEntranceTransitionEnd");
118a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
11989097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
12089097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for skipping entrance transition if not supported.
12189097f67f988ebba714a95e10369665280db0c27Dake Gu     */
12289097f67f988ebba714a95e10369665280db0c27Dake Gu    final Condition COND_TRANSITION_NOT_SUPPORTED = new Condition("EntranceTransitionNotSupport") {
123a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        @Override
12489097f67f988ebba714a95e10369665280db0c27Dake Gu        public boolean canProceed() {
12589097f67f988ebba714a95e10369665280db0c27Dake Gu            return !TransitionHelper.systemSupportsEntranceTransitions();
126a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        }
127a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    };
128a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
12989097f67f988ebba714a95e10369665280db0c27Dake Gu    final StateMachine mStateMachine = new StateMachine();
130a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
13199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mEntranceTransition;
13299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    final ProgressBarManager mProgressBarManager = new ProgressBarManager();
1333f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
13449dff44ccf0cef8fc8130415fd1dae1a69e4c786Dake Gu    @SuppressLint("ValidFragment")
135a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    BaseSupportFragment() {
136a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    }
137a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
1383f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
13989097f67f988ebba714a95e10369665280db0c27Dake Gu    public void onCreate(Bundle savedInstanceState) {
14089097f67f988ebba714a95e10369665280db0c27Dake Gu        createStateMachineStates();
14189097f67f988ebba714a95e10369665280db0c27Dake Gu        createStateMachineTransitions();
14289097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.start();
14389097f67f988ebba714a95e10369665280db0c27Dake Gu        super.onCreate(savedInstanceState);
14489097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.fireEvent(EVT_ON_CREATE);
145a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    }
146a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
14789097f67f988ebba714a95e10369665280db0c27Dake Gu    void createStateMachineStates() {
14889097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_START);
14989097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_INIT);
15089097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_ON_PREPARED);
15189097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW);
15289097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_PERFORM);
15389097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_ON_ENDED);
15489097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_ENTRANCE_COMPLETE);
15589097f67f988ebba714a95e10369665280db0c27Dake Gu    }
15689097f67f988ebba714a95e10369665280db0c27Dake Gu
15789097f67f988ebba714a95e10369665280db0c27Dake Gu    void createStateMachineTransitions() {
15889097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_START, STATE_ENTRANCE_INIT, EVT_ON_CREATE);
15989097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_COMPLETE,
16089097f67f988ebba714a95e10369665280db0c27Dake Gu                COND_TRANSITION_NOT_SUPPORTED);
16189097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_COMPLETE,
16289097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_ON_CREATEVIEW);
16389097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_ENTRANCE_ON_PREPARED,
16489097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_PREPARE_ENTRANCE);
16589097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
16689097f67f988ebba714a95e10369665280db0c27Dake Gu                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
16789097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_ON_CREATEVIEW);
16889097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
16989097f67f988ebba714a95e10369665280db0c27Dake Gu                STATE_ENTRANCE_PERFORM,
17089097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_START_ENTRANCE);
17189097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
17289097f67f988ebba714a95e10369665280db0c27Dake Gu                STATE_ENTRANCE_PERFORM);
17389097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_PERFORM,
17489097f67f988ebba714a95e10369665280db0c27Dake Gu                STATE_ENTRANCE_ON_ENDED,
17589097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_ENTRANCE_END);
17689097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_ENDED, STATE_ENTRANCE_COMPLETE);
17789097f67f988ebba714a95e10369665280db0c27Dake Gu    }
17889097f67f988ebba714a95e10369665280db0c27Dake Gu
17989097f67f988ebba714a95e10369665280db0c27Dake Gu    @Override
18089097f67f988ebba714a95e10369665280db0c27Dake Gu    public void onViewCreated(View view, Bundle savedInstanceState) {
18189097f67f988ebba714a95e10369665280db0c27Dake Gu        super.onViewCreated(view, savedInstanceState);
18289097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.fireEvent(EVT_ON_CREATEVIEW);
1833f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
1843f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
1853f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
1863f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Enables entrance transition.<p>
1873f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Entrance transition is the standard slide-in transition that shows rows of data in
1883f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * browse screen and details screen.
1893f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <p>
190572ed31d757c2635ea0a5cdd7ec8a33cd16f77b7Dake Gu     * The method is ignored before LOLLIPOP (API21).
191572ed31d757c2635ea0a5cdd7ec8a33cd16f77b7Dake Gu     * <p>
1923f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * This method must be called in or
1933f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * before onCreate().  Typically entrance transition should be enabled when savedInstance is
1943f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * null so that fragment restored from instanceState does not run an extra entrance transition.
1953f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * When the entrance transition is enabled, the fragment will make headers and content
1963f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * hidden initially.
1973f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * When data of rows are ready, app must call {@link #startEntranceTransition()} to kick off
1983f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * the transition, otherwise the rows will be invisible forever.
1993f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <p>
2003f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * It is similar to android:windowsEnterTransition and can be considered a late-executed
2013f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * android:windowsEnterTransition controlled by app.  There are two reasons that app needs it:
2023f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <li> Workaround the problem that activity transition is not available between launcher and
2033f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * app.  Browse activity must programmatically start the slide-in transition.</li>
2043f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <li> Separates DetailsOverviewRow transition from other rows transition.  So that
2053f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * the DetailsOverviewRow transition can be executed earlier without waiting for all rows
2063f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * to be loaded.</li>
2073f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <p>
2083f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Transition object is returned by createEntranceTransition().  Typically the app does not need
2093f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * override the default transition that browse and details provides.
2103f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2113f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void prepareEntranceTransition() {
21289097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.fireEvent(EVT_PREPARE_ENTRANCE);
2133f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2143f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2153f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
2163f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Create entrance transition.  Subclass can override to load transition from
2173f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * resource or construct manually.  Typically app does not need to
2183f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * override the default transition that browse and details provides.
2193f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2203f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected Object createEntranceTransition() {
2213f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        return null;
2223f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2233f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2243f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
2253f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Run entrance transition.  Subclass may use TransitionManager to perform
2263f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * go(Scene) or beginDelayedTransition().  App should not override the default
2273f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * implementation of browse and details fragment.
2283f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2293f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void runEntranceTransition(Object entranceTransition) {
2303f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2313f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2323f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
233902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu     * Callback when entrance transition is prepared.  This is when fragment should
234902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu     * stop user input and animations.
235902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu     */
236902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    protected void onEntranceTransitionPrepare() {
237902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    }
238902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu
239902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    /**
240902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu     * Callback when entrance transition is started.  This is when fragment should
241902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu     * stop processing layout.
2423f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2433f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionStart() {
2443f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2453f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2463f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
2473f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Callback when entrance transition is ended.
2483f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2493f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionEnd() {
2503f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2513f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2523f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
2533f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * When fragment finishes loading data, it should call startEntranceTransition()
2543f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * to execute the entrance transition.
2553f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * startEntranceTransition() will start transition only if both two conditions
2563f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * are satisfied:
2573f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <li> prepareEntranceTransition() was called.</li>
2583f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <li> has not executed entrance transition yet.</li>
2593f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * <p>
2603f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * If startEntranceTransition() is called before onViewCreated(), it will be pending
2613f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * and executed when view is created.
2623f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
2633f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void startEntranceTransition() {
26489097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.fireEvent(EVT_START_ENTRANCE);
265a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    }
266a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
267a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    void onExecuteEntranceTransition() {
2683f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        // wait till views get their initial position before start transition
2693f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        final View view = getView();
2708b66ca38dbb9f4af7814e7048a14924deb6251a9Dake Gu        if (view == null) {
2718b66ca38dbb9f4af7814e7048a14924deb6251a9Dake Gu            // fragment view destroyed, transition not needed
2728b66ca38dbb9f4af7814e7048a14924deb6251a9Dake Gu            return;
2738b66ca38dbb9f4af7814e7048a14924deb6251a9Dake Gu        }
2742a9b6dfcc745e9ebe3697b590d7f5cdd116b0c3fDake Gu        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
2753f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            @Override
2763f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            public boolean onPreDraw() {
2773f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                view.getViewTreeObserver().removeOnPreDrawListener(this);
2782452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu                if (getContext() == null || getView() == null) {
2792a9b6dfcc745e9ebe3697b590d7f5cdd116b0c3fDake Gu                    // bail out if fragment is destroyed immediately after startEntranceTransition
2802a9b6dfcc745e9ebe3697b590d7f5cdd116b0c3fDake Gu                    return true;
2812a9b6dfcc745e9ebe3697b590d7f5cdd116b0c3fDake Gu                }
2823f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                internalCreateEntranceTransition();
28389097f67f988ebba714a95e10369665280db0c27Dake Gu                onEntranceTransitionStart();
284902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu                if (mEntranceTransition != null) {
285902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu                    runEntranceTransition(mEntranceTransition);
28689097f67f988ebba714a95e10369665280db0c27Dake Gu                } else {
28789097f67f988ebba714a95e10369665280db0c27Dake Gu                    mStateMachine.fireEvent(EVT_ENTRANCE_END);
288902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu                }
2893f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                return false;
2903f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            }
2913f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        });
2923f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        view.invalidate();
2933f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
2943f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
2953f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    void internalCreateEntranceTransition() {
2963f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        mEntranceTransition = createEntranceTransition();
2973f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        if (mEntranceTransition == null) {
2983f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            return;
2993f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        }
3008403619efebe94666c0615c3fc85080a303acf80Dake Gu        TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
3013f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            @Override
3023f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            public void onTransitionEnd(Object transition) {
3033f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                mEntranceTransition = null;
30489097f67f988ebba714a95e10369665280db0c27Dake Gu                mStateMachine.fireEvent(EVT_ENTRANCE_END);
3053f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            }
3063f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        });
3073f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
308684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata
309684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata    /**
310684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata     * Returns the {@link ProgressBarManager}.
31149dff44ccf0cef8fc8130415fd1dae1a69e4c786Dake Gu     * @return The {@link ProgressBarManager}.
312684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata     */
313684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata    public final ProgressBarManager getProgressBarManager() {
314684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        return mProgressBarManager;
315684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata    }
3163f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu}
317