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