16193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu/* This file is auto-generated from BrowseFragment.java.  DO NOT MODIFY. */
26193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu
361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu/*
461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Copyright (C) 2014 The Android Open Source Project
561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * in compliance with the License. You may obtain a copy of the License at
861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
1061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu *
1161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
1261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
1461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * the License.
1561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu */
1661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gupackage android.support.v17.leanback.app;
1761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
182f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v4.app.Fragment;
192f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v4.app.FragmentManager;
202f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v4.app.FragmentManager.BackStackEntry;
21bb0a680c10b84b83833a59634373140f8bd0750csusnataimport android.support.v4.app.FragmentTransaction;
222f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.content.res.TypedArray;
232f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.graphics.Color;
242f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.graphics.Rect;
252f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.os.Bundle;
2670acb0c19be3831a2080e4f902324de16bfbf62eTor Norbyeimport android.support.annotation.ColorInt;
2761905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.R;
2861905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.transition.TransitionHelper;
2961905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.transition.TransitionListener;
3061905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.BrowseFrameLayout;
318ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Guimport android.support.v17.leanback.widget.InvisibleRowPresenter;
321c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnataimport android.support.v17.leanback.widget.ListRow;
332f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v17.leanback.widget.ObjectAdapter;
3461905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.OnItemViewClickedListener;
3561905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.OnItemViewSelectedListener;
361c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnataimport android.support.v17.leanback.widget.PageRow;
3761905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.Presenter;
3861905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.PresenterSelector;
392f5ebf3f6f7bb6a24856f389e369b247118ba119susnataimport android.support.v17.leanback.widget.Row;
408df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Guimport android.support.v17.leanback.widget.RowHeaderPresenter;
4161905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.RowPresenter;
42a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnataimport android.support.v17.leanback.widget.ScaleFrameLayout;
43a373804d10f93a9488adc35cf6ce44dce09b3778Dake Guimport android.support.v17.leanback.widget.TitleViewAdapter;
4461905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
458e3566285de4ac771d6188f62fe947e23d371a3dKris Giesingimport android.support.v4.view.ViewCompat;
46041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Guimport android.support.v7.widget.RecyclerView;
4761905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.util.Log;
4861905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.LayoutInflater;
4961905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.View;
5061905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.ViewGroup;
5161905b0b52c50018dcaebcd79699c39b8f28d622Dake Guimport android.view.ViewGroup.MarginLayoutParams;
52a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnataimport android.view.ViewTreeObserver;
5361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
54fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basakimport java.util.HashMap;
55fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basakimport java.util.Map;
56fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
57b3756c53c5be55e8c8a2f6e2cda264407be84881susnataimport static android.support.v7.widget.RecyclerView.NO_POSITION;
58b3756c53c5be55e8c8a2f6e2cda264407be84881susnata
5961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu/**
6061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * A fragment for creating Leanback browse screens. It is composed of a
6161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * RowsSupportFragment and a HeadersSupportFragment.
6261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
6361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * A BrowseSupportFragment renders the elements of its {@link ObjectAdapter} as a set
6461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * of rows in a vertical list. The elements in this adapter must be subclasses
6561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * of {@link Row}.
6661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
6761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * The HeadersSupportFragment can be set to be either shown or hidden by default, or
6861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * may be disabled entirely. See {@link #setHeadersState} for details.
6961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * <p>
7061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * By default the BrowseSupportFragment includes support for returning to the headers
7161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * when the user presses Back. For Activities that customize {@link
726193c12a1897723c87b41f4e304a8cd04deef2dcDake Gu * android.support.v4.app.FragmentActivity#onBackPressed()}, you must disable this default Back key support by
7361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
7461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * use {@link BrowseSupportFragment.BrowseTransitionListener} and
7561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu * {@link #startHeadersTransition(boolean)}.
76a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * <p>
77a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * The recommended theme to use with a BrowseSupportFragment is
78a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
79a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * </p>
8061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu */
813f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gupublic class BrowseSupportFragment extends BaseSupportFragment {
8261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
8361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // BUNDLE attribute for saving header show/hide status when backstack is used:
8461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    static final String HEADER_STACK_INDEX = "headerStackIndex";
8561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // BUNDLE attribute for saving header show/hide status when backstack is not used:
8661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    static final String HEADER_SHOW = "headerShow";
87fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private static final String IS_PAGE_ROW = "isPageRow";
88fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
89e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout
9061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
9161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        int mLastEntryCount;
9261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        int mIndexOfHeadersBackStack;
9361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
9461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        BackStackListener() {
9561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
9661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mIndexOfHeadersBackStack = -1;
9761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
9861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
9961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        void load(Bundle savedInstanceState) {
10061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (savedInstanceState != null) {
10161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
10261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mShowingHeaders = mIndexOfHeadersBackStack == -1;
10361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else {
10461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (!mShowingHeaders) {
10561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    getFragmentManager().beginTransaction()
10661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            .addToBackStack(mWithHeadersBackStackName).commit();
10761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
10861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
10961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
11061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
11161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        void save(Bundle outState) {
11261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
11361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
11461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
11561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
11661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
11761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onBackStackChanged() {
11861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (getFragmentManager() == null) {
11961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
12061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return;
12161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
12261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            int count = getFragmentManager().getBackStackEntryCount();
12361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // if backstack is growing and last pushed entry is "headers" backstack,
12461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // remember the index of the entry.
12561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (count > mLastEntryCount) {
12661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
12761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mWithHeadersBackStackName.equals(entry.getName())) {
12861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mIndexOfHeadersBackStack = count - 1;
12961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
13061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else if (count < mLastEntryCount) {
13161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                // if popped "headers" backstack, initiate the show header transition if needed
13261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mIndexOfHeadersBackStack >= count) {
13369381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                    if (!isHeadersDataReady()) {
134b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                        // if main fragment was restored first before BrowseSupportFragment's adapter gets
135b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                        // restored: don't start header transition, but add the entry back.
13669381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                        getFragmentManager().beginTransaction()
13769381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                                .addToBackStack(mWithHeadersBackStackName).commit();
13869381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                        return;
13969381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                    }
14061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mIndexOfHeadersBackStack = -1;
14161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    if (!mShowingHeaders) {
14261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        startHeadersTransitionInternal(true);
14361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
14461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
14561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
14661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mLastEntryCount = count;
14761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
14861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
14961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
15061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
15161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Listener for transitions between browse headers and rows.
15261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
15361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static class BrowseTransitionListener {
15461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        /**
15561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * Callback when headers transition starts.
15661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *
15761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * @param withHeaders True if the transition will result in headers
15861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *        being shown, false otherwise.
15961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         */
16061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onHeadersTransitionStart(boolean withHeaders) {
16161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
16261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        /**
16361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * Callback when headers transition stops.
16461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *
16561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         * @param withHeaders True if the transition will result in headers
16661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         *        being shown, false otherwise.
16761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu         */
16861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onHeadersTransitionStop(boolean withHeaders) {
16961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
17061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
17161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
172aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    private class SetSelectionRunnable implements Runnable {
173aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_INVALID = -1;
174aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_INTERNAL_SYNC = 0;
175aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        static final int TYPE_USER_REQUEST = 1;
176aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
177aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private int mPosition;
178aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private int mType;
179aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private boolean mSmooth;
180aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
181aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        SetSelectionRunnable() {
182aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            reset();
183aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
184aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
185aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        void post(int position, int type, boolean smooth) {
186aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // Posting the set selection, rather than calling it immediately, prevents an issue
187aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // with adapter changes.  Example: a row is added before the current selected row;
188aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // first the fast lane view updates its selection, then the rows fragment has that
189aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // new selection propagated immediately; THEN the rows view processes the same adapter
190aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            // change and moves the selection again.
191aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            if (type >= mType) {
192aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mPosition = position;
193aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mType = type;
194aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mSmooth = smooth;
195aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mBrowseFrame.removeCallbacks(this);
196aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                mBrowseFrame.post(this);
197aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            }
198aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
199aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
200aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        @Override
201aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        public void run() {
202aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            setSelection(mPosition, mSmooth);
203aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            reset();
204aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
205aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
206aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        private void reset() {
207aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mPosition = -1;
208aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mType = TYPE_INVALID;
209aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mSmooth = false;
210aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        }
211aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    }
212aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout
2131c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    /**
214cabb8eca86d0248274f57008ff66427fec2e927csusnata     * Possible set of actions that {@link BrowseSupportFragment} exposes to clients. Custom
215cabb8eca86d0248274f57008ff66427fec2e927csusnata     * fragments can interact with {@link BrowseSupportFragment} using this interface.
216cabb8eca86d0248274f57008ff66427fec2e927csusnata     */
217cabb8eca86d0248274f57008ff66427fec2e927csusnata    public interface FragmentHost {
218cabb8eca86d0248274f57008ff66427fec2e927csusnata        /**
219a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Fragments are required to invoke this callback once their view is created
220a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * inside {@link Fragment#onViewCreated} method. {@link BrowseSupportFragment} starts the entrance
221cabb8eca86d0248274f57008ff66427fec2e927csusnata         * animation only after receiving this callback. Failure to invoke this method
222cabb8eca86d0248274f57008ff66427fec2e927csusnata         * will lead to fragment not showing up.
223cabb8eca86d0248274f57008ff66427fec2e927csusnata         *
224cabb8eca86d0248274f57008ff66427fec2e927csusnata         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
225cabb8eca86d0248274f57008ff66427fec2e927csusnata         */
226cabb8eca86d0248274f57008ff66427fec2e927csusnata        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
2276fd4441435b14669deced90a05097dd5fe459acesusnata
2286fd4441435b14669deced90a05097dd5fe459acesusnata        /**
229a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
230a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * is created for transition, the entrance animation only after receiving this callback.
231a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * Failure to invoke this method will lead to fragment not showing up.
232a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         *
233a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
234a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu         */
235a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
236a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
237a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        /**
238a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * Show or hide title view in {@link BrowseSupportFragment} for fragments mapped to
239a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseSupportFragment is fully
240a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * in control of showing/hiding title view.
241a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * <p>
242a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * When HeadersSupportFragment is visible, BrowseSupportFragment will hide search affordance view if
243a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu         * there are other focusable rows above currently focused row.
2446fd4441435b14669deced90a05097dd5fe459acesusnata         *
2456fd4441435b14669deced90a05097dd5fe459acesusnata         * @param show Boolean indicating whether or not to show the title view.
2466fd4441435b14669deced90a05097dd5fe459acesusnata         */
2476fd4441435b14669deced90a05097dd5fe459acesusnata        void showTitleView(boolean show);
248cabb8eca86d0248274f57008ff66427fec2e927csusnata    }
249cabb8eca86d0248274f57008ff66427fec2e927csusnata
250cabb8eca86d0248274f57008ff66427fec2e927csusnata    /**
251cabb8eca86d0248274f57008ff66427fec2e927csusnata     * Default implementation of {@link FragmentHost} that is used only by
252cabb8eca86d0248274f57008ff66427fec2e927csusnata     * {@link BrowseSupportFragment}.
253cabb8eca86d0248274f57008ff66427fec2e927csusnata     */
254cabb8eca86d0248274f57008ff66427fec2e927csusnata    private final class FragmentHostImpl implements FragmentHost {
2557350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        boolean mShowTitleView = true;
256a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        boolean mDataReady = false;
257cabb8eca86d0248274f57008ff66427fec2e927csusnata
25899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        FragmentHostImpl() {
25999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        }
26099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas
261cabb8eca86d0248274f57008ff66427fec2e927csusnata        @Override
262cabb8eca86d0248274f57008ff66427fec2e927csusnata        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
263a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            performPendingStates();
264a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        }
265a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
266a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        @Override
267a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
268a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            mDataReady = true;
269a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
270a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
271a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // ignore the request.
272a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
273a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu                return;
274a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            }
275a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
276a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            // We only honor showTitle request for PageRows.
277a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            if (!mIsPageRow) {
278a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu                return;
279a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            }
280a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu
281a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            performPendingStates();
282cabb8eca86d0248274f57008ff66427fec2e927csusnata        }
2836fd4441435b14669deced90a05097dd5fe459acesusnata
2846fd4441435b14669deced90a05097dd5fe459acesusnata        @Override
2856fd4441435b14669deced90a05097dd5fe459acesusnata        public void showTitleView(boolean show) {
2867350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata            mShowTitleView = show;
287d0fc2e48059f718676a531af06a31849f54c1ca9susnata
288d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
289d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // ignore the request.
290d0fc2e48059f718676a531af06a31849f54c1ca9susnata            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
291d0fc2e48059f718676a531af06a31849f54c1ca9susnata                return;
292b10ba3b01290ce801180a3d5dc992825af8cb3absusnata            }
293d0fc2e48059f718676a531af06a31849f54c1ca9susnata
294d0fc2e48059f718676a531af06a31849f54c1ca9susnata            // We only honor showTitle request for PageRows.
295d0fc2e48059f718676a531af06a31849f54c1ca9susnata            if (!mIsPageRow) {
296d0fc2e48059f718676a531af06a31849f54c1ca9susnata                return;
297d0fc2e48059f718676a531af06a31849f54c1ca9susnata            }
298d0fc2e48059f718676a531af06a31849f54c1ca9susnata
2998ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            updateTitleViewVisibility();
3006fd4441435b14669deced90a05097dd5fe459acesusnata        }
301cabb8eca86d0248274f57008ff66427fec2e927csusnata    }
302cabb8eca86d0248274f57008ff66427fec2e927csusnata
303cabb8eca86d0248274f57008ff66427fec2e927csusnata    /**
3041c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * Interface that defines the interaction between {@link BrowseSupportFragment} and it's main
305fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
3061c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * it will be used to get the fragment to be shown in the content section. Clients can
3071c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * provide any implementation of fragment and customize it's interaction with
3081c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * {@link BrowseSupportFragment} by overriding the necessary methods.
3091c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
3101c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * <p>
3111c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * Clients are expected to provide
312fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
313fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * implementations of {@link MainFragmentAdapter} for given content types. Currently
3141c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
3151c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
316fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsSupportFragment.MainFragmentAdapter}.
3171c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
3181c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * <p>
3191c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
320fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
321fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * and provide that through {@link MainFragmentAdapterRegistry}.
322fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link MainFragmentAdapter} implementation can supply any fragment and override
3231c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * just those interactions that makes sense.
3241c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     */
325fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class MainFragmentAdapter<T extends Fragment> {
326f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        private boolean mScalingEnabled;
327fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private final T mFragment;
32899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        FragmentHostImpl mFragmentHost;
329fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
330fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public MainFragmentAdapter(T fragment) {
331fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            this.mFragment = fragment;
332fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
333fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
334fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public final T getFragment() {
335fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return mFragment;
336fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
3372f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3382f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3392f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Returns whether its scrolling.
3402f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3411c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public boolean isScrolling() {
3421c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return false;
3431c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3442f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3452f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3462f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Set the visibility of titles/hovercard of browse rows.
3472f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3481c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setExpand(boolean expand) {
3491c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3502f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3512f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3522f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * For rows that willing to participate entrance transition,  this function
3532f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * hide views if afterTransition is true,  show views if afterTransition is false.
3542f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3551c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setEntranceTransitionState(boolean state) {
3561c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3572f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3582f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3592f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Sets the window alignment and also the pivots for scale operation.
3602f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3611c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void setAlignment(int windowAlignOffsetFromTop) {
3621c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3632f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3642f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3652f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition prepare start.
3662f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3671c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public boolean onTransitionPrepare() {
3681c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return false;
3691c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3702f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3712f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3722f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition start.
3732f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3741c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void onTransitionStart() {
3751c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
3762f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
3772f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        /**
3782f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         * Callback indicating transition end.
3792f5ebf3f6f7bb6a24856f389e369b247118ba119susnata         */
3801c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        public void onTransitionEnd() {
3811c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
382f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
383f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        /**
384f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         * Returns whether row scaling is enabled.
385f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         */
386f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        public boolean isScalingEnabled() {
387f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            return mScalingEnabled;
388f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        }
389f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
390f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        /**
391f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         * Sets the row scaling property.
392f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata         */
393f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        public void setScalingEnabled(boolean scalingEnabled) {
394f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            this.mScalingEnabled = scalingEnabled;
395f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        }
396cabb8eca86d0248274f57008ff66427fec2e927csusnata
3977350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        /**
3987350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         * Returns the current host interface so that main fragment can interact with
3997350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         * {@link BrowseSupportFragment}.
4007350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata         */
401cabb8eca86d0248274f57008ff66427fec2e927csusnata        public final FragmentHost getFragmentHost() {
402cabb8eca86d0248274f57008ff66427fec2e927csusnata            return mFragmentHost;
403cabb8eca86d0248274f57008ff66427fec2e927csusnata        }
4047350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
4057350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        void setFragmentHost(FragmentHostImpl fragmentHost) {
4067350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata            this.mFragmentHost = fragmentHost;
4077350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata        }
4082f5ebf3f6f7bb6a24856f389e369b247118ba119susnata    }
4092f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
4101c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    /**
411d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * Interface to be implemented by all fragments for providing an instance of
412d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * {@link MainFragmentAdapter}. Both {@link RowsSupportFragment} and custom fragment provided
413d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * against {@link PageRow} will need to implement this interface.
414d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     */
415d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    public interface MainFragmentAdapterProvider {
416d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        /**
417d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseSupportFragment}
418d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * would use to communicate with the target fragment.
419d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         */
420d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        MainFragmentAdapter getMainFragmentAdapter();
421d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    }
422d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
423d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    /**
424d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * Interface to be implemented by {@link RowsSupportFragment} and it's subclasses for providing
425d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * an instance of {@link MainFragmentRowsAdapter}.
426d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     */
427d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    public interface MainFragmentRowsAdapterProvider {
428d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        /**
429d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseSupportFragment}
430d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         * would use to communicate with the target fragment.
431d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata         */
432d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
433d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    }
434d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
435d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata    /**
436d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * This is used to pass information to {@link RowsSupportFragment} or its subclasses.
437d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * {@link BrowseSupportFragment} uses this interface to pass row based interaction events to
438d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata     * the target fragment.
4391c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     */
440fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class MainFragmentRowsAdapter<T extends Fragment> {
441fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private final T mFragment;
442fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
443fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public MainFragmentRowsAdapter(T fragment) {
444fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (fragment == null) {
445fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                throw new IllegalArgumentException("Fragment can't be null");
446fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
447fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            this.mFragment = fragment;
448fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
449fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
450fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public final T getFragment() {
451fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return mFragment;
452fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
453a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
454a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Set the visibility titles/hover of browse rows.
455a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
456a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setAdapter(ObjectAdapter adapter) {
457a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
4581c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
459a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
460a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Sets an item clicked listener on the fragment.
461a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
462a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
463a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
464a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
465a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
466a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Sets an item selection listener.
467a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
468a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
469a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
470a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
471a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
472a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Selects a Row and perform an optional task on the Row.
473a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
474a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setSelectedPosition(int rowPosition,
475a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata                                        boolean smooth,
476a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata                                        final Presenter.ViewHolderTask rowHolderTask) {
477a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
478a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
479a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
480a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Selects a Row.
481a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
482a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public void setSelectedPosition(int rowPosition, boolean smooth) {
483a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
484a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
485a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        /**
486a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         * Returns the selected position.
487a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata         */
488a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        public int getSelectedPosition() {
489a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            return 0;
490a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
491a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    }
4921c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
493a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    private boolean createMainFragment(ObjectAdapter adapter, int position) {
494a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        Object item = null;
495a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        if (adapter == null || adapter.size() == 0) {
496fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return false;
497a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        } else {
498bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (position < 0) {
499bb0a680c10b84b83833a59634373140f8bd0750csusnata                position = 0;
500bb0a680c10b84b83833a59634373140f8bd0750csusnata            } else if (position >= adapter.size()) {
5011c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                throw new IllegalArgumentException(
5021c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                        String.format("Invalid position %d requested", position));
5031c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            }
504a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            item = adapter.get(position);
505a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
5061c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
507a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        mSelectedPosition = position;
508fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        boolean oldIsPageRow = mIsPageRow;
509fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mIsPageRow = item instanceof PageRow;
510fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        boolean swap;
511fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
512fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragment == null) {
513fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            swap = true;
514a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        } else {
515fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (oldIsPageRow) {
516fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                swap = true;
517fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
518fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                swap = mIsPageRow;
519fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
5201c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
521fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
522fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (swap) {
523fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
524d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
525d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                throw new IllegalArgumentException(
526d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                        "Fragment must implement MainFragmentAdapterProvider");
527d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            }
528d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
529d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            mMainFragmentAdapter = ((MainFragmentAdapterProvider)mMainFragment)
530d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    .getMainFragmentAdapter();
531cabb8eca86d0248274f57008ff66427fec2e927csusnata            mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
532fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (!mIsPageRow) {
533d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
534d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = ((MainFragmentRowsAdapterProvider)mMainFragment)
535d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                            .getMainFragmentRowsAdapter();
536d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                } else {
537d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = null;
538d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                }
539fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mIsPageRow = mMainFragmentRowsAdapter == null;
540fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
541fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mMainFragmentRowsAdapter = null;
542fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
543fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
544d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata
545fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        return swap;
546a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    }
547a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata
548a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata    /**
549fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * Factory class responsible for creating fragment given the current item. {@link ListRow}
550fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * should returns {@link RowsSupportFragment} or it's subclass whereas {@link PageRow}
551fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * can return any fragment class.
552a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata     */
553fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public abstract static class FragmentFactory<T extends Fragment> {
554fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public abstract T createFragment(Object row);
555fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
5561c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
557fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    /**
558fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * FragmentFactory implementation for {@link ListRow}.
559fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     */
560fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public static class ListRowFragmentFactory extends FragmentFactory<RowsSupportFragment> {
561fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        @Override
562fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public RowsSupportFragment createFragment(Object row) {
563fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            return new RowsSupportFragment();
56480a1d2dfbe5c1f26370cc1753c3ae321f126f5d2Carlos Valdivia        }
565fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
5664400ca12ff731a7392715bc3d8ad3539b4c37889susnata
567fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    /**
568fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
569fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
570fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * handling {@link ListRow}. Developers can override that and also if they want to
571fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * use custom fragment, they can register a custom {@link FragmentFactory}
572fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * against {@link PageRow}.
573fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     */
574fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public final static class MainFragmentAdapterRegistry {
575cfcb31c4895793dda843faf67d1b769268e3cce8susnata        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap();
576cfcb31c4895793dda843faf67d1b769268e3cce8susnata        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
577cfcb31c4895793dda843faf67d1b769268e3cce8susnata
578cfcb31c4895793dda843faf67d1b769268e3cce8susnata        public MainFragmentAdapterRegistry() {
579cfcb31c4895793dda843faf67d1b769268e3cce8susnata            registerFragment(ListRow.class, sDefaultFragmentFactory);
580cfcb31c4895793dda843faf67d1b769268e3cce8susnata        }
581fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
582fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public void registerFragment(Class rowClass, FragmentFactory factory) {
583cfcb31c4895793dda843faf67d1b769268e3cce8susnata            mItemToFragmentFactoryMapping.put(rowClass, factory);
584fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        }
585fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
586fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        public Fragment createFragment(Object item) {
587fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (item == null) {
588fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                throw new IllegalArgumentException("Item can't be null");
589fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
590fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
591cfcb31c4895793dda843faf67d1b769268e3cce8susnata            FragmentFactory fragmentFactory = mItemToFragmentFactoryMapping.get(item.getClass());
592cfcb31c4895793dda843faf67d1b769268e3cce8susnata            if (fragmentFactory == null && !(item instanceof PageRow)) {
593cfcb31c4895793dda843faf67d1b769268e3cce8susnata                fragmentFactory = sDefaultFragmentFactory;
594cfcb31c4895793dda843faf67d1b769268e3cce8susnata            }
595cfcb31c4895793dda843faf67d1b769268e3cce8susnata
596cfcb31c4895793dda843faf67d1b769268e3cce8susnata            return fragmentFactory.createFragment(item);
597a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
5981c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
5992f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
60099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final String TAG = "BrowseSupportFragment";
60161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
60261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
60361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
60499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static boolean DEBUG = false;
60561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
60661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is enabled and shown by default. */
60761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_ENABLED = 1;
60861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
60961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is enabled and hidden by default. */
61061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_HIDDEN = 2;
61161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
61261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /** The headers fragment is disabled and will never be shown. */
61361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static final int HEADERS_DISABLED = 3;
61461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
615fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry
616fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            = new MainFragmentAdapterRegistry();
61799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    MainFragmentAdapter mMainFragmentAdapter;
61899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Fragment mMainFragment;
61999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    HeadersSupportFragment mHeadersSupportFragment;
620fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    private MainFragmentRowsAdapter mMainFragmentRowsAdapter;
62161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
62261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private ObjectAdapter mAdapter;
6238ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private PresenterSelector mAdapterPresenter;
6248ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private PresenterSelector mWrappingPresenterSelector;
62561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
62661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mHeadersState = HEADERS_ENABLED;
62761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mBrandColor = Color.TRANSPARENT;
62861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private boolean mBrandColorSet;
62961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
63099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BrowseFrameLayout mBrowseFrame;
631a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private ScaleFrameLayout mScaleFrameLayout;
63299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mHeadersBackStackEnabled = true;
63399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    String mWithHeadersBackStackName;
63499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mShowingHeaders = true;
63599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mCanShowHeaders = true;
6368e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing    private int mContainerListMarginStart;
63761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private int mContainerListAlignTop;
638f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    private boolean mMainFragmentScaleEnabled = true;
63999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
64061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private OnItemViewClickedListener mOnItemViewClickedListener;
641bb0a680c10b84b83833a59634373140f8bd0750csusnata    private int mSelectedPosition = -1;
642f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    private float mScaleFactor;
64399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean mIsPageRow;
64461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
64561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private PresenterSelector mHeaderPresenterSelector;
646aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
64761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
64861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    // transition related:
64999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mSceneWithHeaders;
65099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mSceneWithoutHeaders;
651c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    private Object mSceneAfterEntranceTransition;
65299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Object mHeadersTransition;
65399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BackStackListener mBackStackChangedListener;
65499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    BrowseTransitionListener mBrowseTransitionListener;
65561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
65661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String ARG_TITLE = BrowseSupportFragment.class.getCanonicalName() + ".title";
65761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private static final String ARG_HEADERS_STATE =
65861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        BrowseSupportFragment.class.getCanonicalName() + ".headersState";
65961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
66061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
661a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Creates arguments for a browse fragment.
66261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
66361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param args The Bundle to place arguments into, or null if the method
66461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        should return a new Bundle.
66561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param title The title of the BrowseSupportFragment.
66661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headersState The initial state of the headers of the
66761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        BrowseSupportFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
66861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
66961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @return A Bundle with the given arguments for creating a BrowseSupportFragment.
67061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
67161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public static Bundle createArgs(Bundle args, String title, int headersState) {
67261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args == null) {
67361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            args = new Bundle();
67461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
67561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        args.putString(ARG_TITLE, title);
67661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        args.putInt(ARG_HEADERS_STATE, headersState);
67761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return args;
67861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
67961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
68061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
68161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the brand color for the browse fragment. The brand color is used as
68261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * the primary color for UI elements in the browse fragment. For example,
68361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * the background color of the headers fragment uses the brand color.
68461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
68561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param color The color to use as the brand color of the fragment.
68661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
68770acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setBrandColor(@ColorInt int color) {
68861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrandColor = color;
68961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrandColorSet = true;
69061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
69161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeadersSupportFragment != null) {
69261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
69361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
69461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
69561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
69661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
69761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the brand color for the browse fragment.
69861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * The default is transparent.
69961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
70070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
70161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public int getBrandColor() {
70261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mBrandColor;
70361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
70461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
70561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
7068ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
7078ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * DividerRow and PageRow.
7088ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     */
7098ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private void createAndSetWrapperPresenter() {
7108ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
7118ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (adapterPresenter == null) {
7128ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
7138ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
7148ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (adapterPresenter == mAdapterPresenter) {
7158ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return;
7168ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
7178ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAdapterPresenter = adapterPresenter;
7188ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
7198ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        Presenter[] presenters = adapterPresenter.getPresenters();
7208ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
7218ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
7228ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
7238ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
7248ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAdapter.setPresenterSelector(new PresenterSelector() {
7258ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            @Override
7268ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            public Presenter getPresenter(Object item) {
7278ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                Row row = (Row) item;
7288ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                if (row.isRenderedAsRowView()) {
7298ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                    return adapterPresenter.getPresenter(item);
7308ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                } else {
7318ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                    return invisibleRowPresenter;
7328ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                }
7338ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
7348ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
7358ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            @Override
7368ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            public Presenter[] getPresenters() {
7378ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return allPresenters;
7388ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
7398ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        });
7408ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
7418ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
7428ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    /**
74361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the adapter containing the rows for the fragment.
74461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
74561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>The items referenced by the adapter must be be derived from
74661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link Row}. These rows will be used by the rows fragment and the headers
74761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * fragment (if not disabled) to render the browse rows.
74861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
74961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param adapter An ObjectAdapter for the browse rows. All items must
75061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        derive from {@link Row}.
75161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
75261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setAdapter(ObjectAdapter adapter) {
75361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mAdapter = adapter;
7548ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        createAndSetWrapperPresenter();
755c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu        if (getView() == null) {
756c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu            return;
757c0ad3d1d9ee64cf0bdb68ac70bfb04cc919c53e6Dake Gu        }
758bb0a680c10b84b83833a59634373140f8bd0750csusnata        replaceMainFragment(mSelectedPosition);
759bb0a680c10b84b83833a59634373140f8bd0750csusnata
760bb0a680c10b84b83833a59634373140f8bd0750csusnata        if (adapter != null) {
761bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (mMainFragmentRowsAdapter != null) {
762b3756c53c5be55e8c8a2f6e2cda264407be84881susnata                mMainFragmentRowsAdapter.setAdapter(new ListRowDataAdapter(adapter));
763bb0a680c10b84b83833a59634373140f8bd0750csusnata            }
76461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setAdapter(adapter);
76561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
76661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
76761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
768fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
769fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        return mMainFragmentAdapterRegistry;
7701c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
771fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
77261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
77361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the adapter containing the rows for the fragment.
77461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
77561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public ObjectAdapter getAdapter() {
77661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mAdapter;
77761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
77861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
77961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
78061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets an item selection listener.
78161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
78261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
78361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mExternalOnItemViewSelectedListener = listener;
78461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
78561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
78661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
78761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns an item selection listener.
78861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
78961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
79061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mExternalOnItemViewSelectedListener;
79161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
79261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
79361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
7941c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * Get RowsSupportFragment if it's bound to BrowseSupportFragment or null if either BrowseSupportFragment has
7951c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * not been created yet or a different fragment is bound to it.
7961c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     *
7971c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata     * @return RowsSupportFragment if it's bound to BrowseSupportFragment or null otherwise.
7980d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
7990d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public RowsSupportFragment getRowsSupportFragment() {
8001c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        if (mMainFragment instanceof RowsSupportFragment) {
8011c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return (RowsSupportFragment) mMainFragment;
8021c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
8031c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
8041c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        return null;
8050d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
8060d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
8070d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
8080d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Get currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
8090d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @return Currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
8100d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
8110d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public HeadersSupportFragment getHeadersSupportFragment() {
8120d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        return mHeadersSupportFragment;
8130d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
8140d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
8150d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
81661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets an item clicked listener on the fragment.
81761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * OnItemViewClickedListener will override {@link View.OnClickListener} that
81861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
819cabb8eca86d0248274f57008ff66427fec2e927csusnata     * So in general, developer should choose one of the listeners but not both.
82061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
82161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
82261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mOnItemViewClickedListener = listener;
8232aff8659c7362b48f099a13ffad390bf7984dd5aJaewan Kim        if (mMainFragmentRowsAdapter != null) {
824fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
82561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
82661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
82761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
82861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
82961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the item Clicked listener.
83061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
83161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public OnItemViewClickedListener getOnItemViewClickedListener() {
83261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mOnItemViewClickedListener;
83361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
83461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
83561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
836a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Starts a headers transition.
83761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
83861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>This method will begin a transition to either show or hide the
83961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * headers, depending on the value of withHeaders. If headers are disabled
84061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * for this browse fragment, this method will throw an exception.
84161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
84261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param withHeaders True if the headers should transition to being shown,
84361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        false if the transition should result in headers being hidden.
84461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
84561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void startHeadersTransition(boolean withHeaders) {
84661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (!mCanShowHeaders) {
84761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            throw new IllegalStateException("Cannot start headers transition");
84861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
84961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
85061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
85161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
85261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        startHeadersTransitionInternal(withHeaders);
85361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
85461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
85561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
85661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if the headers transition is currently running.
85761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
85861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public boolean isInHeadersTransition() {
85961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersTransition != null;
86061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
86161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
86261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
86361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if headers are shown.
86461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
86561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public boolean isShowingHeaders() {
86661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mShowingHeaders;
86761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
86861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
86961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
870a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets a listener for browse fragment transitions.
87161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
87261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param listener The listener to call when a browse headers transition
87361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        begins or ends.
87461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
87561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
87661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseTransitionListener = listener;
87761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
87861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
87961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
880f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * @deprecated use {@link BrowseSupportFragment#enableMainFragmentScaling(boolean)} instead.
88161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
88261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param enable true to enable row scaling
88361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
884d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    @Deprecated
88561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void enableRowScaling(boolean enable) {
886f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        enableMainFragmentScaling(enable);
887f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    }
888f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata
889f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    /**
890f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * Enables scaling of main fragment when headers are present. For the page/row fragment,
891f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * scaling is enabled only when both this method and
892fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
893f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     *
894f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     * @param enable true to enable row scaling
895f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata     */
896f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata    public void enableMainFragmentScaling(boolean enable) {
897f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        mMainFragmentScaleEnabled = enable;
89861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
89961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
90099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void startHeadersTransitionInternal(final boolean withHeaders) {
90161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (getFragmentManager().isDestroyed()) {
90261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
90361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
90469381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        if (!isHeadersDataReady()) {
90569381509eace8e71ba4886e9e1e78cda62b66516Dake Gu            return;
90669381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        }
90761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mShowingHeaders = withHeaders;
9081c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionPrepare();
9091c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionStart();
910a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        onExpandTransitionStart(!withHeaders, new Runnable() {
91161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
91261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
913902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu                mHeadersSupportFragment.onTransitionPrepare();
91461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersSupportFragment.onTransitionStart();
91561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                createHeadersTransition();
91661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mBrowseTransitionListener != null) {
91761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
91861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
9191c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                TransitionHelper.runTransition(
9201c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
92161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mHeadersBackStackEnabled) {
92261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    if (!withHeaders) {
92361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        getFragmentManager().beginTransaction()
92461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                                .addToBackStack(mWithHeadersBackStackName).commit();
92561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    } else {
92661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
92761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        if (index >= 0) {
92861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
92961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                            getFragmentManager().popBackStackImmediate(entry.getId(),
93061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
93161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        }
93261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
93361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
93461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
93561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
93661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
93761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
9380d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    boolean isVerticalScrolling() {
93961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        // don't run transition
9401c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        return mHeadersSupportFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
94161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
94261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
943e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout
94461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
94561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            new BrowseFrameLayout.OnFocusSearchListener() {
94661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
94761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public View onFocusSearch(View focused, int direction) {
94861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // if headers is running transition,  focus stays
9495ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            if (mCanShowHeaders && isInHeadersTransition()) {
9505ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout                return focused;
9515ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            }
95261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
9535ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout
954e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            if (getTitleView() != null && focused != getTitleView() &&
955e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                    direction == View.FOCUS_UP) {
956e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                return getTitleView();
957e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            }
958e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            if (getTitleView() != null && getTitleView().hasFocus() &&
959e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                    direction == View.FOCUS_DOWN) {
9605ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout                return mCanShowHeaders && mShowingHeaders ?
9611c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                        mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
9625ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout            }
9635ae73b45620a3d535b2d279512d5d34603e2bdb1Craig Stout
9648e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            boolean isRtl = ViewCompat.getLayoutDirection(focused) == View.LAYOUT_DIRECTION_RTL;
9658e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
9668e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
967e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            if (mCanShowHeaders && direction == towardStart) {
96869381509eace8e71ba4886e9e1e78cda62b66516Dake Gu                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
96961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return focused;
97061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
97161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return mHeadersSupportFragment.getVerticalGridView();
9728e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing            } else if (direction == towardEnd) {
973e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                if (isVerticalScrolling()) {
97461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return focused;
975dc21f7e02936d3bf1f8e69137393814cefd9846aDake Gu                } else if (mMainFragment != null && mMainFragment.getView() != null) {
976dc21f7e02936d3bf1f8e69137393814cefd9846aDake Gu                    return mMainFragment.getView();
97761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
978dc21f7e02936d3bf1f8e69137393814cefd9846aDake Gu                return focused;
9798ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
9808ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // disable focus_down moving into PageFragment.
9818ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return focused;
98261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else {
98361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return null;
98461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
98561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
98661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
98761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
98899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    final boolean isHeadersDataReady() {
98969381509eace8e71ba4886e9e1e78cda62b66516Dake Gu        return mAdapter != null && mAdapter.size() != 0;
99069381509eace8e71ba4886e9e1e78cda62b66516Dake Gu    }
99169381509eace8e71ba4886e9e1e78cda62b66516Dake Gu
99261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
99361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            new BrowseFrameLayout.OnChildFocusListener() {
99461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
99561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
99661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
99728fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            if (getChildFragmentManager().isDestroyed()) {
99828fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu                return true;
99928fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            }
100061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            // Make sure not changing focus when requestFocus() is called.
100161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mCanShowHeaders && mShowingHeaders) {
10027fd35190a1f0fd92f1275324b23708b5a2087a76Craig Stout                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null &&
10037fd35190a1f0fd92f1275324b23708b5a2087a76Craig Stout                        mHeadersSupportFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
100461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return true;
100561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
100661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
10071c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            if (mMainFragment != null && mMainFragment.getView() != null &&
10081c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                    mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
100961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                return true;
101061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
1011e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            if (getTitleView() != null &&
1012e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                    getTitleView().requestFocus(direction, previouslyFocusedRect)) {
10137fd35190a1f0fd92f1275324b23708b5a2087a76Craig Stout                return true;
10147fd35190a1f0fd92f1275324b23708b5a2087a76Craig Stout            }
10157fd35190a1f0fd92f1275324b23708b5a2087a76Craig Stout            return false;
10161c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
101761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
101861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
101961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onRequestChildFocus(View child, View focused) {
102028fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            if (getChildFragmentManager().isDestroyed()) {
102128fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu                return;
102228fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            }
102361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (!mCanShowHeaders || isInHeadersTransition()) return;
102428fe4119471dcc0ccd752c331d6420fcf363f5a5Dake Gu            int childId = child.getId();
102561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (childId == R.id.browse_container_dock && mShowingHeaders) {
102661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(false);
102761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
102861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(true);
102961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
103061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
103161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
103261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
103361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
103461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onSaveInstanceState(Bundle outState) {
1035e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        super.onSaveInstanceState(outState);
1036fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
1037fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
1038fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
103961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBackStackChangedListener != null) {
104061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mBackStackChangedListener.save(outState);
104161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        } else {
104261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
104361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
104461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
104561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
104661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
104761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onCreate(Bundle savedInstanceState) {
104861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onCreate(savedInstanceState);
104961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        TypedArray ta = getActivity().obtainStyledAttributes(R.styleable.LeanbackTheme);
10508e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing        mContainerListMarginStart = (int) ta.getDimension(
105146443cb5b092f1d9156342645088eead9da026f6Dake Gu                R.styleable.LeanbackTheme_browseRowsMarginStart, getActivity().getResources()
105246443cb5b092f1d9156342645088eead9da026f6Dake Gu                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
105361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mContainerListAlignTop = (int) ta.getDimension(
105446443cb5b092f1d9156342645088eead9da026f6Dake Gu                R.styleable.LeanbackTheme_browseRowsMarginTop, getActivity().getResources()
105546443cb5b092f1d9156342645088eead9da026f6Dake Gu                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
105661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        ta.recycle();
105761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
105861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        readArguments(getArguments());
105961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
106034f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout        if (mCanShowHeaders) {
106134f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            if (mHeadersBackStackEnabled) {
106234f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
106334f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mBackStackChangedListener = new BackStackListener();
106434f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
106534f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                mBackStackChangedListener.load(savedInstanceState);
106634f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            } else {
106734f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                if (savedInstanceState != null) {
106834f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
106934f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout                }
107034f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout            }
107134f3ee7e818a20939ef49abf5509bcfaea5c3db0Craig Stout        }
1072a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1073f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
107461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
107561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
107661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
1077fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    public void onDestroyView() {
1078fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragmentRowsAdapter = null;
1079fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragmentAdapter = null;
1080fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mMainFragment = null;
1081fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        mHeadersSupportFragment = null;
1082fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        super.onDestroyView();
1083fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    }
1084fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
1085fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak    @Override
108661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onDestroy() {
108761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBackStackChangedListener != null) {
108861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
108961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
109061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onDestroy();
109161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
109261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
109361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
109461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public View onCreateView(LayoutInflater inflater, ViewGroup container,
109561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            Bundle savedInstanceState) {
10967350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
1097a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
109861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment = new HeadersSupportFragment();
1099bb0a680c10b84b83833a59634373140f8bd0750csusnata
1100a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata            createMainFragment(mAdapter, mSelectedPosition);
1101bb0a680c10b84b83833a59634373140f8bd0750csusnata            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
1102bb0a680c10b84b83833a59634373140f8bd0750csusnata                    .replace(R.id.browse_headers_dock, mHeadersSupportFragment);
1103bb0a680c10b84b83833a59634373140f8bd0750csusnata
1104bb0a680c10b84b83833a59634373140f8bd0750csusnata            if (mMainFragment != null) {
1105bb0a680c10b84b83833a59634373140f8bd0750csusnata                ft.replace(R.id.scale_frame, mMainFragment);
1106bb0a680c10b84b83833a59634373140f8bd0750csusnata            } else {
1107bb0a680c10b84b83833a59634373140f8bd0750csusnata                // Empty adapter used to guard against lazy adapter loading. When this
1108bb0a680c10b84b83833a59634373140f8bd0750csusnata                // fragment is instantiated, mAdapter might not have the data or might not
1109bb0a680c10b84b83833a59634373140f8bd0750csusnata                // have been set. In either of those cases mFragmentAdapter will be null.
1110bb0a680c10b84b83833a59634373140f8bd0750csusnata                // This way we can maintain the invariant that mMainFragmentAdapter is never
1111bb0a680c10b84b83833a59634373140f8bd0750csusnata                // null and it avoids doing null checks all over the code.
1112bb0a680c10b84b83833a59634373140f8bd0750csusnata                mMainFragmentAdapter = new MainFragmentAdapter(null);
1113cabb8eca86d0248274f57008ff66427fec2e927csusnata                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
1114bb0a680c10b84b83833a59634373140f8bd0750csusnata            }
1115bb0a680c10b84b83833a59634373140f8bd0750csusnata
1116bb0a680c10b84b83833a59634373140f8bd0750csusnata            ft.commit();
111761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        } else {
111861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment = (HeadersSupportFragment) getChildFragmentManager()
1119fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                    .findFragmentById(R.id.browse_headers_dock);
1120fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
1121d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata            mMainFragmentAdapter = ((MainFragmentAdapterProvider)mMainFragment)
1122d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    .getMainFragmentAdapter();
1123dc1492d3655550b7a9c861aae1bd538410c7324dDake Gu            mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
1124fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
1125fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mIsPageRow = savedInstanceState != null ?
1126fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                    savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
1127fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak
1128fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mSelectedPosition = savedInstanceState != null ?
1129fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                    savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
11307350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
1131fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            if (!mIsPageRow) {
1132d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
1133d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = ((MainFragmentRowsAdapterProvider) mMainFragment)
1134d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                            .getMainFragmentRowsAdapter();
1135d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                } else {
1136d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                    mMainFragmentRowsAdapter = null;
1137d78de5e10e8426beff2ec22a3e3e0967a6b3d557susnata                }
1138fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            } else {
1139fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak                mMainFragmentRowsAdapter = null;
1140fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            }
114161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
114261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
114361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
114461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeaderPresenterSelector != null) {
114561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
114661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
114761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setAdapter(mAdapter);
11488df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu        mHeadersSupportFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
114961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersSupportFragment.setOnHeaderClickedListener(mHeaderClickedListener);
11502f5ebf3f6f7bb6a24856f389e369b247118ba119susnata
115161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
115261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1153684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata        getProgressBarManager().setRootView((ViewGroup)root);
1154684f4a94f6f55b2abc5ed2677dfdfc9501dd6407susnata
115561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
115661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
1157e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
115861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1159a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu        installTitleView(inflater, mBrowseFrame, savedInstanceState);
1160a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu
1161a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
1162a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setPivotX(0);
1163a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
1164a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1165a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setupMainFragment();
1166a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
116761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mBrandColorSet) {
116861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
116961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
117061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
11718403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
117261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
117361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
117461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                showHeaders(true);
117561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
117661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
11778403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
117861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
117961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void run() {
118061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                showHeaders(false);
118161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
118261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
11838403619efebe94666c0615c3fc85080a303acf80Dake Gu        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
1184c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            @Override
1185c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            public void run() {
1186c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu                setEntranceTransitionEndState();
1187c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            }
1188c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        });
1189d0fc2e48059f718676a531af06a31849f54c1ca9susnata
119061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return root;
119161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
119261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
11931c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    private void setupMainFragment() {
1194fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentRowsAdapter != null) {
119535d7a6c31606ed4ca38deda3cacae080a95c95c9susnata            if (mAdapter != null) {
119635d7a6c31606ed4ca38deda3cacae080a95c95c9susnata                mMainFragmentRowsAdapter.setAdapter(new ListRowDataAdapter(mAdapter));
119735d7a6c31606ed4ca38deda3cacae080a95c95c9susnata            }
11983eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
11993eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
1200fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
1201a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
12021c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
12031c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
1204a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    @Override
1205a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    boolean isReadyForPrepareEntranceTransition() {
1206cabb8eca86d0248274f57008ff66427fec2e927csusnata        return mMainFragment != null && mMainFragment.getView() != null;
1207a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    }
1208a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
1209a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    @Override
1210a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    boolean isReadyForStartEntranceTransition() {
1211a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu        return mMainFragment != null && mMainFragment.getView() != null
1212a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu                && (!mIsPageRow || mMainFragmentAdapter.mFragmentHost.mDataReady);
1213a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu    }
1214a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu
121599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void createHeadersTransition() {
12168403619efebe94666c0615c3fc85080a303acf80Dake Gu        mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
12174735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                mShowingHeaders ?
12184735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu                R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
121961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
12208403619efebe94666c0615c3fc85080a303acf80Dake Gu        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
122161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
122261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void onTransitionStart(Object transition) {
122361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
122461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
122561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            public void onTransitionEnd(Object transition) {
122661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersTransition = null;
122754bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                if (mMainFragmentAdapter != null) {
122854bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    mMainFragmentAdapter.onTransitionEnd();
122954bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    if (!mShowingHeaders && mMainFragment != null) {
123054bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        View mainFragmentView = mMainFragment.getView();
123154bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
123254bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                            mainFragmentView.requestFocus();
123354bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        }
123461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
123554bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                }
123654bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                if (mHeadersSupportFragment != null) {
123754bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    mHeadersSupportFragment.onTransitionEnd();
123854bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                    if (mShowingHeaders) {
123954bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        VerticalGridView headerGridView = mHeadersSupportFragment.getVerticalGridView();
124054bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        if (headerGridView != null && !headerGridView.hasFocus()) {
124154bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                            headerGridView.requestFocus();
124254bab13ae9de4dd00002792bebf9531ede3c12e2Dake Gu                        }
124361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    }
1244d0fc2e48059f718676a531af06a31849f54c1ca9susnata                }
12456fd4441435b14669deced90a05097dd5fe459acesusnata
12467350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata                // Animate TitleView once header animation is complete.
12478ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                updateTitleViewVisibility();
1248d0fc2e48059f718676a531af06a31849f54c1ca9susnata
124961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (mBrowseTransitionListener != null) {
125061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
125161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
125261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
125361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        });
125461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
125561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
12568ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    void updateTitleViewVisibility() {
12578ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (!mShowingHeaders) {
12588ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showTitleView;
12598ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (mIsPageRow && mMainFragmentAdapter != null) {
12608ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // page fragment case:
12618ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
12628ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
12638ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                // regular row view case:
12648ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitleView = isFirstRowWithContent(mSelectedPosition);
12658ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
12668ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (showTitleView) {
1267a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
12688ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
12698ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(false);
12708ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
12718ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        } else {
12728ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
12738ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showBranding;
12748ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            boolean showSearch;
12758ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (mIsPageRow && mMainFragmentAdapter != null) {
12768ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
12778ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
12788ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showBranding = isFirstRowWithContent(mSelectedPosition);
12798ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
12808ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
12818ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            int flags = 0;
1282a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
1283a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
12848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (flags != 0) {
12858ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(flags);
12868ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            } else {
12878ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                showTitle(false);
12888ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
12898ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
12908ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
12918ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
12928ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
12938ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAdapter == null || mAdapter.size() == 0) {
12948ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return true;
12958ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
12968ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        for (int i = 0; i < mAdapter.size(); i++) {
12978ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            final Row row = (Row) mAdapter.get(i);
12988ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (row.isRenderedAsRowView() || row instanceof PageRow) {
12998ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return rowPosition == i;
13008ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13018ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13028ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        return true;
13038ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
13048ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
13058ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    boolean isFirstRowWithContent(int rowPosition) {
13068ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAdapter == null || mAdapter.size() == 0) {
13078ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            return true;
13088ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13098ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        for (int i = 0; i < mAdapter.size(); i++) {
13108ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            final Row row = (Row) mAdapter.get(i);
13118ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            if (row.isRenderedAsRowView()) {
13128ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                return rowPosition == i;
13138ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            }
13148ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
13158ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        return true;
13168ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
13178ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
131861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
131961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the {@link PresenterSelector} used to render the row headers.
132061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
132161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headerPresenterSelector The PresenterSelector that will determine
132261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *        the Presenter for each row header.
132361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
132461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
132561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeaderPresenterSelector = headerPresenterSelector;
132661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mHeadersSupportFragment != null) {
132761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
132861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
132961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
133061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1331c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    private void setHeadersOnScreen(boolean onScreen) {
1332c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        MarginLayoutParams lp;
1333c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        View containerList;
133461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        containerList = mHeadersSupportFragment.getView();
133561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        lp = (MarginLayoutParams) containerList.getLayoutParams();
13368e3566285de4ac771d6188f62fe947e23d371a3dKris Giesing        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
133761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        containerList.setLayoutParams(lp);
1338c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
133961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
134099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void showHeaders(boolean show) {
1341c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        if (DEBUG) Log.v(TAG, "showHeaders " + show);
1342c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        mHeadersSupportFragment.setHeadersEnabled(show);
1343c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(show);
1344a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        expandMainFragment(!show);
1345a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1346a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1347a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void expandMainFragment(boolean expand) {
1348a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
1349c1ec7d7eff002329b245a4edb1b87da2f3b5e006Dake Gu        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
1350a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setLayoutParams(params);
1351a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mMainFragmentAdapter.setExpand(expand);
1352a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1353a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setMainFragmentAlignment();
1354f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        final float scaleFactor = !expand
1355bb0a680c10b84b83833a59634373140f8bd0750csusnata                && mMainFragmentScaleEnabled
1356bb0a680c10b84b83833a59634373140f8bd0750csusnata                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
1357a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
1358a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mScaleFrameLayout.setChildScale(scaleFactor);
135961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
136061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
136161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private HeadersSupportFragment.OnHeaderClickedListener mHeaderClickedListener =
136261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        new HeadersSupportFragment.OnHeaderClickedListener() {
136361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            @Override
1364729cbf4cd57c87bcd569db5974c8cbd51a942581Dake Gu            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
136561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
136661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    return;
136761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                }
136861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                startHeadersTransitionInternal(false);
13691c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata                mMainFragment.getView().requestFocus();
137061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
137161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        };
137261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
13733eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
13743eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
13753eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu
13763eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
13773eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            mMainFragmentRowsAdapter = fragmentRowsAdapter;
13783eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu        }
13793eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu
138061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
138161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
138261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                RowPresenter.ViewHolder rowViewHolder, Row row) {
13833eb709dbe85f06b69cf1b683a2c1fe7109a85a9aDake Gu            int position = mMainFragmentRowsAdapter.getSelectedPosition();
138461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "row selected position " + position);
138561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            onRowSelected(position);
138661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mExternalOnItemViewSelectedListener != null) {
138761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
138861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                        rowViewHolder, row);
138961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
139061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
139161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
139261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
13938df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu    private HeadersSupportFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
13948df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu            new HeadersSupportFragment.OnHeaderViewSelectedListener() {
139561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        @Override
13968df88a1ead9ea62456fc3bbda41657ccf61d5721Dake Gu        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
13970d841b3454f896da58deb506ca22730bfd04f34fDake Gu            int position = mHeadersSupportFragment.getSelectedPosition();
139861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (DEBUG) Log.v(TAG, "header selected position " + position);
139961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            onRowSelected(position);
140061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
140161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    };
140261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
140399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void onRowSelected(int position) {
140461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (position != mSelectedPosition) {
1405aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout            mSetSelectionRunnable.post(
1406aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                    position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
140761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
140861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
140961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
141099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void setSelection(int position, boolean smooth) {
14111c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        if (position == NO_POSITION) {
14121c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            return;
141361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
14141c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
14151c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mHeadersSupportFragment.setSelectedPosition(position, smooth);
1416bb0a680c10b84b83833a59634373140f8bd0750csusnata        replaceMainFragment(position);
1417bb0a680c10b84b83833a59634373140f8bd0750csusnata
1418bb0a680c10b84b83833a59634373140f8bd0750csusnata        if (mMainFragmentRowsAdapter != null) {
1419bb0a680c10b84b83833a59634373140f8bd0750csusnata            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
1420bb0a680c10b84b83833a59634373140f8bd0750csusnata        }
1421bb0a680c10b84b83833a59634373140f8bd0750csusnata        mSelectedPosition = position;
14227350fc450e5850b7a3dddff6d63fb87bd24886ddsusnata
14238ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        updateTitleViewVisibility();
1424bb0a680c10b84b83833a59634373140f8bd0750csusnata    }
14253faa5780307cf10ff0e4a1d89a9ba099cdad2e15susnata
1426bb0a680c10b84b83833a59634373140f8bd0750csusnata    private void replaceMainFragment(int position) {
1427a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        if (createMainFragment(mAdapter, position)) {
1428041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            swapToMainFragment();
1429a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
14301c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            setupMainFragment();
1431a471ba40d52cde2d5a0afeded68c9d915f76183bDake Gu            performPendingStates();
14321c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        }
143361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
143461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1435041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu    private void swapToMainFragment() {
1436041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        final VerticalGridView gridView = mHeadersSupportFragment.getVerticalGridView();
14373f19c1616ed2749a70ecc764dccb467ec96aa1f4Dake Gu        if (isShowingHeaders() && gridView != null
14383f19c1616ed2749a70ecc764dccb467ec96aa1f4Dake Gu                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
1439041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // if user is scrolling HeadersSupportFragment,  swap to empty fragment and wait scrolling
1440041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // finishes.
1441041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            getChildFragmentManager().beginTransaction()
1442041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    .replace(R.id.scale_frame, new Fragment()).commit();
1443041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            gridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
1444041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                @Override
1445041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1446041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
1447041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        gridView.removeOnScrollListener(this);
1448041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        FragmentManager fm = getChildFragmentManager();
1449041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
1450041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        if (currentFragment != mMainFragment) {
1451041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
1452041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                        }
1453041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    }
1454041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                }
1455041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            });
1456041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        } else {
1457041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            // Otherwise swap immediately
1458041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu            getChildFragmentManager().beginTransaction()
1459041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu                    .replace(R.id.scale_frame, mMainFragment).commit();
1460041a037dbeb68c17322e62e729ec5ece6c7f5b20Dake Gu        }
14611c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata    }
14621c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
14633f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
14643f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Sets the selected row position with smooth animation.
14653f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
14663f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setSelectedPosition(int position) {
14673f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        setSelectedPosition(position, true);
14683f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
14693f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
14703f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    /**
14710d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Gets position of currently selected row.
14720d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @return Position of currently selected row.
14730d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
14740d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public int getSelectedPosition() {
14750d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        return mSelectedPosition;
14760d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
14770d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
14780d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
14793f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     * Sets the selected row position.
14803f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu     */
14813f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setSelectedPosition(int position, boolean smooth) {
1482aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout        mSetSelectionRunnable.post(
1483aca6f4e4d28935fdc8f8d2a74cd41dc88c8b9e80Craig Stout                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
14843f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    }
14853f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu
14860d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    /**
14870d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * Selects a Row and perform an optional task on the Row. For example
14880d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
14890d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
14900d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * RowsSupportFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
14910d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * ViewGroup, Bundle)}).
14920d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     *
14930d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param rowPosition Which row to select.
14940d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param smooth True to scroll to the row, false for no animation.
14950d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
14960d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     * fragment will be collapsed.
14970d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu     */
14980d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    public void setSelectedPosition(int rowPosition, boolean smooth,
1499cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            final Presenter.ViewHolderTask rowHolderTask) {
1500fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentAdapterRegistry == null) {
15010d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu            return;
15020d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        }
15030d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        if (rowHolderTask != null) {
15040d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu            startHeadersTransition(false);
15050d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu        }
1506fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        if (mMainFragmentRowsAdapter != null) {
1507fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
1508a9cab85f79e3993c3d7c4f5e0246f8492bcc2a48susnata        }
15090d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu    }
15100d73d42df7cf4b325b8f49660e3326204915ce8fDake Gu
151161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    @Override
151261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void onStart() {
151361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        super.onStart();
15142f5ebf3f6f7bb6a24856f389e369b247118ba119susnata        mHeadersSupportFragment.setAlignment(mContainerListAlignTop);
1515a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        setMainFragmentAlignment();
151661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
151761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mCanShowHeaders && mShowingHeaders && mHeadersSupportFragment.getView() != null) {
151861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersSupportFragment.getView().requestFocus();
1519b3756c53c5be55e8c8a2f6e2cda264407be84881susnata        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment.getView() != null) {
15201c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata            mMainFragment.getView().requestFocus();
152161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
15221c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
152361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (mCanShowHeaders) {
152461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            showHeaders(mShowingHeaders);
152561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
15261c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata
15273f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        if (isEntranceTransitionEnabled()) {
1528c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu            setEntranceTransitionStartState();
1529c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        }
153061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
153161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
1532a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
1533a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        if (expand) {
1534a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            callback.run();
1535a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            return;
1536a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1537a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        // Run a "pre" layout when we go non-expand, in order to get the initial
1538a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        // positions of added rows.
1539fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
1540a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1541a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1542a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    private void setMainFragmentAlignment() {
1543a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        int alignOffset = mContainerListAlignTop;
1544f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata        if (mMainFragmentScaleEnabled
1545f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata                && mMainFragmentAdapter.isScalingEnabled()
1546f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata                && mShowingHeaders) {
1547f7a4099b29d7739616dd9d7e466b48dfda4b32f2susnata            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
1548a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1549a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        mMainFragmentAdapter.setAlignment(alignOffset);
1550a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
1551a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
155261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
1553a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Enables/disables headers transition on back key support. This is enabled by
155461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * default. The BrowseSupportFragment will add a back stack entry when headers are
155561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * showing. Running a headers transition when the back key is pressed only
155661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * works when the headers state is {@link #HEADERS_ENABLED} or
155761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link #HEADERS_HIDDEN}.
155861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * <p>
155961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * NOTE: If an Activity has its own onBackPressed() handling, you must
156061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
156161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * and {@link BrowseTransitionListener} in your own back stack handling.
156261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
156361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
156461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        mHeadersBackStackEnabled = headersBackStackEnabled;
156561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
156661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
156761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
156861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns true if headers transition on back key support is enabled.
156961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
157061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public final boolean isHeadersTransitionOnBackEnabled() {
157161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersBackStackEnabled;
157261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
157361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
157461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    private void readArguments(Bundle args) {
157561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args == null) {
157661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            return;
157761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
157861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args.containsKey(ARG_TITLE)) {
157961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            setTitle(args.getString(ARG_TITLE));
158061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
158161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (args.containsKey(ARG_HEADERS_STATE)) {
158261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            setHeadersState(args.getInt(ARG_HEADERS_STATE));
158361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
158461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
158561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
158661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
158761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Sets the state for the headers column in the browse fragment. Must be one
158861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
158961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * {@link #HEADERS_DISABLED}.
159061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     *
159161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * @param headersState The state of the headers for the browse fragment.
159261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
159361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public void setHeadersState(int headersState) {
159461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
159561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            throw new IllegalArgumentException("Invalid headers state: " + headersState);
159661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
159761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
159861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
159961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        if (headersState != mHeadersState) {
160061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            mHeadersState = headersState;
160161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            switch (headersState) {
160261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_ENABLED:
160361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = true;
160461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = true;
160561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
160661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_HIDDEN:
160761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = true;
160861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = false;
160961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
161061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                case HEADERS_DISABLED:
161161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mCanShowHeaders = false;
161261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    mShowingHeaders = false;
161361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
161461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                default:
161561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    Log.w(TAG, "Unknown headers state: " + headersState);
161661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                    break;
161761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
161861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            if (mHeadersSupportFragment != null) {
161961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu                mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
162061905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu            }
162161905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        }
162261905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
162361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu
162461905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    /**
162561905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     * Returns the state of the headers column in the browse fragment.
162661905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu     */
162761905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    public int getHeadersState() {
162861905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu        return mHeadersState;
162961905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu    }
1630c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
16313f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
16323f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected Object createEntranceTransition() {
16338403619efebe94666c0615c3fc85080a303acf80Dake Gu        return TransitionHelper.loadTransition(getActivity(),
16343f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                R.transition.lb_browse_entrance_transition);
1635c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1636c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
16373f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
16383f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void runEntranceTransition(Object entranceTransition) {
16398403619efebe94666c0615c3fc85080a303acf80Dake Gu        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
1640c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1641c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
16423f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
1643902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    protected void onEntranceTransitionPrepare() {
1644902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu        mHeadersSupportFragment.onTransitionPrepare();
1645a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        // setEntranceTransitionStartState() might be called when mMainFragment is null,
1646a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        // make sure it is called.
1647a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu        mMainFragmentAdapter.setEntranceTransitionState(false);
16481c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionPrepare();
1649902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    }
1650902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu
1651902e68c114f86e8002516ff3f0248b722b6c5711Dake Gu    @Override
16523f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionStart() {
16533f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        mHeadersSupportFragment.onTransitionStart();
16541c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.onTransitionStart();
1655c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1656c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
16573f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    @Override
16583f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    protected void onEntranceTransitionEnd() {
1659b082c7277cff057bdff19e411e345c3d6fea2e12susnata        if (mMainFragmentAdapter != null) {
1660b082c7277cff057bdff19e411e345c3d6fea2e12susnata            mMainFragmentAdapter.onTransitionEnd();
1661b082c7277cff057bdff19e411e345c3d6fea2e12susnata        }
1662b082c7277cff057bdff19e411e345c3d6fea2e12susnata
1663b082c7277cff057bdff19e411e345c3d6fea2e12susnata        if (mHeadersSupportFragment != null) {
1664b082c7277cff057bdff19e411e345c3d6fea2e12susnata            mHeadersSupportFragment.onTransitionEnd();
1665b082c7277cff057bdff19e411e345c3d6fea2e12susnata        }
1666c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1667c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
16683f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    void setSearchOrbViewOnScreen(boolean onScreen) {
1669a373804d10f93a9488adc35cf6ce44dce09b3778Dake Gu        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
1670b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata        if (searchOrbView != null) {
1671b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
1672b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
1673b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata            searchOrbView.setLayoutParams(lp);
1674b92376f5be24ddee5c6cd7c23b7c7e8e5c2cda68susnata        }
1675c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1676c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
1677c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    void setEntranceTransitionStartState() {
1678c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(false);
1679c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setSearchOrbViewOnScreen(false);
16801c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.setEntranceTransitionState(false);
1681c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1682c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu
1683c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    void setEntranceTransitionEndState() {
1684c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setHeadersOnScreen(mShowingHeaders);
1685c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        setSearchOrbViewOnScreen(true);
16861c3ce0fa10ec24e4edd5e5ea909b4d4357534b53susnata        mMainFragmentAdapter.setEntranceTransitionState(true);
1687c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
1688a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1689dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
1690a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1691a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private final View mView;
1692a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private final Runnable mCallback;
1693a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        private int mState;
1694fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        private MainFragmentAdapter mainFragmentAdapter;
1695a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1696a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_INIT = 0;
1697a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_FIRST_DRAW = 1;
1698a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        final static int STATE_SECOND_DRAW = 2;
1699a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1700fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
1701fb11ded6cfa3965883e68625e0c7e14b4b4fe0b3Susnata Basak            mView = view;
1702a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mCallback = callback;
1703a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mainFragmentAdapter = adapter;
1704a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1705a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1706a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        void execute() {
1707a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mView.getViewTreeObserver().addOnPreDrawListener(this);
1708a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mainFragmentAdapter.setExpand(false);
17092dda16536f0cc543f52abf53b18d6c1327031142Dake Gu            // always trigger onPreDraw even adapter setExpand() does nothing.
17102dda16536f0cc543f52abf53b18d6c1327031142Dake Gu            mView.invalidate();
1711a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            mState = STATE_INIT;
1712a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1713a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata
1714a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        @Override
1715a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        public boolean onPreDraw() {
1716dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu            if (getView() == null || getActivity() == null) {
1717dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu                mView.getViewTreeObserver().removeOnPreDrawListener(this);
1718dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu                return true;
1719dee82957d1100c2b65e6850769abd3ff00f1ec95Dake Gu            }
1720a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            if (mState == STATE_INIT) {
1721a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mainFragmentAdapter.setExpand(true);
17222dda16536f0cc543f52abf53b18d6c1327031142Dake Gu                // always trigger onPreDraw even adapter setExpand() does nothing.
17232dda16536f0cc543f52abf53b18d6c1327031142Dake Gu                mView.invalidate();
1724a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mState = STATE_FIRST_DRAW;
1725a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            } else if (mState == STATE_FIRST_DRAW) {
1726a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mCallback.run();
1727a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mView.getViewTreeObserver().removeOnPreDrawListener(this);
1728a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata                mState = STATE_SECOND_DRAW;
1729a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            }
1730a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata            return false;
1731a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata        }
1732a9f6062bd2dd02b3de253b57c69302893bf1f2e3susnata    }
173361905b0b52c50018dcaebcd79699c39b8f28d622Dake Gu}
1734