BrandedFragment.java revision a373804d10f93a9488adc35cf6ce44dce09b3778
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.app.Fragment;
17import android.graphics.drawable.Drawable;
18import android.os.Bundle;
19import android.support.v17.leanback.R;
20import android.support.v17.leanback.widget.SearchOrbView;
21import android.support.v17.leanback.widget.TitleHelper;
22import android.support.v17.leanback.widget.TitleViewAdapter;
23import android.util.TypedValue;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27
28/**
29 * Fragment class for managing search and branding using a view that implements
30 * {@link TitleViewAdapter.Provider}.
31 */
32public class BrandedFragment extends Fragment {
33
34    // BUNDLE attribute for title is showing
35    private static final String TITLE_SHOW = "titleShow";
36
37    private boolean mShowingTitle = true;
38    private CharSequence mTitle;
39    private Drawable mBadgeDrawable;
40    private View mTitleView;
41    private TitleViewAdapter mTitleViewAdapter;
42    private SearchOrbView.Colors mSearchAffordanceColors;
43    private boolean mSearchAffordanceColorSet;
44    private View.OnClickListener mExternalOnSearchClickedListener;
45    private TitleHelper mTitleHelper;
46
47    /**
48     * Called by {@link #installTitleView(LayoutInflater, ViewGroup, Bundle)} to inflate
49     * title view.  Default implementation uses layout file lb_browse_title.
50     * Subclass may override and use its own layout, the layout must have a descendant with id
51     * browse_title_group that implements {@link TitleViewAdapter.Provider}. Subclass may return
52     * null if no title is needed.
53     *
54     * @param inflater           The LayoutInflater object that can be used to inflate
55     *                           any views in the fragment,
56     * @param parent             Parent of title view.
57     * @param savedInstanceState If non-null, this fragment is being re-constructed
58     *                           from a previous saved state as given here.
59     * @return Title view which must have a descendant with id browse_title_group that implements
60     *         {@link TitleViewAdapter.Provider}, or null for no title view.
61     */
62    public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
63                                Bundle savedInstanceState) {
64        TypedValue typedValue = new TypedValue();
65        boolean found = parent.getContext().getTheme().resolveAttribute(
66                R.attr.browseTitleViewLayout, typedValue, true);
67        return inflater.inflate(found ? typedValue.resourceId : R.layout.lb_browse_title,
68                parent, false);
69    }
70
71    /**
72     * Inflate title view and add to parent.  This method should be called in
73     * {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}.
74     * @param inflater The LayoutInflater object that can be used to inflate
75     * any views in the fragment,
76     * @param parent Parent of title view.
77     * @param savedInstanceState If non-null, this fragment is being re-constructed
78     * from a previous saved state as given here.
79     */
80    public void installTitleView(LayoutInflater inflater, ViewGroup parent,
81                            Bundle savedInstanceState) {
82        View titleLayoutRoot = onInflateTitleView(inflater, parent, savedInstanceState);
83        if (titleLayoutRoot != null) {
84            parent.addView(titleLayoutRoot);
85            setTitleView(titleLayoutRoot.findViewById(R.id.browse_title_group));
86        } else {
87            setTitleView(null);
88        }
89    }
90
91    /**
92     * Sets the view that implemented {@link TitleViewAdapter}.
93     * @param titleView The view that implemented {@link TitleViewAdapter.Provider}.
94     */
95    public void setTitleView(View titleView) {
96        mTitleView = titleView;
97        if (mTitleView == null) {
98            mTitleViewAdapter = null;
99            mTitleHelper = null;
100        } else {
101            mTitleViewAdapter = ((TitleViewAdapter.Provider) mTitleView).getTitleViewAdapter();
102            mTitleViewAdapter.setTitle(mTitle);
103            mTitleViewAdapter.setBadgeDrawable(mBadgeDrawable);
104            if (mSearchAffordanceColorSet) {
105                mTitleViewAdapter.setSearchAffordanceColors(mSearchAffordanceColors);
106            }
107            if (mExternalOnSearchClickedListener != null) {
108                setOnSearchClickedListener(mExternalOnSearchClickedListener);
109            }
110            if (getView() instanceof ViewGroup) {
111                mTitleHelper = new TitleHelper((ViewGroup) getView(), mTitleView);
112            }
113        }
114    }
115
116    /**
117     * Returns the view that implements {@link TitleViewAdapter.Provider}.
118     * @return The view that implements {@link TitleViewAdapter.Provider}.
119     */
120    public View getTitleView() {
121        return mTitleView;
122    }
123
124    /**
125     * Returns the {@link TitleViewAdapter} implemented by title view.
126     * @return The {@link TitleViewAdapter} implemented by title view.
127     */
128    public TitleViewAdapter getTitleViewAdapter() {
129        return mTitleViewAdapter;
130    }
131
132    /**
133     * Returns the {@link TitleHelper}.
134     */
135    TitleHelper getTitleHelper() {
136        return mTitleHelper;
137    }
138
139    @Override
140    public void onSaveInstanceState(Bundle outState) {
141        super.onSaveInstanceState(outState);
142        outState.putBoolean(TITLE_SHOW, mShowingTitle);
143    }
144
145    @Override
146    public void onViewCreated(View view, Bundle savedInstanceState) {
147        super.onViewCreated(view, savedInstanceState);
148        if (savedInstanceState != null) {
149            mShowingTitle = savedInstanceState.getBoolean(TITLE_SHOW);
150        }
151        if (mTitleView != null && view instanceof ViewGroup) {
152            mTitleHelper = new TitleHelper((ViewGroup) view, mTitleView);
153        }
154    }
155
156    @Override
157    public void onDestroyView() {
158        super.onDestroyView();
159        mTitleHelper = null;
160    }
161
162    /**
163     * Shows or hides the title view.
164     * @param show True to show title view, false to hide title view.
165     */
166    public void showTitle(boolean show) {
167        // TODO: handle interruptions?
168        if (show == mShowingTitle) {
169            return;
170        }
171        mShowingTitle = show;
172        if (mTitleHelper != null) {
173            mTitleHelper.showTitle(show);
174        }
175    }
176
177    /**
178     * Changes title view's components visibility and shows title.
179     * @param flags Flags representing the visibility of components inside title view.
180     * @see TitleViewAdapter#SEARCH_VIEW_VISIBLE
181     * @see TitleViewAdapter#BRANDING_VIEW_VISIBLE
182     * @see TitleViewAdapter#FULL_VIEW_VISIBLE
183     * @see TitleViewAdapter#updateComponentsVisibility(int)
184     */
185    public void showTitle(int flags) {
186        if (mTitleViewAdapter != null) {
187            mTitleViewAdapter.updateComponentsVisibility(flags);
188        }
189        showTitle(true);
190    }
191
192    /**
193     * Sets the drawable displayed in the fragment title.
194     *
195     * @param drawable The Drawable to display in the fragment title.
196     */
197    public void setBadgeDrawable(Drawable drawable) {
198        if (mBadgeDrawable != drawable) {
199            mBadgeDrawable = drawable;
200            if (mTitleViewAdapter != null) {
201                mTitleViewAdapter.setBadgeDrawable(drawable);
202            }
203        }
204    }
205
206    /**
207     * Returns the badge drawable used in the fragment title.
208     * @return The badge drawable used in the fragment title.
209     */
210    public Drawable getBadgeDrawable() {
211        return mBadgeDrawable;
212    }
213
214    /**
215     * Sets title text for the fragment.
216     *
217     * @param title The title text of the fragment.
218     */
219    public void setTitle(CharSequence title) {
220        mTitle = title;
221        if (mTitleViewAdapter != null) {
222            mTitleViewAdapter.setTitle(title);
223        }
224    }
225
226    /**
227     * Returns the title text for the fragment.
228     * @return Title text for the fragment.
229     */
230    public CharSequence getTitle() {
231        return mTitle;
232    }
233
234    /**
235     * Sets a click listener for the search affordance.
236     *
237     * <p>The presence of a listener will change the visibility of the search
238     * affordance in the fragment title. When set to non-null, the title will
239     * contain an element that a user may click to begin a search.
240     *
241     * <p>The listener's {@link View.OnClickListener#onClick onClick} method
242     * will be invoked when the user clicks on the search element.
243     *
244     * @param listener The listener to call when the search element is clicked.
245     */
246    public void setOnSearchClickedListener(View.OnClickListener listener) {
247        mExternalOnSearchClickedListener = listener;
248        if (mTitleViewAdapter != null) {
249            mTitleViewAdapter.setOnSearchClickedListener(listener);
250        }
251    }
252
253    /**
254     * Sets the {@link android.support.v17.leanback.widget.SearchOrbView.Colors} used to draw the
255     * search affordance.
256     *
257     * @param colors Colors used to draw search affordance.
258     */
259    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
260        mSearchAffordanceColors = colors;
261        mSearchAffordanceColorSet = true;
262        if (mTitleViewAdapter != null) {
263            mTitleViewAdapter.setSearchAffordanceColors(mSearchAffordanceColors);
264        }
265    }
266
267    /**
268     * Returns the {@link android.support.v17.leanback.widget.SearchOrbView.Colors}
269     * used to draw the search affordance.
270     */
271    public SearchOrbView.Colors getSearchAffordanceColors() {
272        if (mSearchAffordanceColorSet) {
273            return mSearchAffordanceColors;
274        }
275        if (mTitleViewAdapter == null) {
276            throw new IllegalStateException("Fragment views not yet created");
277        }
278        return mTitleViewAdapter.getSearchAffordanceColors();
279    }
280
281    /**
282     * Sets the color used to draw the search affordance.
283     * A default brighter color will be set by the framework.
284     *
285     * @param color The color to use for the search affordance.
286     */
287    public void setSearchAffordanceColor(int color) {
288        setSearchAffordanceColors(new SearchOrbView.Colors(color));
289    }
290
291    /**
292     * Returns the color used to draw the search affordance.
293     */
294    public int getSearchAffordanceColor() {
295        return getSearchAffordanceColors().color;
296    }
297
298    @Override
299    public void onStart() {
300        super.onStart();
301        if (mTitleViewAdapter != null) {
302            showTitle(mShowingTitle);
303            mTitleViewAdapter.setAnimationEnabled(true);
304        }
305    }
306
307    @Override
308    public void onPause() {
309        if (mTitleViewAdapter != null) {
310            mTitleViewAdapter.setAnimationEnabled(false);
311        }
312        super.onPause();
313    }
314
315    @Override
316    public void onResume() {
317        super.onResume();
318        if (mTitleViewAdapter != null) {
319            mTitleViewAdapter.setAnimationEnabled(true);
320        }
321    }
322
323    /**
324     * Returns true/false to indicate the visibility of TitleView.
325     *
326     * @return boolean to indicate whether or not it's showing the title.
327     */
328    public final boolean isShowingTitle() {
329        return mShowingTitle;
330    }
331
332}
333