1cc671dd3caac1d0cbf3f6999ab063c9ff1f297b2Dake Gu// CHECKSTYLE:OFF Generated code
26193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu/* This file is auto-generated from BrowseFragment.java.  DO NOT MODIFY. */
36193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu
461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu/*
561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Copyright (C) 2014 The Android Open Source Project
661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * in compliance with the License. You may obtain a copy of the License at
961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
1061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
1161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
1261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
1361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
1561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * the License.
1661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu */
1761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gupackage android.support.v17.leanback.app;
1861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
193103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport static android.support.v7.widget.RecyclerView.NO_POSITION;
203103f63e99d47573823957f7aa34308555873221Aurimas Liutikas
215d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Guimport android.support.v4.app.Fragment;
225d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Guimport android.support.v4.app.FragmentManager;
235d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Guimport android.support.v4.app.FragmentManager.BackStackEntry;
245d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Guimport android.support.v4.app.FragmentTransaction;
252452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Guimport android.content.Context;
262f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.content.res.TypedArray;
272f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.graphics.Color;
282f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.graphics.Rect;
292f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.os.Bundle;
3070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbyeimport android.support.annotation.ColorInt;
3161905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.R;
3261905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.transition.TransitionHelper;
3361905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.transition.TransitionListener;
3489097f67f988ebba714a95e10369665280db0c27Dake Guimport android.support.v17.leanback.util.StateMachine.Event;
3589097f67f988ebba714a95e10369665280db0c27Dake Guimport android.support.v17.leanback.util.StateMachine.State;
3661905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.BrowseFrameLayout;
378ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Guimport android.support.v17.leanback.widget.InvisibleRowPresenter;
381c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnataimport android.support.v17.leanback.widget.ListRow;
392f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v17.leanback.widget.ObjectAdapter;
4061905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.OnItemViewClickedListener;
4161905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.OnItemViewSelectedListener;
421c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnataimport android.support.v17.leanback.widget.PageRow;
4361905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.Presenter;
4461905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.PresenterSelector;
452f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v17.leanback.widget.Row;
468df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Guimport android.support.v17.leanback.widget.RowHeaderPresenter;
4761905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.RowPresenter;
48a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnataimport android.support.v17.leanback.widget.ScaleFrameLayout;
49a373804d10f93a9488adc35cf6ce44dce09b3778Dake Guimport android.support.v17.leanback.widget.TitleViewAdapter;
5061905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
518e3566285de4ac771d6188f62fe947e23d371a3dKris Giesingimport android.support.v4.view.ViewCompat;
52041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Guimport android.support.v7.widget.RecyclerView;
5361905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.util.Log;
5461905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.LayoutInflater;
5561905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.View;
5661905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.ViewGroup;
5761905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.ViewGroup.MarginLayoutParams;
58a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnataimport android.view.ViewTreeObserver;
5961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
60fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basakimport java.util.HashMap;
61fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basakimport java.util.Map;
62fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
6361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu/**
6461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * A fragment for creating Leanback browse screens. It is composed of a
6561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * RowsSupportFragment and a HeadersSupportFragment.
6661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
6761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * A BrowseSupportFragment renders the elements of its {@link ObjectAdapter} as a set
6861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * of rows in a vertical list. The elements in this adapter must be subclasses
6961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * of {@link Row}.
7061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
7161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * The HeadersSupportFragment can be set to be either shown or hidden by default, or
7261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * may be disabled entirely. See {@link #setHeadersState} for details.
7361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
7461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * By default the BrowseSupportFragment includes support for returning to the headers
7561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * when the user presses Back. For Activities that customize {@link
766193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu * android.support.v4.app.FragmentActivity#onBackPressed()}, you must disable this default Back key support by
7761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
7861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * use {@link BrowseSupportFragment.BrowseTransitionListener} and
7961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * {@link #startHeadersTransition(boolean)}.
80a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * <p>
81a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * The recommended theme to use with a BrowseSupportFragment is
82a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
83a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * </p>
8461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu */
853f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gupublic class BrowseSupportFragment extends BaseSupportFragment {
8661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
8761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // BUNDLE attribute for saving header show/hide status when backstack is used:
8861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    static final String HEADER_STACK_INDEX = "headerStackIndex";
8961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // BUNDLE attribute for saving header show/hide status when backstack is not used:
9061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    static final String HEADER_SHOW = "headerShow";
91fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private static final String IS_PAGE_ROW = "isPageRow";
92fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
93e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout
9489097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
9589097f67f988ebba714a95e10369665280db0c27Dake Gu     * State to hide headers fragment.
9689097f67f988ebba714a95e10369665280db0c27Dake Gu     */
9789097f67f988ebba714a95e10369665280db0c27Dake Gu    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
9889097f67f988ebba714a95e10369665280db0c27Dake Gu        @Override
9989097f67f988ebba714a95e10369665280db0c27Dake Gu        public void run() {
10089097f67f988ebba714a95e10369665280db0c27Dake Gu            setEntranceTransitionStartState();
10189097f67f988ebba714a95e10369665280db0c27Dake Gu        }
10289097f67f988ebba714a95e10369665280db0c27Dake Gu    };
10389097f67f988ebba714a95e10369665280db0c27Dake Gu
10489097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
10589097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for Header fragment view is created, we could perform
10689097f67f988ebba714a95e10369665280db0c27Dake Gu     * {@link #setEntranceTransitionStartState()} to hide headers fragment initially.
10789097f67f988ebba714a95e10369665280db0c27Dake Gu     */
10889097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_HEADER_VIEW_CREATED = new Event("headerFragmentViewCreated");
10989097f67f988ebba714a95e10369665280db0c27Dake Gu
11089097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
11189097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event for {@link #getMainFragment()} view is created, it's additional requirement to execute
11289097f67f988ebba714a95e10369665280db0c27Dake Gu     * {@link #onEntranceTransitionPrepare()}.
11389097f67f988ebba714a95e10369665280db0c27Dake Gu     */
11489097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_MAIN_FRAGMENT_VIEW_CREATED = new Event("mainFragmentViewCreated");
11589097f67f988ebba714a95e10369665280db0c27Dake Gu
11689097f67f988ebba714a95e10369665280db0c27Dake Gu    /**
11789097f67f988ebba714a95e10369665280db0c27Dake Gu     * Event that data for the screen is ready, this is additional requirement to launch entrance
11889097f67f988ebba714a95e10369665280db0c27Dake Gu     * transition.
11989097f67f988ebba714a95e10369665280db0c27Dake Gu     */
12089097f67f988ebba714a95e10369665280db0c27Dake Gu    final Event EVT_SCREEN_DATA_READY = new Event("screenDataReady");
12189097f67f988ebba714a95e10369665280db0c27Dake Gu
12289097f67f988ebba714a95e10369665280db0c27Dake Gu    @Override
12389097f67f988ebba714a95e10369665280db0c27Dake Gu    void createStateMachineStates() {
12489097f67f988ebba714a95e10369665280db0c27Dake Gu        super.createStateMachineStates();
12589097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
12689097f67f988ebba714a95e10369665280db0c27Dake Gu    }
12789097f67f988ebba714a95e10369665280db0c27Dake Gu
12889097f67f988ebba714a95e10369665280db0c27Dake Gu    @Override
12989097f67f988ebba714a95e10369665280db0c27Dake Gu    void createStateMachineTransitions() {
13089097f67f988ebba714a95e10369665280db0c27Dake Gu        super.createStateMachineTransitions();
13189097f67f988ebba714a95e10369665280db0c27Dake Gu        // when headers fragment view is created we could setEntranceTransitionStartState()
13289097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, STATE_SET_ENTRANCE_START_STATE,
13389097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_HEADER_VIEW_CREATED);
13489097f67f988ebba714a95e10369665280db0c27Dake Gu
13589097f67f988ebba714a95e10369665280db0c27Dake Gu        // add additional requirement for onEntranceTransitionPrepare()
13689097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
13789097f67f988ebba714a95e10369665280db0c27Dake Gu                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
13889097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_MAIN_FRAGMENT_VIEW_CREATED);
13989097f67f988ebba714a95e10369665280db0c27Dake Gu        // add additional requirement to launch entrance transition.
14089097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,  STATE_ENTRANCE_PERFORM,
14189097f67f988ebba714a95e10369665280db0c27Dake Gu                EVT_SCREEN_DATA_READY);
14289097f67f988ebba714a95e10369665280db0c27Dake Gu    }
14389097f67f988ebba714a95e10369665280db0c27Dake Gu
14461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
14561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        int mLastEntryCount;
14661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        int mIndexOfHeadersBackStack;
14761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
14861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        BackStackListener() {
14961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
15061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mIndexOfHeadersBackStack = -1;
15161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
15261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
15361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        void load(Bundle savedInstanceState) {
15461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (savedInstanceState != null) {
15561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
15661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mShowingHeaders = mIndexOfHeadersBackStack == -1;
15761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else {
15861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (!mShowingHeaders) {
15961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    getFragmentManager().beginTransaction()
16061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            .addToBackStack(mWithHeadersBackStackName).commit();
16161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
16261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
16361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
16461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
16561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        void save(Bundle outState) {
16661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
16761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
16861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
16961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
17061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
17161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onBackStackChanged() {
17261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (getFragmentManager() == null) {
17361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
17461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return;
17561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
17661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            int count = getFragmentManager().getBackStackEntryCount();
17761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // if backstack is growing and last pushed entry is "headers" backstack,
17861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // remember the index of the entry.
17961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (count > mLastEntryCount) {
18061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
18161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mWithHeadersBackStackName.equals(entry.getName())) {
18261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mIndexOfHeadersBackStack = count - 1;
18361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
18461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else if (count < mLastEntryCount) {
18561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                // if popped "headers" backstack, initiate the show header transition if needed
18661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mIndexOfHeadersBackStack >= count) {
18769381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                    if (!isHeadersDataReady()) {
188b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                        // if main fragment was restored first before BrowseSupportFragment's adapter gets
189b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                        // restored: don't start header transition, but add the entry back.
19069381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                        getFragmentManager().beginTransaction()
19169381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                                .addToBackStack(mWithHeadersBackStackName).commit();
19269381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                        return;
19369381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                    }
19461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mIndexOfHeadersBackStack = -1;
19561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    if (!mShowingHeaders) {
19661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        startHeadersTransitionInternal(true);
19761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
19861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
19961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
20061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mLastEntryCount = count;
20161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
20261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
20361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
20461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
20561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Listener for transitions between browse headers and rows.
20661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
20761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static class BrowseTransitionListener {
20861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        /**
20961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * Callback when headers transition starts.
21061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *
21161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * @param withHeaders True if the transition will result in headers
21261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *        being shown, false otherwise.
21361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         */
21461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onHeadersTransitionStart(boolean withHeaders) {
21561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
21661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        /**
21761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * Callback when headers transition stops.
21861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *
21961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * @param withHeaders True if the transition will result in headers
22061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *        being shown, false otherwise.
22161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         */
22261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onHeadersTransitionStop(boolean withHeaders) {
22361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
22461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
22561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
226aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    private class SetSelectionRunnable implements Runnable {
227aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_INVALID = -1;
228aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_INTERNAL_SYNC = 0;
229aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_USER_REQUEST = 1;
230aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
231aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private int mPosition;
232aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private int mType;
233aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private boolean mSmooth;
234aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
235aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        SetSelectionRunnable() {
236aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            reset();
237aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
238aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
239aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        void post(int position, int type, boolean smooth) {
240aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // Posting the set selection, rather than calling it immediately, prevents an issue
241aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // with adapter changes.  Example: a row is added before the current selected row;
242aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // first the fast lane view updates its selection, then the rows fragment has that
243aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // new selection propagated immediately; THEN the rows view processes the same adapter
244aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // change and moves the selection again.
245aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            if (type >= mType) {
246aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mPosition = position;
247aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mType = type;
248aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mSmooth = smooth;
249aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mBrowseFrame.removeCallbacks(this);
250aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mBrowseFrame.post(this);
251aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            }
252aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
253aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
254aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        @Override
255aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        public void run() {
256aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            setSelection(mPosition, mSmooth);
257aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            reset();
258aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
259aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
260aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private void reset() {
261aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mPosition = -1;
262aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mType = TYPE_INVALID;
263aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mSmooth = false;
264aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
265aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    }
266aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
2671c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    /**
268cabb8eca86d0248274f57008ff66427fec2e927csusnata     * Possible set of actions that {@link BrowseSupportFragment} exposes to clients. Custom
269cabb8eca86d0248274f57008ff66427fec2e927csusnata     * fragments can interact with {@link BrowseSupportFragment} using this interface.
270cabb8eca86d0248274f57008ff66427fec2e927csusnata     */
271cabb8eca86d0248274f57008ff66427fec2e927csusnata    public interface FragmentHost {
272cabb8eca86d0248274f57008ff66427fec2e927csusnata        /**
273a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Fragments are required to invoke this callback once their view is created
274a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * inside {@link Fragment#onViewCreated} method. {@link BrowseSupportFragment} starts the entrance
275cabb8eca86d0248274f57008ff66427fec2e927csusnata         * animation only after receiving this callback. Failure to invoke this method
276cabb8eca86d0248274f57008ff66427fec2e927csusnata         * will lead to fragment not showing up.
277cabb8eca86d0248274f57008ff66427fec2e927csusnata         *
278cabb8eca86d0248274f57008ff66427fec2e927csusnata         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
279cabb8eca86d0248274f57008ff66427fec2e927csusnata         */
280cabb8eca86d0248274f57008ff66427fec2e927csusnata        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
2816fd4441435b14669deced90a05097dd5fe459acesusnata
2826fd4441435b14669deced90a05097dd5fe459acesusnata        /**
283a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
284a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * is created for transition, the entrance animation only after receiving this callback.
285a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Failure to invoke this method will lead to fragment not showing up.
286a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         *
287a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
288a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         */
289a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
290a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
291a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        /**
292a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * Show or hide title view in {@link BrowseSupportFragment} for fragments mapped to
293a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseSupportFragment is fully
294a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * in control of showing/hiding title view.
295a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * <p>
296a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * When HeadersSupportFragment is visible, BrowseSupportFragment will hide search affordance view if
297a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * there are other focusable rows above currently focused row.
2986fd4441435b14669deced90a05097dd5fe459acesusnata         *
2996fd4441435b14669deced90a05097dd5fe459acesusnata         * @param show Boolean indicating whether or not to show the title view.
3006fd4441435b14669deced90a05097dd5fe459acesusnata         */
3016fd4441435b14669deced90a05097dd5fe459acesusnata        void showTitleView(boolean show);
302cabb8eca86d0248274f57008ff66427fec2e927csusnata    }
303cabb8eca86d0248274f57008ff66427fec2e927csusnata
304cabb8eca86d0248274f57008ff66427fec2e927csusnata    /**
305cabb8eca86d0248274f57008ff66427fec2e927csusnata     * Default implementation of {@link FragmentHost} that is used only by
306cabb8eca86d0248274f57008ff66427fec2e927csusnata     * {@link BrowseSupportFragment}.
307cabb8eca86d0248274f57008ff66427fec2e927csusnata     */
308cabb8eca86d0248274f57008ff66427fec2e927csusnata    private final class FragmentHostImpl implements FragmentHost {
3097350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        boolean mShowTitleView = true;
310cabb8eca86d0248274f57008ff66427fec2e927csusnata
31199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        FragmentHostImpl() {
31299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        }
31399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas
314cabb8eca86d0248274f57008ff66427fec2e927csusnata        @Override
315cabb8eca86d0248274f57008ff66427fec2e927csusnata        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
31689097f67f988ebba714a95e10369665280db0c27Dake Gu            mStateMachine.fireEvent(EVT_MAIN_FRAGMENT_VIEW_CREATED);
31789097f67f988ebba714a95e10369665280db0c27Dake Gu            if (!mIsPageRow) {
31889097f67f988ebba714a95e10369665280db0c27Dake Gu                // If it's not a PageRow: it's a ListRow, so we already have data ready.
31989097f67f988ebba714a95e10369665280db0c27Dake Gu                mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
32089097f67f988ebba714a95e10369665280db0c27Dake Gu            }
321a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        }
322a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
323a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        @Override
324a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
325a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
326a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // ignore the request.
327a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
328a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu                return;
329a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            }
330a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
331a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // We only honor showTitle request for PageRows.
332a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            if (!mIsPageRow) {
333a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu                return;
334a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            }
335a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
33689097f67f988ebba714a95e10369665280db0c27Dake Gu            mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
337cabb8eca86d0248274f57008ff66427fec2e927csusnata        }
3386fd4441435b14669deced90a05097dd5fe459acesusnata
3396fd4441435b14669deced90a05097dd5fe459acesusnata        @Override
3406fd4441435b14669deced90a05097dd5fe459acesusnata        public void showTitleView(boolean show) {
3417350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata            mShowTitleView = show;
342d0fc2e48059f718676a531af06a31849f54c1ca9susnata
343d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
344d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // ignore the request.
345d0fc2e48059f718676a531af06a31849f54c1ca9susnata            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
346d0fc2e48059f718676a531af06a31849f54c1ca9susnata                return;
347b10ba3b01290ce801180a3d5dc992825af8cb3absusnata            }
348d0fc2e48059f718676a531af06a31849f54c1ca9susnata
349d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // We only honor showTitle request for PageRows.
350d0fc2e48059f718676a531af06a31849f54c1ca9susnata            if (!mIsPageRow) {
351d0fc2e48059f718676a531af06a31849f54c1ca9susnata                return;
352d0fc2e48059f718676a531af06a31849f54c1ca9susnata            }
353d0fc2e48059f718676a531af06a31849f54c1ca9susnata
3548ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            updateTitleViewVisibility();
3556fd4441435b14669deced90a05097dd5fe459acesusnata        }
356cabb8eca86d0248274f57008ff66427fec2e927csusnata    }
357cabb8eca86d0248274f57008ff66427fec2e927csusnata
358cabb8eca86d0248274f57008ff66427fec2e927csusnata    /**
35944ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls     * Interface that defines the interaction between {@link BrowseSupportFragment} and its main
360fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
3611c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * it will be used to get the fragment to be shown in the content section. Clients can
36244ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls     * provide any implementation of fragment and customize its interaction with
3631c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * {@link BrowseSupportFragment} by overriding the necessary methods.
3641c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
3651c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * <p>
3661c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * Clients are expected to provide
367fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
368fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * implementations of {@link MainFragmentAdapter} for given content types. Currently
3691c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
3701c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
371fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsSupportFragment.MainFragmentAdapter}.
3721c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
3731c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * <p>
3741c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
375fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
376fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * and provide that through {@link MainFragmentAdapterRegistry}.
377fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link MainFragmentAdapter} implementation can supply any fragment and override
3781c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * just those interactions that makes sense.
3791c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     */
380fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class MainFragmentAdapter<T extends Fragment> {
381f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        private boolean mScalingEnabled;
382fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private final T mFragment;
38399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        FragmentHostImpl mFragmentHost;
384fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
385fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public MainFragmentAdapter(T fragment) {
386fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            this.mFragment = fragment;
387fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
388fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
389fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public final T getFragment() {
390fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return mFragment;
391fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
3922f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3932f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3942f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Returns whether its scrolling.
3952f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3961c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public boolean isScrolling() {
3971c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return false;
3981c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3992f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4002f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4012f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Set the visibility of titles/hovercard of browse rows.
4022f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4031c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setExpand(boolean expand) {
4041c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
4052f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4062f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4072f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * For rows that willing to participate entrance transition,  this function
4082f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * hide views if afterTransition is true,  show views if afterTransition is false.
4092f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4101c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setEntranceTransitionState(boolean state) {
4111c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
4122f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4132f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4142f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Sets the window alignment and also the pivots for scale operation.
4152f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4161c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setAlignment(int windowAlignOffsetFromTop) {
4171c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
4182f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4192f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4202f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition prepare start.
4212f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4221c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public boolean onTransitionPrepare() {
4231c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return false;
4241c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
4252f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4262f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4272f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition start.
4282f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4291c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void onTransitionStart() {
4301c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
4312f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4322f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
4332f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition end.
4342f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
4351c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void onTransitionEnd() {
4361c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
437f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
438f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        /**
439f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         * Returns whether row scaling is enabled.
440f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         */
441f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        public boolean isScalingEnabled() {
442f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            return mScalingEnabled;
443f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        }
444f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
445f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        /**
446f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         * Sets the row scaling property.
447f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         */
448f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        public void setScalingEnabled(boolean scalingEnabled) {
449f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            this.mScalingEnabled = scalingEnabled;
450f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        }
451cabb8eca86d0248274f57008ff66427fec2e927csusnata
4527350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        /**
4537350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         * Returns the current host interface so that main fragment can interact with
4547350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         * {@link BrowseSupportFragment}.
4557350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         */
456cabb8eca86d0248274f57008ff66427fec2e927csusnata        public final FragmentHost getFragmentHost() {
457cabb8eca86d0248274f57008ff66427fec2e927csusnata            return mFragmentHost;
458cabb8eca86d0248274f57008ff66427fec2e927csusnata        }
4597350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
4607350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        void setFragmentHost(FragmentHostImpl fragmentHost) {
4617350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata            this.mFragmentHost = fragmentHost;
4627350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        }
4632f5ebf3f6f7bb6a24856f389e369b247118ba119susnata    }
4642f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4651c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    /**
466d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * Interface to be implemented by all fragments for providing an instance of
467d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * {@link MainFragmentAdapter}. Both {@link RowsSupportFragment} and custom fragment provided
468d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * against {@link PageRow} will need to implement this interface.
469d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     */
470d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    public interface MainFragmentAdapterProvider {
471d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        /**
472d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseSupportFragment}
473d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * would use to communicate with the target fragment.
474d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         */
475d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        MainFragmentAdapter getMainFragmentAdapter();
476d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    }
477d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
478d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    /**
47944ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls     * Interface to be implemented by {@link RowsSupportFragment} and its subclasses for providing
480d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * an instance of {@link MainFragmentRowsAdapter}.
481d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     */
482d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    public interface MainFragmentRowsAdapterProvider {
483d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        /**
484d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseSupportFragment}
485d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * would use to communicate with the target fragment.
486d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         */
487d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
488d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    }
489d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
490d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    /**
491d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * This is used to pass information to {@link RowsSupportFragment} or its subclasses.
492d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * {@link BrowseSupportFragment} uses this interface to pass row based interaction events to
493d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * the target fragment.
4941c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     */
495fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class MainFragmentRowsAdapter<T extends Fragment> {
496fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private final T mFragment;
497fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
498fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public MainFragmentRowsAdapter(T fragment) {
499fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (fragment == null) {
500fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                throw new IllegalArgumentException("Fragment can't be null");
501fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
502fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            this.mFragment = fragment;
503fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
504fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
505fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public final T getFragment() {
506fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return mFragment;
507fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
508a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
509a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Set the visibility titles/hover of browse rows.
510a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
511a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setAdapter(ObjectAdapter adapter) {
512a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
5131c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
514a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
515a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Sets an item clicked listener on the fragment.
516a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
517a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
518a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
519a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
520a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
521a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Sets an item selection listener.
522a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
523a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
524a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
525a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
526a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
527a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Selects a Row and perform an optional task on the Row.
528a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
529a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setSelectedPosition(int rowPosition,
530a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata                                        boolean smooth,
531a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata                                        final Presenter.ViewHolderTask rowHolderTask) {
532a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
533a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
534a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
535a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Selects a Row.
536a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
537a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setSelectedPosition(int rowPosition, boolean smooth) {
538a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
539a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
540a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
541181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu         * @return The position of selected row.
542a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
543a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public int getSelectedPosition() {
544a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            return 0;
545a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
546181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
547181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        /**
548181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu         * @param position Position of Row.
549181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu         * @return Row ViewHolder.
550181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu         */
551181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        public RowPresenter.ViewHolder findRowViewHolderByPosition(int position) {
552181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return null;
553181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
554a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    }
5551c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
556a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    private boolean createMainFragment(ObjectAdapter adapter, int position) {
557a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        Object item = null;
558f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu        if (!mCanShowHeaders) {
559f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu            // when header is disabled, we can decide to use RowsSupportFragment even no data.
560f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu        } else if (adapter == null || adapter.size() == 0) {
561fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return false;
562a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        } else {
563bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (position < 0) {
564bb0a680c10b84b83833a59634373140f8bd0750csusnata                position = 0;
565bb0a680c10b84b83833a59634373140f8bd0750csusnata            } else if (position >= adapter.size()) {
5661c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                throw new IllegalArgumentException(
5671c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                        String.format("Invalid position %d requested", position));
5681c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            }
569a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            item = adapter.get(position);
570a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
5711c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
572fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        boolean oldIsPageRow = mIsPageRow;
573f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu        mIsPageRow = mCanShowHeaders && item instanceof PageRow;
574fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        boolean swap;
575fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
576fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragment == null) {
577fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            swap = true;
578a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        } else {
579fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (oldIsPageRow) {
580fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                swap = true;
581fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
582fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                swap = mIsPageRow;
583fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
5841c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
585fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
586fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (swap) {
587fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
588d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
589d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                throw new IllegalArgumentException(
590d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                        "Fragment must implement MainFragmentAdapterProvider");
591d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            }
592d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
593d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            mMainFragmentAdapter = ((MainFragmentAdapterProvider)mMainFragment)
594d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    .getMainFragmentAdapter();
595cabb8eca86d0248274f57008ff66427fec2e927csusnata            mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
596fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (!mIsPageRow) {
597d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
598d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = ((MainFragmentRowsAdapterProvider)mMainFragment)
599d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                            .getMainFragmentRowsAdapter();
600d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                } else {
601d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = null;
602d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                }
603fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mIsPageRow = mMainFragmentRowsAdapter == null;
604fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
605fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mMainFragmentRowsAdapter = null;
606fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
607fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
608d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
609fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        return swap;
610a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    }
611a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
612a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    /**
613fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * Factory class responsible for creating fragment given the current item. {@link ListRow}
61444ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls     * should return {@link RowsSupportFragment} or its subclass whereas {@link PageRow}
615fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * can return any fragment class.
616a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata     */
617fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public abstract static class FragmentFactory<T extends Fragment> {
618fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public abstract T createFragment(Object row);
619fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
6201c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
621fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    /**
622fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * FragmentFactory implementation for {@link ListRow}.
623fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     */
624fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class ListRowFragmentFactory extends FragmentFactory<RowsSupportFragment> {
625fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        @Override
626fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public RowsSupportFragment createFragment(Object row) {
627fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return new RowsSupportFragment();
62880a1d2dfbe5c1f26370cc1753c3ae321f126f5d2Carlos Valdivia        }
629fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
6304400ca12ff731a7392715bc3d8ad3539b4c37889susnata
631fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    /**
632fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
633fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
634fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * handling {@link ListRow}. Developers can override that and also if they want to
635fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * use custom fragment, they can register a custom {@link FragmentFactory}
636fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * against {@link PageRow}.
637fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     */
638fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public final static class MainFragmentAdapterRegistry {
639abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
640cfcb31c4895793dda843faf67d1b769268e3cce8susnata        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
641cfcb31c4895793dda843faf67d1b769268e3cce8susnata
642cfcb31c4895793dda843faf67d1b769268e3cce8susnata        public MainFragmentAdapterRegistry() {
643cfcb31c4895793dda843faf67d1b769268e3cce8susnata            registerFragment(ListRow.class, sDefaultFragmentFactory);
644cfcb31c4895793dda843faf67d1b769268e3cce8susnata        }
645fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
646fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public void registerFragment(Class rowClass, FragmentFactory factory) {
647cfcb31c4895793dda843faf67d1b769268e3cce8susnata            mItemToFragmentFactoryMapping.put(rowClass, factory);
648fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
649fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
650fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public Fragment createFragment(Object item) {
651f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu            FragmentFactory fragmentFactory = item == null ? sDefaultFragmentFactory :
652f89c67eeac3938f245c858774cc7c9f87fb7487dDake Gu                    mItemToFragmentFactoryMapping.get(item.getClass());
653cfcb31c4895793dda843faf67d1b769268e3cce8susnata            if (fragmentFactory == null && !(item instanceof PageRow)) {
654cfcb31c4895793dda843faf67d1b769268e3cce8susnata                fragmentFactory = sDefaultFragmentFactory;
655cfcb31c4895793dda843faf67d1b769268e3cce8susnata            }
656cfcb31c4895793dda843faf67d1b769268e3cce8susnata
657cfcb31c4895793dda843faf67d1b769268e3cce8susnata            return fragmentFactory.createFragment(item);
658a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
6591c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
6602f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
66199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final String TAG = "BrowseSupportFragment";
66261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
66361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
66461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
66599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static boolean DEBUG = false;
66661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
66761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is enabled and shown by default. */
66861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_ENABLED = 1;
66961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
67061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is enabled and hidden by default. */
67161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_HIDDEN = 2;
67261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
67361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is disabled and will never be shown. */
67461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_DISABLED = 3;
67561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
6763103f63e99d47573823957f7aa34308555873221Aurimas Liutikas    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
6773103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            new MainFragmentAdapterRegistry();
67899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    MainFragmentAdapter mMainFragmentAdapter;
67999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Fragment mMainFragment;
68099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    HeadersSupportFragment mHeadersSupportFragment;
681fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private MainFragmentRowsAdapter mMainFragmentRowsAdapter;
68261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
68361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private ObjectAdapter mAdapter;
6848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private PresenterSelector mAdapterPresenter;
6858ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private PresenterSelector mWrappingPresenterSelector;
68661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
68761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mHeadersState = HEADERS_ENABLED;
68861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mBrandColor = Color.TRANSPARENT;
68961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private boolean mBrandColorSet;
69061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
69199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BrowseFrameLayout mBrowseFrame;
692a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private ScaleFrameLayout mScaleFrameLayout;
69399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mHeadersBackStackEnabled = true;
69499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    String mWithHeadersBackStackName;
69599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mShowingHeaders = true;
69699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mCanShowHeaders = true;
6978e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing    private int mContainerListMarginStart;
69861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mContainerListAlignTop;
699f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    private boolean mMainFragmentScaleEnabled = true;
70099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
70161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private OnItemViewClickedListener mOnItemViewClickedListener;
702bb0a680c10b84b83833a59634373140f8bd0750csusnata    private int mSelectedPosition = -1;
703f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    private float mScaleFactor;
70499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mIsPageRow;
70561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
70661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private PresenterSelector mHeaderPresenterSelector;
707aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
70861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
70961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // transition related:
71099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mSceneWithHeaders;
71199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mSceneWithoutHeaders;
712c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    private Object mSceneAfterEntranceTransition;
71399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mHeadersTransition;
71499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BackStackListener mBackStackChangedListener;
71599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BrowseTransitionListener mBrowseTransitionListener;
71661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
71761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String ARG_TITLE = BrowseSupportFragment.class.getCanonicalName() + ".title";
71861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String ARG_HEADERS_STATE =
71961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        BrowseSupportFragment.class.getCanonicalName() + ".headersState";
72061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
72161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
722a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Creates arguments for a browse fragment.
72361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
72461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param args The Bundle to place arguments into, or null if the method
72561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        should return a new Bundle.
72661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param title The title of the BrowseSupportFragment.
72761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headersState The initial state of the headers of the
72861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        BrowseSupportFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
72961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
73061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @return A Bundle with the given arguments for creating a BrowseSupportFragment.
73161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
73261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static Bundle createArgs(Bundle args, String title, int headersState) {
73361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args == null) {
73461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            args = new Bundle();
73561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
73661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        args.putString(ARG_TITLE, title);
73761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        args.putInt(ARG_HEADERS_STATE, headersState);
73861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return args;
73961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
74061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
74161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
74261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the brand color for the browse fragment. The brand color is used as
74361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * the primary color for UI elements in the browse fragment. For example,
74461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * the background color of the headers fragment uses the brand color.
74561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
74661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param color The color to use as the brand color of the fragment.
74761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
74870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setBrandColor(@ColorInt int color) {
74961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrandColor = color;
75061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrandColorSet = true;
75161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
75261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeadersSupportFragment != null) {
75361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
75461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
75561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
75661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
75761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
75861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the brand color for the browse fragment.
75961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * The default is transparent.
76061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
76170acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
76261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public int getBrandColor() {
76361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mBrandColor;
76461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
76561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
76661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
7678ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
7688ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * DividerRow and PageRow.
7698ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     */
7708ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private void createAndSetWrapperPresenter() {
7718ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
7728ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (adapterPresenter == null) {
7738ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
7748ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
7758ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (adapterPresenter == mAdapterPresenter) {
7768ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return;
7778ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
7788ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAdapterPresenter = adapterPresenter;
7798ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
7808ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        Presenter[] presenters = adapterPresenter.getPresenters();
7818ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
7828ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
7838ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
7848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
7858ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAdapter.setPresenterSelector(new PresenterSelector() {
7868ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            @Override
7878ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            public Presenter getPresenter(Object item) {
7888ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                Row row = (Row) item;
7898ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                if (row.isRenderedAsRowView()) {
7908ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                    return adapterPresenter.getPresenter(item);
7918ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                } else {
7928ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                    return invisibleRowPresenter;
7938ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                }
7948ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
7958ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
7968ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            @Override
7978ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            public Presenter[] getPresenters() {
7988ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return allPresenters;
7998ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
8008ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        });
8018ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
8028ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
8038ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    /**
80461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the adapter containing the rows for the fragment.
80561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
80661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>The items referenced by the adapter must be be derived from
80761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link Row}. These rows will be used by the rows fragment and the headers
80861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * fragment (if not disabled) to render the browse rows.
80961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
81061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param adapter An ObjectAdapter for the browse rows. All items must
81161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        derive from {@link Row}.
81261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
81361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setAdapter(ObjectAdapter adapter) {
81461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mAdapter = adapter;
8158ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        createAndSetWrapperPresenter();
816c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu        if (getView() == null) {
817c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu            return;
818c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu        }
819bb0a680c10b84b83833a59634373140f8bd0750csusnata        replaceMainFragment(mSelectedPosition);
820bb0a680c10b84b83833a59634373140f8bd0750csusnata
821bb0a680c10b84b83833a59634373140f8bd0750csusnata        if (adapter != null) {
822bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (mMainFragmentRowsAdapter != null) {
823b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                mMainFragmentRowsAdapter.setAdapter(new ListRowDataAdapter(adapter));
824bb0a680c10b84b83833a59634373140f8bd0750csusnata            }
82561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setAdapter(adapter);
82661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
82761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
82861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
829fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
830fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        return mMainFragmentAdapterRegistry;
8311c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
832fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
83361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
83461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the adapter containing the rows for the fragment.
83561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
83661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public ObjectAdapter getAdapter() {
83761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mAdapter;
83861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
83961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
84061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
84161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets an item selection listener.
84261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
84361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
84461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mExternalOnItemViewSelectedListener = listener;
84561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
84661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
84761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
84861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns an item selection listener.
84961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
85061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
85161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mExternalOnItemViewSelectedListener;
85261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
85361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
85461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
8551c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * Get RowsSupportFragment if it's bound to BrowseSupportFragment or null if either BrowseSupportFragment has
8561c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * not been created yet or a different fragment is bound to it.
8571c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
8581c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * @return RowsSupportFragment if it's bound to BrowseSupportFragment or null otherwise.
8590d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
8600d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public RowsSupportFragment getRowsSupportFragment() {
8611c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        if (mMainFragment instanceof RowsSupportFragment) {
8621c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return (RowsSupportFragment) mMainFragment;
8631c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
8641c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
8651c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        return null;
8660d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
8670d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
8680d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
869489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu     * @return Current main fragment or null if not created.
870489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu     */
871489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu    public Fragment getMainFragment() {
872489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu        return mMainFragment;
873489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu    }
874489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu
875489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu    /**
8760d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Get currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
8770d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @return Currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
8780d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
8790d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public HeadersSupportFragment getHeadersSupportFragment() {
8800d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        return mHeadersSupportFragment;
8810d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
8820d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
8830d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
88461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets an item clicked listener on the fragment.
88561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * OnItemViewClickedListener will override {@link View.OnClickListener} that
88661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
887cabb8eca86d0248274f57008ff66427fec2e927csusnata     * So in general, developer should choose one of the listeners but not both.
88861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
88961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
89061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mOnItemViewClickedListener = listener;
8912aff8659c7362b48f099a13ffad390bf7984dd5aJaewan Kim        if (mMainFragmentRowsAdapter != null) {
892fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
89361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
89461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
89561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
89661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
89761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the item Clicked listener.
89861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
89961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public OnItemViewClickedListener getOnItemViewClickedListener() {
90061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mOnItemViewClickedListener;
90161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
90261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
90361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
904a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Starts a headers transition.
90561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
90661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>This method will begin a transition to either show or hide the
90761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * headers, depending on the value of withHeaders. If headers are disabled
90861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * for this browse fragment, this method will throw an exception.
90961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
91061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param withHeaders True if the headers should transition to being shown,
91161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        false if the transition should result in headers being hidden.
91261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
91361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void startHeadersTransition(boolean withHeaders) {
91461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (!mCanShowHeaders) {
91561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            throw new IllegalStateException("Cannot start headers transition");
91661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
91761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
91861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
91961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
92061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        startHeadersTransitionInternal(withHeaders);
92161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
92261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
92361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
92461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if the headers transition is currently running.
92561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
92661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public boolean isInHeadersTransition() {
92761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersTransition != null;
92861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
92961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
93061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
93161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if headers are shown.
93261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
93361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public boolean isShowingHeaders() {
93461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mShowingHeaders;
93561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
93661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
93761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
938a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets a listener for browse fragment transitions.
93961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
94061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param listener The listener to call when a browse headers transition
94161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        begins or ends.
94261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
94361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
94461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseTransitionListener = listener;
94561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
94661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
94761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
948f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * @deprecated use {@link BrowseSupportFragment#enableMainFragmentScaling(boolean)} instead.
94961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
95061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param enable true to enable row scaling
95161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
952d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    @Deprecated
95361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void enableRowScaling(boolean enable) {
954f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        enableMainFragmentScaling(enable);
955f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    }
956f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
957f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    /**
958f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * Enables scaling of main fragment when headers are present. For the page/row fragment,
959f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * scaling is enabled only when both this method and
960fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
961f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     *
962f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * @param enable true to enable row scaling
963f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     */
964f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    public void enableMainFragmentScaling(boolean enable) {
965f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        mMainFragmentScaleEnabled = enable;
96661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
96761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
96899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void startHeadersTransitionInternal(final boolean withHeaders) {
96961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (getFragmentManager().isDestroyed()) {
97061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
97161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
97269381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        if (!isHeadersDataReady()) {
97369381509eace8e71ba4886e9e1e78cda62b66516Dake Gu            return;
97469381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        }
97561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mShowingHeaders = withHeaders;
9761c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionPrepare();
9771c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionStart();
978a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        onExpandTransitionStart(!withHeaders, new Runnable() {
97961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
98061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
981902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu                mHeadersSupportFragment.onTransitionPrepare();
98261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersSupportFragment.onTransitionStart();
98361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                createHeadersTransition();
98461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mBrowseTransitionListener != null) {
98561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
98661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
9871c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                TransitionHelper.runTransition(
9881c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
98961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mHeadersBackStackEnabled) {
99061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    if (!withHeaders) {
99161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        getFragmentManager().beginTransaction()
99261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                                .addToBackStack(mWithHeadersBackStackName).commit();
99361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    } else {
99461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
99561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        if (index >= 0) {
99661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
99761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            getFragmentManager().popBackStackImmediate(entry.getId(),
99861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
99961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        }
100061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
100161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
100261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
100361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
100461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
100561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
10060d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    boolean isVerticalScrolling() {
100761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        // don't run transition
10081c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        return mHeadersSupportFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
100961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
101061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1011e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout
101261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
101361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            new BrowseFrameLayout.OnFocusSearchListener() {
101461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
101561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public View onFocusSearch(View focused, int direction) {
101661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // if headers is running transition,  focus stays
10175ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            if (mCanShowHeaders && isInHeadersTransition()) {
10185ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout                return focused;
10195ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            }
102061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
10215ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout
10223103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (getTitleView() != null && focused != getTitleView()
10233103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    && direction == View.FOCUS_UP) {
1024e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                return getTitleView();
1025e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            }
10263103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (getTitleView() != null && getTitleView().hasFocus()
10273103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    && direction == View.FOCUS_DOWN) {
10283103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                return mCanShowHeaders && mShowingHeaders
10293103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                        ? mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
10305ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            }
10315ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout
10328e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            boolean isRtl = ViewCompat.getLayoutDirection(focused) == View.LAYOUT_DIRECTION_RTL;
10338e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
10348e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
1035e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            if (mCanShowHeaders && direction == towardStart) {
103669381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
103761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return focused;
103861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
103961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return mHeadersSupportFragment.getVerticalGridView();
10408e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            } else if (direction == towardEnd) {
1041e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                if (isVerticalScrolling()) {
104261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return focused;
1043489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu                } else if (mMainFragment != null && mMainFragment.getView() != null) {
1044489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu                    return mMainFragment.getView();
104561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
1046489c9a861b7cde47efcd5cf6351bc9696786ae41Dake Gu                return focused;
10478ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
10488ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // disable focus_down moving into PageFragment.
10498ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return focused;
105061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else {
105161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return null;
105261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
105361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
105461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
105561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
105699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    final boolean isHeadersDataReady() {
105769381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        return mAdapter != null && mAdapter.size() != 0;
105869381509eace8e71ba4886e9e1e78cda62b66516Dake Gu    }
105969381509eace8e71ba4886e9e1e78cda62b66516Dake Gu
106061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
106161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            new BrowseFrameLayout.OnChildFocusListener() {
106261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
106361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
106461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
106528fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            if (getChildFragmentManager().isDestroyed()) {
106628fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu                return true;
106728fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            }
106861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // Make sure not changing focus when requestFocus() is called.
106961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mCanShowHeaders && mShowingHeaders) {
10703103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null
10715d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Gu                        && mHeadersSupportFragment.getView().requestFocus(
10725d926e60b034b2e4d1404c6ac088a13b9c91ee3eDake Gu                                direction, previouslyFocusedRect)) {
107361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return true;
107461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
107561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
10763103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (mMainFragment != null && mMainFragment.getView() != null
10773103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
107861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return true;
107961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
1080b655650666d7bd317c41c7a5be229e3a80dd2692Dake Gu            return getTitleView() != null
1081b655650666d7bd317c41c7a5be229e3a80dd2692Dake Gu                    && getTitleView().requestFocus(direction, previouslyFocusedRect);
10821c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
108361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
108461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
108561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onRequestChildFocus(View child, View focused) {
108628fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            if (getChildFragmentManager().isDestroyed()) {
108728fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu                return;
108828fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            }
108961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (!mCanShowHeaders || isInHeadersTransition()) return;
109028fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            int childId = child.getId();
109161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (childId == R.id.browse_container_dock && mShowingHeaders) {
109261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(false);
109361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
109461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(true);
109561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
109661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
109761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
109861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
109961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
110061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onSaveInstanceState(Bundle outState) {
1101e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        super.onSaveInstanceState(outState);
1102fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
1103fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
1104fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
110561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBackStackChangedListener != null) {
110661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mBackStackChangedListener.save(outState);
110761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        } else {
110861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
110961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
111061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
111161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
111261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
111361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onCreate(Bundle savedInstanceState) {
111461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onCreate(savedInstanceState);
11152452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu        final Context context = getContext();
11162452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
11178e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing        mContainerListMarginStart = (int) ta.getDimension(
11182452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
111946443cb5b092f1d9156342645088eead9da026f6Dake Gu                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
112061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mContainerListAlignTop = (int) ta.getDimension(
11212452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
112246443cb5b092f1d9156342645088eead9da026f6Dake Gu                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
112361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        ta.recycle();
112461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
112561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        readArguments(getArguments());
112661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
112734f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout        if (mCanShowHeaders) {
112834f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            if (mHeadersBackStackEnabled) {
112934f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
113034f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mBackStackChangedListener = new BackStackListener();
113134f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
113234f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mBackStackChangedListener.load(savedInstanceState);
113334f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            } else {
113434f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                if (savedInstanceState != null) {
113534f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
113634f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                }
113734f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            }
113834f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout        }
1139a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1140f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
114161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
114261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
114361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
1144fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public void onDestroyView() {
1145fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragmentRowsAdapter = null;
1146fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragmentAdapter = null;
1147fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragment = null;
1148fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mHeadersSupportFragment = null;
1149fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        super.onDestroyView();
1150fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
1151fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
1152fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    @Override
115361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onDestroy() {
115461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBackStackChangedListener != null) {
115561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
115661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
115761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onDestroy();
115861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
115961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
116050cf9ada93e50e906f20f5edf595234ada196d45Dake Gu    /**
116150cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     * Creates a new {@link HeadersSupportFragment} instance. Subclass of BrowseSupportFragment may override and
116250cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     * return an instance of subclass of HeadersSupportFragment, e.g. when app wants to replace presenter
116350cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     * to render HeaderItem.
116450cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     *
116550cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     * @return A new instance of {@link HeadersSupportFragment} or its subclass.
116650cf9ada93e50e906f20f5edf595234ada196d45Dake Gu     */
116750cf9ada93e50e906f20f5edf595234ada196d45Dake Gu    public HeadersSupportFragment onCreateHeadersSupportFragment() {
116850cf9ada93e50e906f20f5edf595234ada196d45Dake Gu        return new HeadersSupportFragment();
116950cf9ada93e50e906f20f5edf595234ada196d45Dake Gu    }
117050cf9ada93e50e906f20f5edf595234ada196d45Dake Gu
117161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
117261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public View onCreateView(LayoutInflater inflater, ViewGroup container,
117361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            Bundle savedInstanceState) {
11747350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
1175a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
117650cf9ada93e50e906f20f5edf595234ada196d45Dake Gu            mHeadersSupportFragment = onCreateHeadersSupportFragment();
1177bb0a680c10b84b83833a59634373140f8bd0750csusnata
1178a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            createMainFragment(mAdapter, mSelectedPosition);
1179bb0a680c10b84b83833a59634373140f8bd0750csusnata            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
1180bb0a680c10b84b83833a59634373140f8bd0750csusnata                    .replace(R.id.browse_headers_dock, mHeadersSupportFragment);
1181bb0a680c10b84b83833a59634373140f8bd0750csusnata
1182bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (mMainFragment != null) {
1183bb0a680c10b84b83833a59634373140f8bd0750csusnata                ft.replace(R.id.scale_frame, mMainFragment);
1184bb0a680c10b84b83833a59634373140f8bd0750csusnata            } else {
1185bb0a680c10b84b83833a59634373140f8bd0750csusnata                // Empty adapter used to guard against lazy adapter loading. When this
1186bb0a680c10b84b83833a59634373140f8bd0750csusnata                // fragment is instantiated, mAdapter might not have the data or might not
1187bb0a680c10b84b83833a59634373140f8bd0750csusnata                // have been set. In either of those cases mFragmentAdapter will be null.
1188bb0a680c10b84b83833a59634373140f8bd0750csusnata                // This way we can maintain the invariant that mMainFragmentAdapter is never
1189bb0a680c10b84b83833a59634373140f8bd0750csusnata                // null and it avoids doing null checks all over the code.
1190bb0a680c10b84b83833a59634373140f8bd0750csusnata                mMainFragmentAdapter = new MainFragmentAdapter(null);
1191cabb8eca86d0248274f57008ff66427fec2e927csusnata                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
1192bb0a680c10b84b83833a59634373140f8bd0750csusnata            }
1193bb0a680c10b84b83833a59634373140f8bd0750csusnata
1194bb0a680c10b84b83833a59634373140f8bd0750csusnata            ft.commit();
119561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        } else {
119661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment = (HeadersSupportFragment) getChildFragmentManager()
1197fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                    .findFragmentById(R.id.browse_headers_dock);
1198fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
1199d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            mMainFragmentAdapter = ((MainFragmentAdapterProvider)mMainFragment)
1200d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    .getMainFragmentAdapter();
1201dc1492d3655550b7a9c861aae1bd538410c7324dDake Gu            mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
1202fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
12033103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            mIsPageRow = savedInstanceState != null
1204b655650666d7bd317c41c7a5be229e3a80dd2692Dake Gu                    && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
1205fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
12063103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            mSelectedPosition = savedInstanceState != null
12073103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
12087350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
1209fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (!mIsPageRow) {
1210d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
1211d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = ((MainFragmentRowsAdapterProvider) mMainFragment)
1212d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                            .getMainFragmentRowsAdapter();
1213d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                } else {
1214d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = null;
1215d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                }
1216fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
1217fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mMainFragmentRowsAdapter = null;
1218fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
121961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
122061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
122161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
122261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeaderPresenterSelector != null) {
122361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
122461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
122561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setAdapter(mAdapter);
12268df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu        mHeadersSupportFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
122761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setOnHeaderClickedListener(mHeaderClickedListener);
12282f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
122961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
123061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1231684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        getProgressBarManager().setRootView((ViewGroup)root);
1232684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata
123361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
123461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
1235e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
123661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1237a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu        installTitleView(inflater, mBrowseFrame, savedInstanceState);
1238a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu
1239a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
1240a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setPivotX(0);
1241a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
1242a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1243a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setupMainFragment();
1244a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
124561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBrandColorSet) {
124661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
124761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
124861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
12498403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
125061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
125161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
125261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                showHeaders(true);
125361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
125461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
12558403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
125661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
125761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
125861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                showHeaders(false);
125961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
126061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
12618403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
1262c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            @Override
1263c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            public void run() {
1264c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu                setEntranceTransitionEndState();
1265c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            }
1266c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        });
1267d0fc2e48059f718676a531af06a31849f54c1ca9susnata
126861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return root;
126961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
127061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
12711c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    private void setupMainFragment() {
1272fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentRowsAdapter != null) {
127335d7a6c31606ed4ca38deda3cacae080a95c95c9susnata            if (mAdapter != null) {
127435d7a6c31606ed4ca38deda3cacae080a95c95c9susnata                mMainFragmentRowsAdapter.setAdapter(new ListRowDataAdapter(mAdapter));
127535d7a6c31606ed4ca38deda3cacae080a95c95c9susnata            }
12763eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
12773eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
1278fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
1279a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
12801c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
12811c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
128299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void createHeadersTransition() {
12832452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu        mHeadersTransition = TransitionHelper.loadTransition(getContext(),
12843103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                mShowingHeaders
12853103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
128661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
12878403619efebe94666c0615c3fc85080a303acf80Dake Gu        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
128861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
128961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void onTransitionStart(Object transition) {
129061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
129161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
129261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void onTransitionEnd(Object transition) {
129361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersTransition = null;
129454bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                if (mMainFragmentAdapter != null) {
129554bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    mMainFragmentAdapter.onTransitionEnd();
129654bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    if (!mShowingHeaders && mMainFragment != null) {
129754bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        View mainFragmentView = mMainFragment.getView();
129854bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
129954bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                            mainFragmentView.requestFocus();
130054bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        }
130161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
130254bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                }
130354bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                if (mHeadersSupportFragment != null) {
130454bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    mHeadersSupportFragment.onTransitionEnd();
130554bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    if (mShowingHeaders) {
130654bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        VerticalGridView headerGridView = mHeadersSupportFragment.getVerticalGridView();
130754bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        if (headerGridView != null && !headerGridView.hasFocus()) {
130854bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                            headerGridView.requestFocus();
130954bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        }
131061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
1311d0fc2e48059f718676a531af06a31849f54c1ca9susnata                }
13126fd4441435b14669deced90a05097dd5fe459acesusnata
13137350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata                // Animate TitleView once header animation is complete.
13148ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                updateTitleViewVisibility();
1315d0fc2e48059f718676a531af06a31849f54c1ca9susnata
131661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mBrowseTransitionListener != null) {
131761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
131861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
131961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
132061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
132161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
132261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
13238ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    void updateTitleViewVisibility() {
13248ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (!mShowingHeaders) {
13258ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showTitleView;
13268ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (mIsPageRow && mMainFragmentAdapter != null) {
13278ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // page fragment case:
13288ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
13298ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
13308ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // regular row view case:
13318ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitleView = isFirstRowWithContent(mSelectedPosition);
13328ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13338ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (showTitleView) {
1334a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
13358ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
13368ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(false);
13378ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13388ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        } else {
13398ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
13408ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showBranding;
13418ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showSearch;
13428ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (mIsPageRow && mMainFragmentAdapter != null) {
13438ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
13448ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
13458ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showBranding = isFirstRowWithContent(mSelectedPosition);
13468ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13478ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
13488ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            int flags = 0;
1349a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
1350a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
13518ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (flags != 0) {
13528ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(flags);
13538ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
13548ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(false);
13558ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13568ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13578ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
13588ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
13598ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
13608ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAdapter == null || mAdapter.size() == 0) {
13618ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return true;
13628ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13638ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        for (int i = 0; i < mAdapter.size(); i++) {
13648ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            final Row row = (Row) mAdapter.get(i);
13658ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (row.isRenderedAsRowView() || row instanceof PageRow) {
13668ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return rowPosition == i;
13678ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13688ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13698ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        return true;
13708ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
13718ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
13728ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    boolean isFirstRowWithContent(int rowPosition) {
13738ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAdapter == null || mAdapter.size() == 0) {
13748ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return true;
13758ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13768ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        for (int i = 0; i < mAdapter.size(); i++) {
13778ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            final Row row = (Row) mAdapter.get(i);
13788ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (row.isRenderedAsRowView()) {
13798ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return rowPosition == i;
13808ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13818ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13828ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        return true;
13838ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
13848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
138561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
138661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the {@link PresenterSelector} used to render the row headers.
138761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
138861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headerPresenterSelector The PresenterSelector that will determine
138961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        the Presenter for each row header.
139061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
139161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
139261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeaderPresenterSelector = headerPresenterSelector;
139361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeadersSupportFragment != null) {
139461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
139561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
139661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
139761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1398c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    private void setHeadersOnScreen(boolean onScreen) {
1399c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        MarginLayoutParams lp;
1400c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        View containerList;
140161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        containerList = mHeadersSupportFragment.getView();
140261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        lp = (MarginLayoutParams) containerList.getLayoutParams();
14038e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
140461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        containerList.setLayoutParams(lp);
1405c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
140661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
140799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void showHeaders(boolean show) {
1408c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        if (DEBUG) Log.v(TAG, "showHeaders " + show);
1409c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        mHeadersSupportFragment.setHeadersEnabled(show);
1410c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(show);
1411a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        expandMainFragment(!show);
1412a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1413a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1414a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void expandMainFragment(boolean expand) {
1415a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
1416c1ec7d7eff002329b245a4edb1b87da2f3b5e006Dake Gu        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
1417a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setLayoutParams(params);
1418a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mMainFragmentAdapter.setExpand(expand);
1419a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1420a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setMainFragmentAlignment();
1421f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        final float scaleFactor = !expand
1422bb0a680c10b84b83833a59634373140f8bd0750csusnata                && mMainFragmentScaleEnabled
1423bb0a680c10b84b83833a59634373140f8bd0750csusnata                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
1424a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
1425a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setChildScale(scaleFactor);
142661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
142761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
142861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private HeadersSupportFragment.OnHeaderClickedListener mHeaderClickedListener =
142961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        new HeadersSupportFragment.OnHeaderClickedListener() {
143061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
1431729cbf4cd57c87bcd569db5974c8cbd51a942581Dake Gu            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
143261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
143361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return;
143461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
143561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(false);
14361c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                mMainFragment.getView().requestFocus();
143761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
143861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        };
143961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
14403eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
14413eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
14423eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu
14433eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
14443eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            mMainFragmentRowsAdapter = fragmentRowsAdapter;
14453eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        }
14463eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu
144761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
144861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
144961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                RowPresenter.ViewHolder rowViewHolder, Row row) {
14503eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            int position = mMainFragmentRowsAdapter.getSelectedPosition();
145161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "row selected position " + position);
145261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            onRowSelected(position);
145361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mExternalOnItemViewSelectedListener != null) {
145461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
145561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        rowViewHolder, row);
145661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
145761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
145861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
145961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
14608df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu    private HeadersSupportFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
14618df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu            new HeadersSupportFragment.OnHeaderViewSelectedListener() {
146261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
14638df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
14640d841b3454f896da58deb506ca22730bfd04f34fDake Gu            int position = mHeadersSupportFragment.getSelectedPosition();
146561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "header selected position " + position);
146661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            onRowSelected(position);
146761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
146861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
146961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
147099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void onRowSelected(int position) {
147161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (position != mSelectedPosition) {
1472aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mSetSelectionRunnable.post(
1473aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                    position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
147461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
147561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
147661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
147799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void setSelection(int position, boolean smooth) {
14781c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        if (position == NO_POSITION) {
14791c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return;
148061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
14811c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
1482e5bf7f32e6f2957e41fc7794b49ed10108171261Dake Gu        mSelectedPosition = position;
1483e5bf7f32e6f2957e41fc7794b49ed10108171261Dake Gu        if (mHeadersSupportFragment == null || mMainFragmentAdapter == null) {
1484e5bf7f32e6f2957e41fc7794b49ed10108171261Dake Gu            // onDestroyView() called
1485e5bf7f32e6f2957e41fc7794b49ed10108171261Dake Gu            return;
1486e5bf7f32e6f2957e41fc7794b49ed10108171261Dake Gu        }
14871c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mHeadersSupportFragment.setSelectedPosition(position, smooth);
1488bb0a680c10b84b83833a59634373140f8bd0750csusnata        replaceMainFragment(position);
1489bb0a680c10b84b83833a59634373140f8bd0750csusnata
1490bb0a680c10b84b83833a59634373140f8bd0750csusnata        if (mMainFragmentRowsAdapter != null) {
1491bb0a680c10b84b83833a59634373140f8bd0750csusnata            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
1492bb0a680c10b84b83833a59634373140f8bd0750csusnata        }
14937350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
14948ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        updateTitleViewVisibility();
1495bb0a680c10b84b83833a59634373140f8bd0750csusnata    }
14963faa5780307cf10ff0e4a1d89a9ba099cdad2e15susnata
1497bb0a680c10b84b83833a59634373140f8bd0750csusnata    private void replaceMainFragment(int position) {
1498a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        if (createMainFragment(mAdapter, position)) {
1499041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            swapToMainFragment();
1500a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
15011c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            setupMainFragment();
15021c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
150361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
150461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1505041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu    private void swapToMainFragment() {
1506041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        final VerticalGridView gridView = mHeadersSupportFragment.getVerticalGridView();
15073f19c1616ed2749a70ecc764dccb467ec96aa1f4Dake Gu        if (isShowingHeaders() && gridView != null
15083f19c1616ed2749a70ecc764dccb467ec96aa1f4Dake Gu                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
1509041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // if user is scrolling HeadersSupportFragment,  swap to empty fragment and wait scrolling
1510041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // finishes.
1511041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            getChildFragmentManager().beginTransaction()
1512041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    .replace(R.id.scale_frame, new Fragment()).commit();
1513041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            gridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
1514694edde99dc3782374977dab6d9aa34a16c13337Dake Gu                @SuppressWarnings("ReferenceEquality")
1515041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                @Override
1516041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1517041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
1518041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        gridView.removeOnScrollListener(this);
1519041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        FragmentManager fm = getChildFragmentManager();
1520041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
1521041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        if (currentFragment != mMainFragment) {
1522041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
1523041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        }
1524041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    }
1525041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                }
1526041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            });
1527041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        } else {
1528041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // Otherwise swap immediately
1529041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            getChildFragmentManager().beginTransaction()
1530041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    .replace(R.id.scale_frame, mMainFragment).commit();
1531041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        }
15321c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
15331c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
15343f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
15353f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Sets the selected row position with smooth animation.
15363f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
15373f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setSelectedPosition(int position) {
15383f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        setSelectedPosition(position, true);
15393f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
15403f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
15413f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
15420d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Gets position of currently selected row.
15430d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @return Position of currently selected row.
15440d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
15450d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public int getSelectedPosition() {
15460d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        return mSelectedPosition;
15470d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
15480d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
15490d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
1550181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @return selected row ViewHolder inside fragment created by {@link MainFragmentRowsAdapter}.
1551181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     */
1552181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    public RowPresenter.ViewHolder getSelectedRowViewHolder() {
1553181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mMainFragmentRowsAdapter != null) {
1554181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            int rowPos = mMainFragmentRowsAdapter.getSelectedPosition();
1555181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return mMainFragmentRowsAdapter.findRowViewHolderByPosition(rowPos);
1556181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
1557181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        return null;
1558181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
1559181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1560181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    /**
15613f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Sets the selected row position.
15623f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
15633f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setSelectedPosition(int position, boolean smooth) {
1564aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        mSetSelectionRunnable.post(
1565aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
15663f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
15673f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
15680d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
15690d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Selects a Row and perform an optional task on the Row. For example
15700d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
15710d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
15720d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * RowsSupportFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
15730d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * ViewGroup, Bundle)}).
15740d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     *
15750d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param rowPosition Which row to select.
15760d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param smooth True to scroll to the row, false for no animation.
15770d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
15780d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * fragment will be collapsed.
15790d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
15800d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public void setSelectedPosition(int rowPosition, boolean smooth,
1581cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            final Presenter.ViewHolderTask rowHolderTask) {
1582fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentAdapterRegistry == null) {
15830d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu            return;
15840d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        }
15850d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        if (rowHolderTask != null) {
15860d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu            startHeadersTransition(false);
15870d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        }
1588fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentRowsAdapter != null) {
1589fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
1590a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
15910d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
15920d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
159361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
159461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onStart() {
159561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onStart();
15962f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        mHeadersSupportFragment.setAlignment(mContainerListAlignTop);
1597a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setMainFragmentAlignment();
159861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1599b21aa0b72a6800f694a3b2ba513a187deb28f252Dake Gu        if (mCanShowHeaders && mShowingHeaders && mHeadersSupportFragment != null
1600b21aa0b72a6800f694a3b2ba513a187deb28f252Dake Gu                && mHeadersSupportFragment.getView() != null) {
160161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.getView().requestFocus();
1602b21aa0b72a6800f694a3b2ba513a187deb28f252Dake Gu        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment != null
1603b21aa0b72a6800f694a3b2ba513a187deb28f252Dake Gu                && mMainFragment.getView() != null) {
16041c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            mMainFragment.getView().requestFocus();
160561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
16061c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
160761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mCanShowHeaders) {
160861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            showHeaders(mShowingHeaders);
160961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
16101c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
161189097f67f988ebba714a95e10369665280db0c27Dake Gu        mStateMachine.fireEvent(EVT_HEADER_VIEW_CREATED);
161261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
161361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1614a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
1615a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        if (expand) {
1616a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            callback.run();
1617a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            return;
1618a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1619a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        // Run a "pre" layout when we go non-expand, in order to get the initial
1620a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        // positions of added rows.
1621fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
1622a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1623a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1624a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void setMainFragmentAlignment() {
1625a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        int alignOffset = mContainerListAlignTop;
1626f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        if (mMainFragmentScaleEnabled
1627f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata                && mMainFragmentAdapter.isScalingEnabled()
1628f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata                && mShowingHeaders) {
1629f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
1630a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1631a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mMainFragmentAdapter.setAlignment(alignOffset);
1632a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1633a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
163461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
1635a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Enables/disables headers transition on back key support. This is enabled by
163661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * default. The BrowseSupportFragment will add a back stack entry when headers are
163761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * showing. Running a headers transition when the back key is pressed only
163861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * works when the headers state is {@link #HEADERS_ENABLED} or
163961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link #HEADERS_HIDDEN}.
164061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>
164161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * NOTE: If an Activity has its own onBackPressed() handling, you must
164261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
164361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * and {@link BrowseTransitionListener} in your own back stack handling.
164461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
164561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
164661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersBackStackEnabled = headersBackStackEnabled;
164761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
164861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
164961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
165061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if headers transition on back key support is enabled.
165161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
165261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public final boolean isHeadersTransitionOnBackEnabled() {
165361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersBackStackEnabled;
165461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
165561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
165661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private void readArguments(Bundle args) {
165761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args == null) {
165861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
165961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
166061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args.containsKey(ARG_TITLE)) {
166161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            setTitle(args.getString(ARG_TITLE));
166261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
166361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args.containsKey(ARG_HEADERS_STATE)) {
166461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            setHeadersState(args.getInt(ARG_HEADERS_STATE));
166561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
166661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
166761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
166861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
166961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the state for the headers column in the browse fragment. Must be one
167061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
167161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link #HEADERS_DISABLED}.
167261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
167361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headersState The state of the headers for the browse fragment.
167461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
167561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setHeadersState(int headersState) {
167661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
167761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            throw new IllegalArgumentException("Invalid headers state: " + headersState);
167861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
167961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
168061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
168161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (headersState != mHeadersState) {
168261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersState = headersState;
168361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            switch (headersState) {
168461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_ENABLED:
168561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = true;
168661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = true;
168761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
168861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_HIDDEN:
168961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = true;
169061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = false;
169161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
169261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_DISABLED:
169361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = false;
169461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = false;
169561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
169661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                default:
169761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    Log.w(TAG, "Unknown headers state: " + headersState);
169861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
169961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
170061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mHeadersSupportFragment != null) {
170161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
170261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
170361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
170461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
170561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
170661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
170761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the state of the headers column in the browse fragment.
170861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
170961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public int getHeadersState() {
171061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersState;
171161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
1712c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
17133f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
17143f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected Object createEntranceTransition() {
17152452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu        return TransitionHelper.loadTransition(getContext(),
17163f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                R.transition.lb_browse_entrance_transition);
1717c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1718c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
17193f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
17203f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void runEntranceTransition(Object entranceTransition) {
17218403619efebe94666c0615c3fc85080a303acf80Dake Gu        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
1722c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1723c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
17243f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
1725902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    protected void onEntranceTransitionPrepare() {
1726902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu        mHeadersSupportFragment.onTransitionPrepare();
1727a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        mMainFragmentAdapter.setEntranceTransitionState(false);
17281c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionPrepare();
1729902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    }
1730902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu
1731902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    @Override
17323f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionStart() {
17333f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        mHeadersSupportFragment.onTransitionStart();
17341c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionStart();
1735c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1736c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
17373f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
17383f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionEnd() {
1739b082c7277cff057bdff19e411e345c3d6fea2e12susnata        if (mMainFragmentAdapter != null) {
1740b082c7277cff057bdff19e411e345c3d6fea2e12susnata            mMainFragmentAdapter.onTransitionEnd();
1741b082c7277cff057bdff19e411e345c3d6fea2e12susnata        }
1742b082c7277cff057bdff19e411e345c3d6fea2e12susnata
1743b082c7277cff057bdff19e411e345c3d6fea2e12susnata        if (mHeadersSupportFragment != null) {
1744b082c7277cff057bdff19e411e345c3d6fea2e12susnata            mHeadersSupportFragment.onTransitionEnd();
1745b082c7277cff057bdff19e411e345c3d6fea2e12susnata        }
1746c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1747c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
17483f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    void setSearchOrbViewOnScreen(boolean onScreen) {
1749a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
1750b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata        if (searchOrbView != null) {
1751b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
1752b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
1753b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            searchOrbView.setLayoutParams(lp);
1754b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata        }
1755c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1756c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
1757c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    void setEntranceTransitionStartState() {
1758c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(false);
1759c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setSearchOrbViewOnScreen(false);
176089097f67f988ebba714a95e10369665280db0c27Dake Gu        // NOTE that mMainFragmentAdapter.setEntranceTransitionState(false) will be called
176189097f67f988ebba714a95e10369665280db0c27Dake Gu        // in onEntranceTransitionPrepare() because mMainFragmentAdapter is still the dummy
176289097f67f988ebba714a95e10369665280db0c27Dake Gu        // one when setEntranceTransitionStartState() is called.
1763c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1764c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
1765c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    void setEntranceTransitionEndState() {
1766c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(mShowingHeaders);
1767c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setSearchOrbViewOnScreen(true);
17681c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.setEntranceTransitionState(true);
1769c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1770a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1771dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
1772a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1773a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private final View mView;
1774a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private final Runnable mCallback;
1775a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private int mState;
1776fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private MainFragmentAdapter mainFragmentAdapter;
1777a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1778a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_INIT = 0;
1779a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_FIRST_DRAW = 1;
1780a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_SECOND_DRAW = 2;
1781a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1782fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
1783fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mView = view;
1784a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mCallback = callback;
1785a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mainFragmentAdapter = adapter;
1786a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1787a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1788a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        void execute() {
1789a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mView.getViewTreeObserver().addOnPreDrawListener(this);
1790a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mainFragmentAdapter.setExpand(false);
17912dda16536f0cc543f52abf53b18d6c1327031142Dake Gu            // always trigger onPreDraw even adapter setExpand() does nothing.
17922dda16536f0cc543f52abf53b18d6c1327031142Dake Gu            mView.invalidate();
1793a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mState = STATE_INIT;
1794a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1795a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1796a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        @Override
1797a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        public boolean onPreDraw() {
17982452cde3b8d7cbe62f6eb2fbcbcf9a02448d6891Dake Gu            if (getView() == null || getContext() == null) {
1799dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu                mView.getViewTreeObserver().removeOnPreDrawListener(this);
1800dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu                return true;
1801dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu            }
1802a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            if (mState == STATE_INIT) {
1803a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mainFragmentAdapter.setExpand(true);
18042dda16536f0cc543f52abf53b18d6c1327031142Dake Gu                // always trigger onPreDraw even adapter setExpand() does nothing.
18052dda16536f0cc543f52abf53b18d6c1327031142Dake Gu                mView.invalidate();
1806a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mState = STATE_FIRST_DRAW;
1807a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            } else if (mState == STATE_FIRST_DRAW) {
1808a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mCallback.run();
1809a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mView.getViewTreeObserver().removeOnPreDrawListener(this);
1810a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mState = STATE_SECOND_DRAW;
1811a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            }
1812a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            return false;
1813a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1814a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
181561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu}
1816