BrowseFragment.java revision e34cae48707e70442aca13e1b4ab55757292828d
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.support.v17.leanback.R;
17import android.support.v17.leanback.widget.HorizontalGridView;
18import android.support.v17.leanback.widget.Presenter;
19import android.support.v17.leanback.widget.PresenterSelector;
20import android.support.v17.leanback.widget.VerticalGridView;
21import android.support.v17.leanback.widget.Row;
22import android.support.v17.leanback.widget.ObjectAdapter;
23import android.support.v17.leanback.widget.OnItemSelectedListener;
24import android.support.v17.leanback.widget.OnItemClickedListener;
25import android.support.v17.leanback.widget.SearchOrbView;
26import android.util.Log;
27import android.util.SparseIntArray;
28import android.app.Fragment;
29import android.content.res.TypedArray;
30import android.os.Bundle;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.view.View.OnClickListener;
34import android.view.ViewGroup;
35import android.view.ViewGroup.MarginLayoutParams;
36import android.widget.ImageView;
37import android.widget.TextView;
38import android.graphics.drawable.Drawable;
39
40import java.util.ArrayList;
41
42import static android.support.v7.widget.RecyclerView.NO_POSITION;
43
44/**
45 * Wrapper fragment for leanback browse screens. Composed of a
46 * RowsFragment and a HeadersFragment.
47 *
48 */
49public class BrowseFragment extends Fragment {
50    private static final String TAG = "BrowseFragment";
51    private static boolean DEBUG = false;
52
53    /** The fastlane navigation panel is enabled and shown by default. */
54    public static final int HEADERS_ENABLED = 1;
55
56    /** The fastlane navigation panel is enabled and hidden by default. */
57    public static final int HEADERS_HIDDEN = 2;
58
59    /** The fastlane navigation panel is disabled and will never be shown. */
60    public static final int HEADERS_DISABLED = 3;
61
62    private RowsFragment mRowsFragment;
63    private HeadersFragment mHeadersFragment;
64
65    private ObjectAdapter mAdapter;
66
67    private Params mParams;
68    private BrowseFrameLayout mBrowseFrame;
69    private ImageView mBadgeView;
70    private TextView mTitleView;
71    private ViewGroup mBrowseTitle;
72    private SearchOrbView mSearchOrbView;
73    private boolean mShowingTitle = true;
74    private boolean mShowingHeaders = true;
75    private boolean mCanShowHeaders = true;
76    private int mContainerListMarginLeft;
77    private int mContainerListAlignTop;
78    private OnItemSelectedListener mExternalOnItemSelectedListener;
79    private OnClickListener mExternalOnSearchClickedListener;
80    private OnItemClickedListener mOnItemClickedListener;
81    private int mSelectedPosition = -1;
82
83    private PresenterSelector mHeaderPresenterSelector;
84
85    // transition related:
86    private static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
87    private static int sReparentHeaderId = View.generateViewId();
88    private Object mSceneWithTitle;
89    private Object mSceneWithoutTitle;
90    private Object mSceneWithHeaders;
91    private Object mSceneWithoutHeaders;
92    private Object mTitleTransition;
93    private Object mHeadersTransition;
94    private int mHeadersTransitionStartDelay;
95
96    private static final String ARG_TITLE = BrowseFragment.class.getCanonicalName() + ".title";
97    private static final String ARG_BADGE_URI = BrowseFragment.class.getCanonicalName() + ".badge";
98    private static final String ARG_HEADERS_STATE =
99        BrowseFragment.class.getCanonicalName() + ".headersState";
100
101    /**
102     * @param args Bundle to use for the arguments, if null a new Bundle will be created.
103     */
104    public static Bundle createArgs(Bundle args, String title, String badgeUri) {
105        return createArgs(args, title, badgeUri, HEADERS_ENABLED);
106    }
107
108    public static Bundle createArgs(Bundle args, String title, String badgeUri, int headersState) {
109        if (args == null) {
110            args = new Bundle();
111        }
112        args.putString(ARG_TITLE, title);
113        args.putString(ARG_BADGE_URI, badgeUri);
114        args.putInt(ARG_HEADERS_STATE, headersState);
115        return args;
116    }
117
118    public static class Params {
119        private String mTitle;
120        private Drawable mBadgeDrawable;
121        private int mHeadersState;
122
123        /**
124         * Sets the badge image.
125         */
126        public void setBadgeImage(Drawable drawable) {
127            mBadgeDrawable = drawable;
128        }
129
130        /**
131         * Returns the badge image.
132         */
133        public Drawable getBadgeImage() {
134            return mBadgeDrawable;
135        }
136
137        /**
138         * Sets a title for the browse fragment.
139         */
140        public void setTitle(String title) {
141            mTitle = title;
142        }
143
144        /**
145         * Returns the title for the browse fragment.
146         */
147        public String getTitle() {
148            return mTitle;
149        }
150
151        /**
152         * Sets the state for the headers column in the browse fragment.
153         */
154        public void setHeadersState(int headersState) {
155            if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
156                Log.e(TAG, "Invalid headers state: " + headersState
157                        + ", default to enabled and shown.");
158                mHeadersState = HEADERS_ENABLED;
159            } else {
160                mHeadersState = headersState;
161            }
162        }
163
164        /**
165         * Returns the state for the headers column in the browse fragment.
166         */
167        public int getHeadersState() {
168            return mHeadersState;
169        }
170    }
171
172    /**
173     * Set browse parameters.
174     */
175    public void setBrowseParams(Params params) {
176        mParams = params;
177        setBadgeDrawable(mParams.mBadgeDrawable);
178        setTitle(mParams.mTitle);
179        setHeadersState(mParams.mHeadersState);
180    }
181
182    /**
183     * Returns browse parameters.
184     */
185    public Params getBrowseParams() {
186        return mParams;
187    }
188
189    /**
190     * Sets the list of rows for the fragment.
191     */
192    public void setAdapter(ObjectAdapter adapter) {
193        mAdapter = adapter;
194        if (mRowsFragment != null) {
195            mRowsFragment.setAdapter(adapter);
196            mHeadersFragment.setAdapter(adapter);
197        }
198    }
199
200    /**
201     * Returns the list of rows.
202     */
203    public ObjectAdapter getAdapter() {
204        return mAdapter;
205    }
206
207    /**
208     * Sets an item selection listener.
209     */
210    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
211        mExternalOnItemSelectedListener = listener;
212    }
213
214    /**
215     * Sets an item clicked listener on the fragment.
216     * OnItemClickedListener will override {@link View.OnClickListener} that
217     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
218     * So in general,  developer should choose one of the listeners but not both.
219     */
220    public void setOnItemClickedListener(OnItemClickedListener listener) {
221        mOnItemClickedListener = listener;
222        if (mRowsFragment != null) {
223            mRowsFragment.setOnItemClickedListener(listener);
224        }
225    }
226
227    /**
228     * Returns the item Clicked listener.
229     */
230    public OnItemClickedListener getOnItemClickedListener() {
231        return mOnItemClickedListener;
232    }
233
234    /**
235     * Sets a click listener for the search affordance.
236     *
237     * The presence of a listener will change the visibility of the search affordance in the
238     * title area. When set to non-null the title area will contain a call to search action.
239     *
240     * The listener onClick method will be invoked when the user click on the search action.
241     *
242     * @param listener The listener.
243     */
244    public void setOnSearchClickedListener(View.OnClickListener listener) {
245        mExternalOnSearchClickedListener = listener;
246        if (mSearchOrbView != null) {
247            mSearchOrbView.setOnOrbClickedListener(listener);
248        }
249    }
250
251    private void onHeadersTransitionStart(boolean withHeaders) {
252        mRowsFragment.getVerticalGridView().setAnimateChildLayout(false);
253        mRowsFragment.getVerticalGridView().setFocusSearchDisabled(true);
254        mHeadersFragment.getVerticalGridView().setFocusSearchDisabled(true);
255        createHeadersTransition(withHeaders);
256    }
257
258    private boolean isVerticalScrolling() {
259        // don't run transition
260        return mHeadersFragment.getVerticalGridView().getScrollState()
261                != HorizontalGridView.SCROLL_STATE_IDLE
262                || mRowsFragment.getVerticalGridView().getScrollState()
263                != HorizontalGridView.SCROLL_STATE_IDLE;
264    }
265
266    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
267            new BrowseFrameLayout.OnFocusSearchListener() {
268        @Override
269        public View onFocusSearch(View focused, int direction) {
270            // If fastlane is disabled, just return null.
271            if (!mCanShowHeaders) return null;
272
273            // if fast lane is running transition,  focus stays
274            if (mHeadersTransition != null) return focused;
275            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
276            if (direction == View.FOCUS_LEFT) {
277                if (isVerticalScrolling() || mShowingHeaders) {
278                    return focused;
279                }
280                return mHeadersFragment.getVerticalGridView();
281            } else if (direction == View.FOCUS_RIGHT) {
282                if (isVerticalScrolling() || !mShowingHeaders) {
283                    return focused;
284                }
285                return mRowsFragment.getVerticalGridView();
286            } else if (focused == mSearchOrbView && direction == View.FOCUS_DOWN) {
287                return mShowingHeaders ? mHeadersFragment.getVerticalGridView() :
288                    mRowsFragment.getVerticalGridView();
289
290            } else if (focused != mSearchOrbView && mSearchOrbView.getVisibility() == View.VISIBLE
291                    && direction == View.FOCUS_UP) {
292                return mSearchOrbView;
293
294            } else {
295                return null;
296            }
297        }
298    };
299
300    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
301            new BrowseFrameLayout.OnChildFocusListener() {
302        @Override
303        public void onRequestChildFocus(View child, View focused) {
304            int childId = child.getId();
305            if (mHeadersTransition != null) return;
306            if (childId == R.id.browse_container_dock && mShowingHeaders) {
307                mShowingHeaders = false;
308                onHeadersTransitionStart(false);
309                sTransitionHelper.runTransition(mSceneWithoutHeaders, mHeadersTransition);
310            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
311                mShowingHeaders = true;
312                //mHeadersFragment.getView().setAlpha(1f);
313                onHeadersTransitionStart(true);
314                sTransitionHelper.runTransition(mSceneWithHeaders, mHeadersTransition);
315            }
316        }
317    };
318
319    @Override
320    public void onCreate(Bundle savedInstanceState) {
321        super.onCreate(savedInstanceState);
322        TypedArray ta = getActivity().obtainStyledAttributes(R.styleable.LeanbackTheme);
323        mContainerListMarginLeft = (int) ta.getDimension(
324                R.styleable.LeanbackTheme_browseRowsMarginStart, 0);
325        mContainerListAlignTop = (int) ta.getDimension(
326                R.styleable.LeanbackTheme_browseRowsMarginTop, 0);
327        ta.recycle();
328        mHeadersTransitionStartDelay = getResources()
329                .getInteger(R.integer.lb_browse_headers_transition_delay);
330    }
331
332    @Override
333    public View onCreateView(LayoutInflater inflater, ViewGroup container,
334            Bundle savedInstanceState) {
335        if (getChildFragmentManager().findFragmentById(R.id.browse_container_dock) == null) {
336            mRowsFragment = new RowsFragment();
337            mHeadersFragment = new HeadersFragment();
338            getChildFragmentManager().beginTransaction()
339                    .replace(R.id.browse_headers_dock, mHeadersFragment)
340                    .replace(R.id.browse_container_dock, mRowsFragment).commit();
341        } else {
342            mHeadersFragment = (HeadersFragment) getChildFragmentManager()
343                    .findFragmentById(R.id.browse_headers_dock);
344            mRowsFragment = (RowsFragment) getChildFragmentManager()
345                    .findFragmentById(R.id.browse_container_dock);
346        }
347        mRowsFragment.setAdapter(mAdapter);
348        if (mHeaderPresenterSelector != null) {
349            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
350        }
351        mHeadersFragment.setAdapter(mAdapter);
352
353        mRowsFragment.setOnItemSelectedListener(mRowSelectedListener);
354        mHeadersFragment.setOnItemSelectedListener(mHeaderSelectedListener);
355        mHeadersFragment.setOnHeaderClickedListener(mHeaderClickedListener);
356        mRowsFragment.setOnItemClickedListener(mOnItemClickedListener);
357
358        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
359
360        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
361        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
362        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
363
364        mBrowseTitle = (ViewGroup) root.findViewById(R.id.browse_title_group);
365        mBadgeView = (ImageView) mBrowseTitle.findViewById(R.id.browse_badge);
366        mTitleView = (TextView) mBrowseTitle.findViewById(R.id.browse_title);
367        mSearchOrbView = (SearchOrbView) mBrowseTitle.findViewById(R.id.browse_orb);
368        if (mExternalOnSearchClickedListener != null) {
369            mSearchOrbView.setOnOrbClickedListener(mExternalOnSearchClickedListener);
370        }
371
372        readArguments(getArguments());
373        if (mParams != null) {
374            setBadgeDrawable(mParams.mBadgeDrawable);
375            setTitle(mParams.mTitle);
376            setHeadersState(mParams.mHeadersState);
377        }
378
379        mSceneWithTitle = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
380            @Override
381            public void run() {
382                showTitle(true);
383            }
384        });
385        mSceneWithoutTitle = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
386            @Override
387            public void run() {
388                showTitle(false);
389            }
390        });
391        mSceneWithHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
392            @Override
393            public void run() {
394                showHeaders(true);
395            }
396        });
397        mSceneWithoutHeaders =  sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
398            @Override
399            public void run() {
400                showHeaders(false);
401            }
402        });
403        mTitleTransition = sTransitionHelper.createAutoTransition();
404        sTransitionHelper.excludeChildren(mTitleTransition, R.id.browse_headers, true);
405        sTransitionHelper.excludeChildren(mTitleTransition, R.id.container_list, true);
406
407        return root;
408    }
409
410    private void createHeadersTransition(boolean withHeaders) {
411        ArrayList<View> fastHeaders = new ArrayList<View>();
412        ArrayList<Integer> fastHeaderPositions = new ArrayList<Integer>();
413        ArrayList<View> headers = new ArrayList<View>();
414        ArrayList<Integer> headerPositions = new ArrayList<Integer>();
415
416        mHeadersFragment.getHeaderViews(fastHeaders, fastHeaderPositions);
417        mRowsFragment.getHeaderViews(headers, headerPositions);
418
419        mHeadersTransition = sTransitionHelper.createTransitionSet(true);
420        sTransitionHelper.excludeChildren(mHeadersTransition, R.id.browse_title_group, true);
421        Object changeBounds = sTransitionHelper.createChangeBounds(true);
422        Object fadeIn = sTransitionHelper.createFadeTransition(TransitionHelper.FADE_IN);
423        Object fadeOut = sTransitionHelper.createFadeTransition(TransitionHelper.FADE_OUT);
424        if (!withHeaders) {
425            sTransitionHelper.setChangeBoundsDefaultStartDelay(changeBounds,
426                    mHeadersTransitionStartDelay);
427        }
428
429        for (int i = 0; i < headerPositions.size(); i++) {
430            Integer position = headerPositions.get(i);
431            if (position == mSelectedPosition) {
432                headers.get(i).setId(sReparentHeaderId);
433                sTransitionHelper.setChangeBoundsStartDelay(changeBounds, sReparentHeaderId,
434                        withHeaders ? mHeadersTransitionStartDelay : 0);
435                sTransitionHelper.exclude(fadeIn, headers.get(i), true);
436                sTransitionHelper.exclude(fadeOut, headers.get(i), true);
437            } else {
438                headers.get(i).setId(View.NO_ID);
439            }
440        }
441        for (int i = 0; i < fastHeaderPositions.size(); i++) {
442            Integer position = fastHeaderPositions.get(i);
443            if (position == mSelectedPosition) {
444                fastHeaders.get(i).setId(sReparentHeaderId);
445                sTransitionHelper.setChangeBoundsStartDelay(changeBounds, sReparentHeaderId,
446                        withHeaders ? mHeadersTransitionStartDelay : 0);
447                sTransitionHelper.exclude(fadeIn, fastHeaders.get(i), true);
448                sTransitionHelper.exclude(fadeOut, fastHeaders.get(i), true);
449            } else {
450                fastHeaders.get(i).setId(View.NO_ID);
451            }
452        }
453
454        sTransitionHelper.addTransition(mHeadersTransition, fadeOut);
455        sTransitionHelper.addTransition(mHeadersTransition, changeBounds);
456        sTransitionHelper.addTransition(mHeadersTransition, fadeIn);
457
458        sTransitionHelper.setTransitionCompleteListener(mHeadersTransition, new Runnable() {
459            @Override
460            public void run() {
461                mHeadersTransition = null;
462                // TODO: deal fragment destroy view properly
463                VerticalGridView rowsGridView = mRowsFragment.getVerticalGridView();
464                if (rowsGridView != null) {
465                    rowsGridView.setAnimateChildLayout(true);
466                    rowsGridView.setFocusSearchDisabled(false);
467                    if (!mShowingHeaders && !rowsGridView.hasFocus()) {
468                        rowsGridView.requestFocus();
469                    }
470                }
471                VerticalGridView headerGridView = mHeadersFragment.getVerticalGridView();
472                if (headerGridView != null) {
473                    headerGridView.setFocusSearchDisabled(false);
474                    headerGridView.invalidate();
475                    if (mShowingHeaders && !headerGridView.hasFocus()) {
476                        headerGridView.requestFocus();
477                    }
478                }
479            }
480        });
481    }
482
483    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
484        mHeaderPresenterSelector = headerPresenterSelector;
485        if (mHeadersFragment != null) {
486            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
487        }
488    }
489
490    private void showTitle(boolean show) {
491        mBrowseTitle.setVisibility(show ? View.VISIBLE : View.GONE);
492    }
493
494    private void showHeaders(boolean show) {
495        if (DEBUG) Log.v(TAG, "showHeaders " + show);
496        mHeadersFragment.setHeadersVisiblity(show);
497
498        View containerList = mRowsFragment.getView();
499        MarginLayoutParams lp;
500        lp = (MarginLayoutParams) containerList.getLayoutParams();
501        lp.leftMargin = show ? mContainerListMarginLeft : 0;
502        containerList.setLayoutParams(lp);
503        mRowsFragment.setExpand(!show);
504    }
505
506    private HeadersFragment.OnHeaderClickedListener mHeaderClickedListener =
507        new HeadersFragment.OnHeaderClickedListener() {
508            @Override
509            public void onHeaderClicked() {
510                if (!mCanShowHeaders || !mShowingHeaders) return;
511
512                if (mHeadersTransition != null) {
513                    return;
514                }
515                mShowingHeaders = false;
516                onHeadersTransitionStart(false);
517                sTransitionHelper.runTransition(mSceneWithoutHeaders, mHeadersTransition);
518                mRowsFragment.getVerticalGridView().requestFocus();
519            }
520        };
521
522    private OnItemSelectedListener mRowSelectedListener = new OnItemSelectedListener() {
523        @Override
524        public void onItemSelected(Object item, Row row) {
525            int position = mRowsFragment.getVerticalGridView().getSelectedPosition();
526            if (DEBUG) Log.v(TAG, "row selected position " + position);
527            onRowSelected(position);
528            if (mExternalOnItemSelectedListener != null) {
529                mExternalOnItemSelectedListener.onItemSelected(item, row);
530            }
531        }
532    };
533
534    private OnItemSelectedListener mHeaderSelectedListener = new OnItemSelectedListener() {
535        @Override
536        public void onItemSelected(Object item, Row row) {
537            int position = mHeadersFragment.getVerticalGridView().getSelectedPosition();
538            if (DEBUG) Log.v(TAG, "header selected position " + position);
539            onRowSelected(position);
540        }
541    };
542
543    private void onRowSelected(int position) {
544        if (position != mSelectedPosition) {
545            mSetSelectionRunnable.mPosition = position;
546            mBrowseFrame.getHandler().post(mSetSelectionRunnable);
547
548            if (position == 0) {
549                if (!mShowingTitle) {
550                    sTransitionHelper.runTransition(mSceneWithTitle, mTitleTransition);
551                    mShowingTitle = true;
552                }
553            } else if (mShowingTitle) {
554                sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleTransition);
555                mShowingTitle = false;
556            }
557        }
558    }
559
560    private class SetSelectionRunnable implements Runnable {
561        int mPosition;
562        @Override
563        public void run() {
564            setSelection(mPosition);
565        }
566    }
567
568    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
569
570    private void setSelection(int position) {
571        if (position != NO_POSITION) {
572            mRowsFragment.setSelectedPosition(position);
573            mHeadersFragment.setSelectedPosition(position);
574        }
575        mSelectedPosition = position;
576    }
577
578    private void setVerticalVerticalGridViewLayout(VerticalGridView listview, int extraOffset) {
579        // align the top edge of item to a fixed position
580        listview.setItemAlignmentOffset(0);
581        listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
582        listview.setWindowAlignmentOffset(mContainerListAlignTop + extraOffset);
583        listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
584        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
585    }
586
587    /**
588     * Setup dimensions that are only meaningful when the child Fragments are inside
589     * BrowseFragment.
590     */
591    private void setupChildFragmentsLayout() {
592        VerticalGridView headerList = mHeadersFragment.getVerticalGridView();
593        VerticalGridView containerList = mRowsFragment.getVerticalGridView();
594
595        // Both fragments list view has the same alignment
596        setVerticalVerticalGridViewLayout(headerList, 16);
597        setVerticalVerticalGridViewLayout(containerList, 0);
598    }
599
600    @Override
601    public void onStart() {
602        super.onStart();
603        setupChildFragmentsLayout();
604        if (mCanShowHeaders && mShowingHeaders && mHeadersFragment.getView() != null) {
605            mHeadersFragment.getView().requestFocus();
606        } else if ((!mCanShowHeaders || !mShowingHeaders)
607                && mRowsFragment.getView() != null) {
608            mRowsFragment.getView().requestFocus();
609        }
610        showHeaders(mCanShowHeaders && mShowingHeaders);
611    }
612
613    private void readArguments(Bundle args) {
614        if (args == null) {
615            return;
616        }
617        if (args.containsKey(ARG_TITLE)) {
618            setTitle(args.getString(ARG_TITLE));
619        }
620
621        if (args.containsKey(ARG_BADGE_URI)) {
622            setBadgeUri(args.getString(ARG_BADGE_URI));
623        }
624
625        if (args.containsKey(ARG_HEADERS_STATE)) {
626            setHeadersState(args.getInt(ARG_HEADERS_STATE));
627        }
628    }
629
630    private void setBadgeUri(String badgeUri) {
631        // TODO - need a drawable downloader
632    }
633
634    private void setBadgeDrawable(Drawable drawable) {
635        if (mBadgeView == null) {
636            return;
637        }
638        mBadgeView.setImageDrawable(drawable);
639        if (drawable != null) {
640            mBadgeView.setVisibility(View.VISIBLE);
641        } else {
642            mBadgeView.setVisibility(View.GONE);
643        }
644    }
645
646    private void setTitle(String title) {
647        if (mTitleView != null) {
648            mTitleView.setText(title);
649        }
650    }
651
652    private void setHeadersState(int headersState) {
653        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
654        switch (headersState) {
655            case HEADERS_ENABLED:
656                mCanShowHeaders = true;
657                mShowingHeaders = true;
658                break;
659            case HEADERS_HIDDEN:
660                mCanShowHeaders = true;
661                mShowingHeaders = false;
662                break;
663            case HEADERS_DISABLED:
664                mCanShowHeaders = false;
665                mShowingHeaders = false;
666                break;
667            default:
668                Log.w(TAG, "Unknown headers state: " + headersState);
669                break;
670        }
671    }
672}
673