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