1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.app; 15 16import android.os.Bundle; 17import android.support.v17.leanback.R; 18import android.support.v17.leanback.transition.TransitionHelper; 19import android.support.v17.leanback.util.StateMachine.State; 20import android.support.v17.leanback.widget.BrowseFrameLayout; 21import android.support.v17.leanback.widget.ObjectAdapter; 22import android.support.v17.leanback.widget.OnChildLaidOutListener; 23import android.support.v17.leanback.widget.OnItemViewClickedListener; 24import android.support.v17.leanback.widget.OnItemViewSelectedListener; 25import android.support.v17.leanback.widget.Presenter; 26import android.support.v17.leanback.widget.Row; 27import android.support.v17.leanback.widget.RowPresenter; 28import android.support.v17.leanback.widget.VerticalGridPresenter; 29import android.util.Log; 30import android.view.LayoutInflater; 31import android.view.View; 32import android.view.ViewGroup; 33 34/** 35 * A fragment for creating leanback vertical grids. 36 * 37 * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and 38 * an {@link ObjectAdapter}. 39 */ 40public class VerticalGridSupportFragment extends BaseSupportFragment { 41 static final String TAG = "VerticalGF"; 42 static boolean DEBUG = false; 43 44 private ObjectAdapter mAdapter; 45 private VerticalGridPresenter mGridPresenter; 46 VerticalGridPresenter.ViewHolder mGridViewHolder; 47 OnItemViewSelectedListener mOnItemViewSelectedListener; 48 private OnItemViewClickedListener mOnItemViewClickedListener; 49 private Object mSceneAfterEntranceTransition; 50 private int mSelectedPosition = -1; 51 52 /** 53 * State to setEntranceTransitionState(false) 54 */ 55 final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") { 56 @Override 57 public void run() { 58 setEntranceTransitionState(false); 59 } 60 }; 61 62 @Override 63 void createStateMachineStates() { 64 super.createStateMachineStates(); 65 mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE); 66 } 67 68 @Override 69 void createStateMachineTransitions() { 70 super.createStateMachineTransitions(); 71 mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, 72 STATE_SET_ENTRANCE_START_STATE, EVT_ON_CREATEVIEW); 73 } 74 75 /** 76 * Sets the grid presenter. 77 */ 78 public void setGridPresenter(VerticalGridPresenter gridPresenter) { 79 if (gridPresenter == null) { 80 throw new IllegalArgumentException("Grid presenter may not be null"); 81 } 82 mGridPresenter = gridPresenter; 83 mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener); 84 if (mOnItemViewClickedListener != null) { 85 mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener); 86 } 87 } 88 89 /** 90 * Returns the grid presenter. 91 */ 92 public VerticalGridPresenter getGridPresenter() { 93 return mGridPresenter; 94 } 95 96 /** 97 * Sets the object adapter for the fragment. 98 */ 99 public void setAdapter(ObjectAdapter adapter) { 100 mAdapter = adapter; 101 updateAdapter(); 102 } 103 104 /** 105 * Returns the object adapter. 106 */ 107 public ObjectAdapter getAdapter() { 108 return mAdapter; 109 } 110 111 final private OnItemViewSelectedListener mViewSelectedListener = 112 new OnItemViewSelectedListener() { 113 @Override 114 public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, 115 RowPresenter.ViewHolder rowViewHolder, Row row) { 116 int position = mGridViewHolder.getGridView().getSelectedPosition(); 117 if (DEBUG) Log.v(TAG, "grid selected position " + position); 118 gridOnItemSelected(position); 119 if (mOnItemViewSelectedListener != null) { 120 mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item, 121 rowViewHolder, row); 122 } 123 } 124 }; 125 126 final private OnChildLaidOutListener mChildLaidOutListener = 127 new OnChildLaidOutListener() { 128 @Override 129 public void onChildLaidOut(ViewGroup parent, View view, int position, long id) { 130 if (position == 0) { 131 showOrHideTitle(); 132 } 133 } 134 }; 135 136 /** 137 * Sets an item selection listener. 138 */ 139 public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) { 140 mOnItemViewSelectedListener = listener; 141 } 142 143 void gridOnItemSelected(int position) { 144 if (position != mSelectedPosition) { 145 mSelectedPosition = position; 146 showOrHideTitle(); 147 } 148 } 149 150 void showOrHideTitle() { 151 if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition) 152 == null) { 153 return; 154 } 155 if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) { 156 showTitle(true); 157 } else { 158 showTitle(false); 159 } 160 } 161 162 /** 163 * Sets an item clicked listener. 164 */ 165 public void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 166 mOnItemViewClickedListener = listener; 167 if (mGridPresenter != null) { 168 mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener); 169 } 170 } 171 172 /** 173 * Returns the item clicked listener. 174 */ 175 public OnItemViewClickedListener getOnItemViewClickedListener() { 176 return mOnItemViewClickedListener; 177 } 178 179 @Override 180 public View onCreateView(LayoutInflater inflater, ViewGroup container, 181 Bundle savedInstanceState) { 182 ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment, 183 container, false); 184 ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame); 185 installTitleView(inflater, gridFrame, savedInstanceState); 186 getProgressBarManager().setRootView(root); 187 188 ViewGroup gridDock = (ViewGroup) root.findViewById(R.id.browse_grid_dock); 189 mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock); 190 gridDock.addView(mGridViewHolder.view); 191 mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener); 192 193 mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() { 194 @Override 195 public void run() { 196 setEntranceTransitionState(true); 197 } 198 }); 199 200 updateAdapter(); 201 return root; 202 } 203 204 private void setupFocusSearchListener() { 205 BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById( 206 R.id.grid_frame); 207 browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener()); 208 } 209 210 @Override 211 public void onStart() { 212 super.onStart(); 213 setupFocusSearchListener(); 214 } 215 216 @Override 217 public void onDestroyView() { 218 super.onDestroyView(); 219 mGridViewHolder = null; 220 } 221 222 /** 223 * Sets the selected item position. 224 */ 225 public void setSelectedPosition(int position) { 226 mSelectedPosition = position; 227 if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) { 228 mGridViewHolder.getGridView().setSelectedPositionSmooth(position); 229 } 230 } 231 232 private void updateAdapter() { 233 if (mGridViewHolder != null) { 234 mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter); 235 if (mSelectedPosition != -1) { 236 mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition); 237 } 238 } 239 } 240 241 @Override 242 protected Object createEntranceTransition() { 243 return TransitionHelper.loadTransition(getContext(), 244 R.transition.lb_vertical_grid_entrance_transition); 245 } 246 247 @Override 248 protected void runEntranceTransition(Object entranceTransition) { 249 TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition); 250 } 251 252 void setEntranceTransitionState(boolean afterTransition) { 253 mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition); 254 } 255} 256