VerticalGridSupportFragment.java revision 4a10f1eb5c4283cfeef34cd71b84173f5ab3eefb
1/* This file is auto-generated from VerticalGridFragment.java.  DO NOT MODIFY. */
2
3/*
4 * Copyright (C) 2014 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7 * in compliance with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software distributed under the License
12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package android.support.v17.leanback.app;
17
18import android.support.v17.leanback.R;
19import android.support.v17.leanback.transition.TransitionHelper;
20import android.support.v17.leanback.widget.BrowseFrameLayout;
21import android.support.v17.leanback.widget.OnItemViewClickedListener;
22import android.support.v17.leanback.widget.OnItemViewSelectedListener;
23import android.support.v17.leanback.widget.Presenter;
24import android.support.v17.leanback.widget.Row;
25import android.support.v17.leanback.widget.RowPresenter;
26import android.support.v17.leanback.widget.TitleView;
27import android.support.v17.leanback.widget.VerticalGridPresenter;
28import android.support.v17.leanback.widget.ObjectAdapter;
29import android.support.v17.leanback.widget.OnItemClickedListener;
30import android.support.v17.leanback.widget.OnItemSelectedListener;
31import android.support.v17.leanback.widget.SearchOrbView;
32import android.support.v4.view.ViewCompat;
33import android.support.v4.app.Fragment;
34import android.graphics.drawable.Drawable;
35import android.os.Bundle;
36import android.util.Log;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.ViewGroup;
40import android.view.ViewGroup.MarginLayoutParams;
41import android.widget.ImageView;
42import android.widget.TextView;
43
44/**
45 * A fragment for creating leanback vertical grids.
46 *
47 * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
48 * an {@link ObjectAdapter}.
49 */
50public class VerticalGridSupportFragment extends Fragment {
51    private static final String TAG = "VerticalGridSupportFragment";
52    private static boolean DEBUG = false;
53
54    private BrowseFrameLayout mBrowseFrame;
55    private String mTitle;
56    private Drawable mBadgeDrawable;
57    private ObjectAdapter mAdapter;
58    private VerticalGridPresenter mGridPresenter;
59    private VerticalGridPresenter.ViewHolder mGridViewHolder;
60    private OnItemSelectedListener mOnItemSelectedListener;
61    private OnItemClickedListener mOnItemClickedListener;
62    private OnItemViewSelectedListener mOnItemViewSelectedListener;
63    private OnItemViewClickedListener mOnItemViewClickedListener;
64    private View.OnClickListener mExternalOnSearchClickedListener;
65    private int mSelectedPosition = -1;
66
67    private TitleView mTitleView;
68    private SearchOrbView.Colors mSearchAffordanceColors;
69    private boolean mSearchAffordanceColorSet;
70    private boolean mShowingTitle = true;
71
72    // transition related
73    private static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
74    private Object mTitleUpTransition;
75    private Object mTitleDownTransition;
76    private Object mSceneWithTitle;
77    private Object mSceneWithoutTitle;
78
79    /**
80     * Sets the badge drawable displayed in the title area.
81     */
82    public void setBadgeDrawable(Drawable drawable) {
83        if (drawable != mBadgeDrawable) {
84            mBadgeDrawable = drawable;
85            if (mTitleView != null) {
86                mTitleView.setBadgeDrawable(drawable);
87            }
88        }
89    }
90
91    /**
92     * Returns the badge drawable.
93     */
94    public Drawable getBadgeDrawable() {
95        return mBadgeDrawable;
96    }
97
98    /**
99     * Sets a title for the fragment.
100     */
101    public void setTitle(String title) {
102        mTitle = title;
103        if (mTitleView != null) {
104            mTitleView.setTitle(mTitle);
105        }
106    }
107
108    /**
109     * Returns the title for the fragment.
110     */
111    public String getTitle() {
112        return mTitle;
113    }
114
115    /**
116     * Sets the grid presenter.
117     */
118    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
119        if (gridPresenter == null) {
120            throw new IllegalArgumentException("Grid presenter may not be null");
121        }
122        mGridPresenter = gridPresenter;
123        mGridPresenter.setOnItemViewSelectedListener(mRowSelectedListener);
124        if (mOnItemViewClickedListener != null) {
125            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
126        }
127        if (mOnItemClickedListener != null) {
128            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
129        }
130    }
131
132    /**
133     * Returns the grid presenter.
134     */
135    public VerticalGridPresenter getGridPresenter() {
136        return mGridPresenter;
137    }
138
139    /**
140     * Sets the object adapter for the fragment.
141     */
142    public void setAdapter(ObjectAdapter adapter) {
143        mAdapter = adapter;
144        updateAdapter();
145    }
146
147    /**
148     * Returns the object adapter.
149     */
150    public ObjectAdapter getAdapter() {
151        return mAdapter;
152    }
153
154    final private OnItemViewSelectedListener mRowSelectedListener =
155            new OnItemViewSelectedListener() {
156        @Override
157        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
158                RowPresenter.ViewHolder rowViewHolder, Row row) {
159            int position = mGridViewHolder.getGridView().getSelectedPosition();
160            if (DEBUG) Log.v(TAG, "row selected position " + position);
161            onRowSelected(position);
162            if (mOnItemSelectedListener != null) {
163                mOnItemSelectedListener.onItemSelected(item, row);
164            }
165            if (mOnItemViewSelectedListener != null) {
166                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
167                        rowViewHolder, row);
168            }
169        }
170    };
171
172    /**
173     * Sets an item selection listener.
174     * @deprecated Use {@link #setOnItemViewSelectedListener(OnItemViewSelectedListener)}
175     */
176    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
177        mOnItemSelectedListener = listener;
178    }
179
180    /**
181     * Sets an item selection listener.
182     */
183    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
184        mOnItemViewSelectedListener = listener;
185    }
186
187    private void onRowSelected(int position) {
188        if (position != mSelectedPosition) {
189            if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(position)) {
190                // if has no sibling in front of it,  show title
191                if (!mShowingTitle) {
192                    sTransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
193                    mShowingTitle = true;
194                }
195            } else if (mShowingTitle) {
196                sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
197                mShowingTitle = false;
198            }
199            mSelectedPosition = position;
200        }
201    }
202
203    /**
204     * Sets an item clicked listener.
205     * @deprecated Use {@link #setOnItemViewClickedListener(OnItemViewClickedListener)}
206     */
207    public void setOnItemClickedListener(OnItemClickedListener listener) {
208        mOnItemClickedListener = listener;
209        if (mGridPresenter != null) {
210            mGridPresenter.setOnItemClickedListener(mOnItemClickedListener);
211        }
212    }
213
214    /**
215     * Returns the item clicked listener.
216     * @deprecated Use {@link #getOnItemViewClickedListener()}
217     */
218    public OnItemClickedListener getOnItemClickedListener() {
219        return mOnItemClickedListener;
220    }
221
222    /**
223     * Sets an item clicked listener.
224     */
225    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
226        mOnItemViewClickedListener = listener;
227        if (mGridPresenter != null) {
228            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
229        }
230    }
231
232    /**
233     * Returns the item clicked listener.
234     */
235    public OnItemViewClickedListener getOnItemViewClickedListener() {
236        return mOnItemViewClickedListener;
237    }
238
239    /**
240     * Sets a click listener for the search affordance.
241     *
242     * <p>The presence of a listener will change the visibility of the search
243     * affordance in the title area. When set to non-null, the title area will
244     * contain a call to search action.
245     *
246     * <p>The listener's onClick method will be invoked when the user clicks on
247     * the search action.
248     *
249     * @param listener The listener to invoke when the search affordance is
250     *        clicked, or null to hide the search affordance.
251     */
252    public void setOnSearchClickedListener(View.OnClickListener listener) {
253        mExternalOnSearchClickedListener = listener;
254        if (mTitleView != null) {
255            mTitleView.setOnSearchClickedListener(listener);
256        }
257    }
258
259    /**
260     * Sets the {@link SearchOrbView.Colors} used to draw the search affordance.
261     */
262    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
263        mSearchAffordanceColors = colors;
264        mSearchAffordanceColorSet = true;
265        if (mTitleView != null) {
266            mTitleView.setSearchAffordanceColors(mSearchAffordanceColors);
267        }
268    }
269
270    /**
271     * Returns the {@link SearchOrbView.Colors} used to draw the search affordance.
272     */
273    public SearchOrbView.Colors getSearchAffordanceColors() {
274        if (mSearchAffordanceColorSet) {
275            return mSearchAffordanceColors;
276        }
277        if (mTitleView == null) {
278            throw new IllegalStateException("Fragment views not yet created");
279        }
280        return mTitleView.getSearchAffordanceColors();
281    }
282
283    /**
284     * Sets the color used to draw the search affordance.
285     * A default brighter color will be set by the framework.
286     *
287     * @param color The color to use for the search affordance.
288     */
289    public void setSearchAffordanceColor(int color) {
290        setSearchAffordanceColors(new SearchOrbView.Colors(color));
291    }
292
293    /**
294     * Returns the color used to draw the search affordance.
295     */
296    public int getSearchAffordanceColor() {
297        return getSearchAffordanceColors().color;
298    }
299
300    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
301            new BrowseFrameLayout.OnFocusSearchListener() {
302        @Override
303        public View onFocusSearch(View focused, int direction) {
304            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
305
306            final View searchOrbView = mTitleView.getSearchAffordanceView();
307            final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
308                    View.LAYOUT_DIRECTION_RTL;
309            final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
310            if (focused == searchOrbView && (
311                    direction == View.FOCUS_DOWN || direction == forward)) {
312                return mGridViewHolder.view;
313
314            } else if (focused != searchOrbView && searchOrbView.getVisibility() == View.VISIBLE
315                    && direction == View.FOCUS_UP) {
316                return searchOrbView;
317
318            } else {
319                return null;
320            }
321        }
322    };
323
324    @Override
325    public View onCreateView(LayoutInflater inflater, ViewGroup container,
326            Bundle savedInstanceState) {
327        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
328                container, false);
329
330        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
331        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
332
333        mTitleView = (TitleView) root.findViewById(R.id.browse_title_group);
334        mTitleView.setBadgeDrawable(mBadgeDrawable);
335        mTitleView.setTitle(mTitle);
336        if (mSearchAffordanceColorSet) {
337            mTitleView.setSearchAffordanceColors(mSearchAffordanceColors);
338        }
339        if (mExternalOnSearchClickedListener != null) {
340            mTitleView.setOnSearchClickedListener(mExternalOnSearchClickedListener);
341        }
342
343        mSceneWithTitle = sTransitionHelper.createScene(root, new Runnable() {
344            @Override
345            public void run() {
346                mTitleView.setVisibility(View.VISIBLE);
347            }
348        });
349        mSceneWithoutTitle = sTransitionHelper.createScene(root, new Runnable() {
350            @Override
351            public void run() {
352                mTitleView.setVisibility(View.INVISIBLE);
353            }
354        });
355        mTitleUpTransition = TitleTransitionHelper.createTransitionTitleUp(sTransitionHelper);
356        mTitleDownTransition = TitleTransitionHelper.createTransitionTitleDown(sTransitionHelper);
357        sTransitionHelper.excludeChildren(mTitleUpTransition, R.id.browse_grid_dock, true);
358        sTransitionHelper.excludeChildren(mTitleDownTransition, R.id.browse_grid_dock, true);
359
360        return root;
361    }
362
363    @Override
364    public void onViewCreated(View view, Bundle savedInstanceState) {
365        ViewGroup gridDock = (ViewGroup) view.findViewById(R.id.browse_grid_dock);
366        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
367        gridDock.addView(mGridViewHolder.view);
368
369        updateAdapter();
370    }
371
372    @Override
373    public void onStart() {
374        super.onStart();
375        mGridViewHolder.getGridView().requestFocus();
376    }
377
378    @Override
379    public void onPause() {
380        mTitleView.enableAnimation(false);
381        super.onPause();
382    }
383
384    @Override
385    public void onResume() {
386        super.onResume();
387        mTitleView.enableAnimation(true);
388    }
389
390    @Override
391    public void onDestroyView() {
392        super.onDestroyView();
393        mGridViewHolder = null;
394    }
395
396    /**
397     * Sets the selected item position.
398     */
399    public void setSelectedPosition(int position) {
400        mSelectedPosition = position;
401        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
402            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
403        }
404    }
405
406    private void updateAdapter() {
407        if (mGridViewHolder != null) {
408            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
409            if (mSelectedPosition != -1) {
410                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
411            }
412        }
413    }
414}
415