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
1670acb0c19be3831a2080e4f902324de16bfbf62eTor Norbyeimport android.support.annotation.ColorInt;
17739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.R;
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;
25e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stoutimport android.support.v17.leanback.widget.TitleHelper;
26731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stoutimport android.support.v17.leanback.widget.TitleView;
27739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.VerticalGridPresenter;
28739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.support.v17.leanback.widget.ObjectAdapter;
29739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.os.Bundle;
3025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.util.Log;
31739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.LayoutInflater;
32739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.View;
33739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport android.view.ViewGroup;
34739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
35739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout/**
364c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn * A fragment for creating leanback vertical grids.
37739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout *
384c0f3062b5edd9750351068f46e5270bb220091dTim Kilbourn * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
39739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * an {@link ObjectAdapter}.
40739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout */
41e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stoutpublic class VerticalGridFragment extends BrandedFragment {
42739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static final String TAG = "VerticalGridFragment";
43739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private static boolean DEBUG = false;
44739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
45739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private ObjectAdapter mAdapter;
46739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private VerticalGridPresenter mGridPresenter;
47739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private VerticalGridPresenter.ViewHolder mGridViewHolder;
48947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    private OnItemViewSelectedListener mOnItemViewSelectedListener;
49947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    private OnItemViewClickedListener mOnItemViewClickedListener;
50739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private int mSelectedPosition = -1;
51739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
52dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout    /**
53dfb60d0af5d49da05c584d74245c616263f26b65Craig Stout     * Sets the grid presenter.
54739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
55739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
56739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (gridPresenter == null) {
57739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            throw new IllegalArgumentException("Grid presenter may not be null");
58739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
59739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridPresenter = gridPresenter;
60d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
61947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        if (mOnItemViewClickedListener != null) {
62947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
63947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        }
64739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
65739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
66739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
67739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the grid presenter.
68739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
69739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public VerticalGridPresenter getGridPresenter() {
70739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mGridPresenter;
71739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
72739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
73739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
74739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the object adapter for the fragment.
75739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
76739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setAdapter(ObjectAdapter adapter) {
77739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mAdapter = adapter;
78739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        updateAdapter();
79739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
80739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
81739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
82739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Returns the object adapter.
83739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
84739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public ObjectAdapter getAdapter() {
85739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        return mAdapter;
86739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
87739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
88d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    final private OnItemViewSelectedListener mViewSelectedListener =
89947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            new OnItemViewSelectedListener() {
90e34cae48707e70442aca13e1b4ab55757292828dDake Gu        @Override
91947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
92947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                RowPresenter.ViewHolder rowViewHolder, Row row) {
93e34cae48707e70442aca13e1b4ab55757292828dDake Gu            int position = mGridViewHolder.getGridView().getSelectedPosition();
94d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            if (DEBUG) Log.v(TAG, "grid selected position " + position);
95d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            gridOnItemSelected(position);
96947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            if (mOnItemViewSelectedListener != null) {
97947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
98947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu                        rowViewHolder, row);
99947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            }
100e34cae48707e70442aca13e1b4ab55757292828dDake Gu        }
101e34cae48707e70442aca13e1b4ab55757292828dDake Gu    };
102e34cae48707e70442aca13e1b4ab55757292828dDake Gu
103d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    final private OnChildLaidOutListener mChildLaidOutListener =
104d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            new OnChildLaidOutListener() {
105d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        @Override
106d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
107d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            if (position == 0) {
108d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                showOrHideTitle();
109d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            }
110d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
111d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    };
112d586ba8825b418d9589436725bfdead30f0dc075Dake Gu
113739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
114739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets an item selection listener.
115947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
116947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
117947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        mOnItemViewSelectedListener = listener;
118947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
119947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
120d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    private void gridOnItemSelected(int position) {
121e34cae48707e70442aca13e1b4ab55757292828dDake Gu        if (position != mSelectedPosition) {
122e34cae48707e70442aca13e1b4ab55757292828dDake Gu            mSelectedPosition = position;
123d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            showOrHideTitle();
124d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
125d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    }
126d586ba8825b418d9589436725bfdead30f0dc075Dake Gu
127d586ba8825b418d9589436725bfdead30f0dc075Dake Gu    private void showOrHideTitle() {
128d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
129d586ba8825b418d9589436725bfdead30f0dc075Dake Gu                == null) {
130d586ba8825b418d9589436725bfdead30f0dc075Dake Gu            return;
131d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        }
132d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
133e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            showTitle(true);
134e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        } else {
135e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout            showTitle(false);
136e34cae48707e70442aca13e1b4ab55757292828dDake Gu        }
137e34cae48707e70442aca13e1b4ab55757292828dDake Gu    }
138739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
139739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
140739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets an item clicked listener.
141947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
142947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
143947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        mOnItemViewClickedListener = listener;
144947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        if (mGridPresenter != null) {
145947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
146947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        }
147947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
148947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
149947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    /**
150947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     * Returns the item clicked listener.
151947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu     */
152947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    public OnItemViewClickedListener getOnItemViewClickedListener() {
153947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu        return mOnItemViewClickedListener;
154947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu    }
155947dbf076cd019e3c26217fbc7aa21e860d68044Dake Gu
156739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
157739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public View onCreateView(LayoutInflater inflater, ViewGroup container,
158739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            Bundle savedInstanceState) {
159e34cae48707e70442aca13e1b4ab55757292828dDake Gu        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
160e34cae48707e70442aca13e1b4ab55757292828dDake Gu                container, false);
161e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        setTitleView((TitleView) root.findViewById(R.id.browse_title_group));
162731066a59e10ddc7bb6c95d0b91b3e0e11e10396Craig Stout        return root;
1639020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout    }
1649020c0aec57b4e8994d66b7cd1a89c225e9bfa11Craig Stout
165739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
166739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onViewCreated(View view, Bundle savedInstanceState) {
167e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        super.onViewCreated(view, savedInstanceState);
168739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        ViewGroup gridDock = (ViewGroup) view.findViewById(R.id.browse_grid_dock);
169739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
170739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        gridDock.addView(mGridViewHolder.view);
171d586ba8825b418d9589436725bfdead30f0dc075Dake Gu        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
172739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
173739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        updateAdapter();
174739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
175739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
176e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout    private void setupFocusSearchListener() {
177e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
178e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout                R.id.grid_frame);
179e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
180e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout    }
181e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout
182739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
183739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onStart() {
184739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        super.onStart();
185e7246ef136ed686d8caf339d4d1fd8e37b499c6aCraig Stout        setupFocusSearchListener();
186739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder.getGridView().requestFocus();
187739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
188739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
189739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    @Override
190739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void onDestroyView() {
191739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        super.onDestroyView();
192739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mGridViewHolder = null;
193739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
194739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
195739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    /**
196739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Sets the selected item position.
197739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     */
198739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    public void setSelectedPosition(int position) {
199739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        mSelectedPosition = position;
200739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
201739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
202739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
203739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
204739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
205739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    private void updateAdapter() {
206739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        if (mGridViewHolder != null) {
207739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
208739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            if (mSelectedPosition != -1) {
209739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
210739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout            }
211739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        }
212739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout    }
213739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout}
214