VerticalGridFragment.java revision d586ba8825b418d9589436725bfdead30f0dc075
1739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout/*
2739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Copyright (C) 2014 The Android Open Source Project
3739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
4739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * in compliance with the License. You may obtain a copy of the License at
6739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
7739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
8739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
9739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
10739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
12739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * the License.
13739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout */
14739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutpackage android.support.v17.leanback.app;
15739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
16739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.R;
1795400e6d31a1ac09e48cb8944a79b7250484aa4cDake Guimport android.support.v17.leanback.transition.TransitionHelper;
185d00775a5d3ce3c1fc06c4de0945d1b8f03aadc4Dake Guimport android.support.v17.leanback.widget.BrowseFrameLayout;
19d586ba8825b418d9589436725bfdead30f0dc075Dake Guimport android.support.v17.leanback.widget.OnChildLaidOutListener;
20947dbf076cd019e3c26217fbc7aa21e860d68044Dake Guimport android.support.v17.leanback.widget.OnItemViewClickedListener;
21947dbf076cd019e3c26217fbc7aa21e860d68044Dake Guimport android.support.v17.leanback.widget.OnItemViewSelectedListener;
22947dbf076cd019e3c26217fbc7aa21e860d68044Dake Guimport android.support.v17.leanback.widget.Presenter;
23e34cae48707e70442aca13e1b4ab55757292828dDake Guimport android.support.v17.leanback.widget.Row;
24947dbf076cd019e3c26217fbc7aa21e860d68044Dake Guimport android.support.v17.leanback.widget.RowPresenter;
25731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stoutimport android.support.v17.leanback.widget.TitleView;
26739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.VerticalGridPresenter;
27739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.ObjectAdapter;
28739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.OnItemClickedListener;
29739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.OnItemSelectedListener;
30739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.SearchOrbView;
314a10f1eb5c4283cfeef34cd71b84173f5ab3eefbKris Giesingimport android.support.v4.view.ViewCompat;
32739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.app.Fragment;
334735bfcd924fec2d694523f34fac5f8151257dc7Dake Guimport android.content.Context;
34739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.graphics.drawable.Drawable;
35739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.os.Bundle;
3625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.util.Log;
37739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.LayoutInflater;
38739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.View;
39739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.ViewGroup;
409020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stoutimport android.view.ViewGroup.MarginLayoutParams;
41739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.widget.ImageView;
42739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.widget.TextView;
43739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
44739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout/**
454c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn * A fragment for creating leanback vertical grids.
46739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
474c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
48739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * an {@link ObjectAdapter}.
49739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout */
50739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutpublic class VerticalGridFragment extends Fragment {
51739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static final String TAG = "VerticalGridFragment";
52739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static boolean DEBUG = false;
53739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
549020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout    private BrowseFrameLayout mBrowseFrame;
55dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    private String mTitle;
56dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    private Drawable mBadgeDrawable;
57739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private ObjectAdapter mAdapter;
58739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private VerticalGridPresenter mGridPresenter;
59739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private VerticalGridPresenter.ViewHolder mGridViewHolder;
60739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private OnItemSelectedListener mOnItemSelectedListener;
61739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private OnItemClickedListener mOnItemClickedListener;
62947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    private OnItemViewSelectedListener mOnItemViewSelectedListener;
63947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    private OnItemViewClickedListener mOnItemViewClickedListener;
64a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn    private View.OnClickListener mExternalOnSearchClickedListener;
65739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private int mSelectedPosition = -1;
66739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
67731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    private TitleView mTitleView;
684fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    private SearchOrbView.Colors mSearchAffordanceColors;
69731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    private boolean mSearchAffordanceColorSet;
70e34cae48707e70442aca13e1b4ab55757292828dDake Gu    private boolean mShowingTitle = true;
71e34cae48707e70442aca13e1b4ab55757292828dDake Gu
72e34cae48707e70442aca13e1b4ab55757292828dDake Gu    // transition related
73e34cae48707e70442aca13e1b4ab55757292828dDake Gu    private static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
74731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    private Object mTitleUpTransition;
75731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    private Object mTitleDownTransition;
76e34cae48707e70442aca13e1b4ab55757292828dDake Gu    private Object mSceneWithTitle;
77e34cae48707e70442aca13e1b4ab55757292828dDake Gu    private Object mSceneWithoutTitle;
78739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
79739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
80dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Sets the badge drawable displayed in the title area.
81dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     */
82dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    public void setBadgeDrawable(Drawable drawable) {
83dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        if (drawable != mBadgeDrawable) {
84dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout            mBadgeDrawable = drawable;
85731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            if (mTitleView != null) {
86731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout                mTitleView.setBadgeDrawable(drawable);
87731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            }
88dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        }
89dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    }
90dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout
91dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    /**
92dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Returns the badge drawable.
93dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     */
94dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    public Drawable getBadgeDrawable() {
95dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        return mBadgeDrawable;
96dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    }
97dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout
98dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    /**
99dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Sets a title for the fragment.
100dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     */
101dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    public void setTitle(String title) {
102dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        mTitle = title;
103dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        if (mTitleView != null) {
104731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            mTitleView.setTitle(mTitle);
105dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        }
106dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    }
107dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout
108dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    /**
109dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Returns the title for the fragment.
110dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     */
111dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    public String getTitle() {
112dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout        return mTitle;
113dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    }
114dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout
115dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    /**
116dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Sets the grid presenter.
117739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
118739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
119739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (gridPresenter == null) {
120739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            throw new IllegalArgumentException("Grid presenter may not be null");
121739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
122739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridPresenter = gridPresenter;
123d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
124947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        if (mOnItemViewClickedListener != null) {
125947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
126947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        }
127739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mOnItemClickedListener != null) {
128739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
129739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
130739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
131739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
132739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
133739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the grid presenter.
134739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
135739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public VerticalGridPresenter getGridPresenter() {
136739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mGridPresenter;
137739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
138739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
139739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
140739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the object adapter for the fragment.
141739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
142739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setAdapter(ObjectAdapter adapter) {
143739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mAdapter = adapter;
144739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        updateAdapter();
145739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
146739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
147739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
148739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the object adapter.
149739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
150739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public ObjectAdapter getAdapter() {
151739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mAdapter;
152739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
153739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
154d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    final private OnItemViewSelectedListener mViewSelectedListener =
155947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            new OnItemViewSelectedListener() {
156e34cae48707e70442aca13e1b4ab55757292828dDake Gu        @Override
157947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
158947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                RowPresenter.ViewHolder rowViewHolder, Row row) {
159e34cae48707e70442aca13e1b4ab55757292828dDake Gu            int position = mGridViewHolder.getGridView().getSelectedPosition();
160d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            if (DEBUG) Log.v(TAG, "grid selected position " + position);
161d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            gridOnItemSelected(position);
162e34cae48707e70442aca13e1b4ab55757292828dDake Gu            if (mOnItemSelectedListener != null) {
163e34cae48707e70442aca13e1b4ab55757292828dDake Gu                mOnItemSelectedListener.onItemSelected(item, row);
164e34cae48707e70442aca13e1b4ab55757292828dDake Gu            }
165947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            if (mOnItemViewSelectedListener != null) {
166947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
167947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                        rowViewHolder, row);
168947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            }
169e34cae48707e70442aca13e1b4ab55757292828dDake Gu        }
170e34cae48707e70442aca13e1b4ab55757292828dDake Gu    };
171e34cae48707e70442aca13e1b4ab55757292828dDake Gu
172d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    final private OnChildLaidOutListener mChildLaidOutListener =
173d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            new OnChildLaidOutListener() {
174d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        @Override
175d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
176d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            if (position == 0) {
177d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                showOrHideTitle();
178d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            }
179d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
180d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    };
181d586ba8825b418d9589436725bfdead30f0dc075Dake Gu
182739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
183739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets an item selection listener.
184afe1da48b4673f64c67c130237dd485a34a69c1bDake Gu     * @deprecated Use {@link #setOnItemViewSelectedListener(OnItemViewSelectedListener)}
185739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
186739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
187739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mOnItemSelectedListener = listener;
188739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
189739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
190947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    /**
191947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     * Sets an item selection listener.
192947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
193947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
194947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        mOnItemViewSelectedListener = listener;
195947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
196947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
197d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    private void gridOnItemSelected(int position) {
198e34cae48707e70442aca13e1b4ab55757292828dDake Gu        if (position != mSelectedPosition) {
199e34cae48707e70442aca13e1b4ab55757292828dDake Gu            mSelectedPosition = position;
200d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            showOrHideTitle();
201d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
202d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    }
203d586ba8825b418d9589436725bfdead30f0dc075Dake Gu
204d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    private void showOrHideTitle() {
205d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
206d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                == null) {
207d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            return;
208d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
209d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
210d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            // if has no sibling in front of it,  show title
211d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            if (!mShowingTitle) {
212d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                sTransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
213d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                mShowingTitle = true;
214d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            }
215d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        } else if (mShowingTitle) {
216d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
217d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            mShowingTitle = false;
218e34cae48707e70442aca13e1b4ab55757292828dDake Gu        }
219e34cae48707e70442aca13e1b4ab55757292828dDake Gu    }
220739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
221739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
222739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets an item clicked listener.
223afe1da48b4673f64c67c130237dd485a34a69c1bDake Gu     * @deprecated Use {@link #setOnItemViewClickedListener(OnItemViewClickedListener)}
224739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
225739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setOnItemClickedListener(OnItemClickedListener listener) {
226739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mOnItemClickedListener = listener;
227739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mGridPresenter != null) {
228739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
229739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
230739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
231739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
232739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
233739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the item clicked listener.
234afe1da48b4673f64c67c130237dd485a34a69c1bDake Gu     * @deprecated Use {@link #getOnItemViewClickedListener()}
235739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
236739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public OnItemClickedListener getOnItemClickedListener() {
237739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mOnItemClickedListener;
238739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
239739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
240a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn    /**
241947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     * Sets an item clicked listener.
242947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
243947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
244947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        mOnItemViewClickedListener = listener;
245947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        if (mGridPresenter != null) {
246947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
247947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        }
248947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
249947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
250947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    /**
251947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     * Returns the item clicked listener.
252947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
253947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public OnItemViewClickedListener getOnItemViewClickedListener() {
254947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        return mOnItemViewClickedListener;
255947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
256947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
257947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    /**
258a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn     * Sets a click listener for the search affordance.
259a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn     *
2604c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * <p>The presence of a listener will change the visibility of the search
2614c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * affordance in the title area. When set to non-null, the title area will
2624c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * contain a call to search action.
263a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn     *
2644c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * <p>The listener's onClick method will be invoked when the user clicks on
2654c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * the search action.
266a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn     *
2674c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     * @param listener The listener to invoke when the search affordance is
2684c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn     *        clicked, or null to hide the search affordance.
269a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn     */
270a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn    public void setOnSearchClickedListener(View.OnClickListener listener) {
271a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn        mExternalOnSearchClickedListener = listener;
272731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        if (mTitleView != null) {
273731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            mTitleView.setOnSearchClickedListener(listener);
274731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        }
275731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    }
276731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout
277731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    /**
2784fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Sets the {@link SearchOrbView.Colors} used to draw the search affordance.
279731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout     */
2804fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
2814fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        mSearchAffordanceColors = colors;
282731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        mSearchAffordanceColorSet = true;
283731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        if (mTitleView != null) {
2844fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            mTitleView.setSearchAffordanceColors(mSearchAffordanceColors);
285a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn        }
286a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn    }
287a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn
288731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout    /**
2894fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Returns the {@link SearchOrbView.Colors} used to draw the search affordance.
290731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout     */
2914fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public SearchOrbView.Colors getSearchAffordanceColors() {
292731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        if (mSearchAffordanceColorSet) {
2934fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            return mSearchAffordanceColors;
294739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
295731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        if (mTitleView == null) {
296731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            throw new IllegalStateException("Fragment views not yet created");
297739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
2984fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        return mTitleView.getSearchAffordanceColors();
2994fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    }
3004fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout
3014fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
3024fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Sets the color used to draw the search affordance.
3034fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * A default brighter color will be set by the framework.
3044fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     *
3054fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * @param color The color to use for the search affordance.
3064fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
3074fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public void setSearchAffordanceColor(int color) {
3084fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        setSearchAffordanceColors(new SearchOrbView.Colors(color));
309739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
310739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
3114fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    /**
3124fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     * Returns the color used to draw the search affordance.
3134fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout     */
3144fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    public int getSearchAffordanceColor() {
3154fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout        return getSearchAffordanceColors().color;
3164fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout    }
317731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout
3189020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
3199020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout            new BrowseFrameLayout.OnFocusSearchListener() {
3209020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout        @Override
3219020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout        public View onFocusSearch(View focused, int direction) {
3229020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
3239020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
324731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            final View searchOrbView = mTitleView.getSearchAffordanceView();
3254a10f1eb5c4283cfeef34cd71b84173f5ab3eefbKris Giesing            final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
3264a10f1eb5c4283cfeef34cd71b84173f5ab3eefbKris Giesing                    View.LAYOUT_DIRECTION_RTL;
3274a10f1eb5c4283cfeef34cd71b84173f5ab3eefbKris Giesing            final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
328731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            if (focused == searchOrbView && (
3294a10f1eb5c4283cfeef34cd71b84173f5ab3eefbKris Giesing                    direction == View.FOCUS_DOWN || direction == forward)) {
3309020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout                return mGridViewHolder.view;
3319020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
332731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            } else if (focused != searchOrbView && searchOrbView.getVisibility() == View.VISIBLE
3339020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout                    && direction == View.FOCUS_UP) {
334731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout                return searchOrbView;
3359020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
3369020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout            } else {
3379020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout                return null;
3389020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout            }
3399020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout        }
3409020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout    };
3419020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
342739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
343739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public View onCreateView(LayoutInflater inflater, ViewGroup container,
344739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            Bundle savedInstanceState) {
345e34cae48707e70442aca13e1b4ab55757292828dDake Gu        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
346e34cae48707e70442aca13e1b4ab55757292828dDake Gu                container, false);
347739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
3489020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
3499020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
3509020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
351731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        mTitleView = (TitleView) root.findViewById(R.id.browse_title_group);
352731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        mTitleView.setBadgeDrawable(mBadgeDrawable);
353731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        mTitleView.setTitle(mTitle);
354731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        if (mSearchAffordanceColorSet) {
3554fdd3589c982860b831c0fad63c0082cb9079f47Craig Stout            mTitleView.setSearchAffordanceColors(mSearchAffordanceColors);
356731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        }
357a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn        if (mExternalOnSearchClickedListener != null) {
358731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout            mTitleView.setOnSearchClickedListener(mExternalOnSearchClickedListener);
359a8d3588c80a232042474aca55a69df78c8ac8cb3Tim Kilbourn        }
360739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
361e34cae48707e70442aca13e1b4ab55757292828dDake Gu        mSceneWithTitle = sTransitionHelper.createScene(root, new Runnable() {
362e34cae48707e70442aca13e1b4ab55757292828dDake Gu            @Override
363e34cae48707e70442aca13e1b4ab55757292828dDake Gu            public void run() {
36433f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                mTitleView.setVisibility(View.VISIBLE);
365e34cae48707e70442aca13e1b4ab55757292828dDake Gu            }
366e34cae48707e70442aca13e1b4ab55757292828dDake Gu        });
367e34cae48707e70442aca13e1b4ab55757292828dDake Gu        mSceneWithoutTitle = sTransitionHelper.createScene(root, new Runnable() {
368e34cae48707e70442aca13e1b4ab55757292828dDake Gu            @Override
369e34cae48707e70442aca13e1b4ab55757292828dDake Gu            public void run() {
37033f66eb67b6457ea75434dfd9f79703ad9e03560Dake Gu                mTitleView.setVisibility(View.INVISIBLE);
371e34cae48707e70442aca13e1b4ab55757292828dDake Gu            }
372e34cae48707e70442aca13e1b4ab55757292828dDake Gu        });
3734735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        Context context = getActivity();
3744735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        mTitleUpTransition = sTransitionHelper.loadTransition(context, R.transition.lb_title_out);
3754735bfcd924fec2d694523f34fac5f8151257dc7Dake Gu        mTitleDownTransition = sTransitionHelper.loadTransition(context, R.transition.lb_title_in);
376739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
377731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        return root;
3789020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout    }
3799020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
380739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
381739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onViewCreated(View view, Bundle savedInstanceState) {
382739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        ViewGroup gridDock = (ViewGroup) view.findViewById(R.id.browse_grid_dock);
383739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
384739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        gridDock.addView(mGridViewHolder.view);
385d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
386739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
387739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        updateAdapter();
388739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
389739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
390739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
391739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onStart() {
392739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        super.onStart();
393739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder.getGridView().requestFocus();
394739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
395739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
396739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
397447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    public void onPause() {
398447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout        mTitleView.enableAnimation(false);
399447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout        super.onPause();
400447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    }
401447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout
402447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    @Override
403447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    public void onResume() {
404447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout        super.onResume();
405447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout        mTitleView.enableAnimation(true);
406447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    }
407447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout
408447860fd5c105dd0ccd227237ac5f18fdc4c26dcCraig Stout    @Override
409739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onDestroyView() {
410739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        super.onDestroyView();
411739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder = null;
412739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
413739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
414739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
415739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the selected item position.
416739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
417739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setSelectedPosition(int position) {
418739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mSelectedPosition = position;
419739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
420739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
421739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
422739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
423739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
424739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private void updateAdapter() {
425739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mGridViewHolder != null) {
426739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
427739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            if (mSelectedPosition != -1) {
428739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
429739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            }
430739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
431739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
432739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout}
433