ToolbarWidgetWrapper.java revision e021e6ed8931a0a8296af182fc9b0c76b64fb0c4
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package com.android.internal.widget;
19
20import android.animation.Animator;
21import android.animation.AnimatorListenerAdapter;
22import android.app.ActionBar;
23import android.content.Context;
24import android.content.res.TypedArray;
25import android.graphics.drawable.Drawable;
26import android.os.Parcelable;
27import android.util.Log;
28import android.util.SparseArray;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.View;
32import android.view.ViewGroup;
33import android.view.Window;
34import android.widget.ActionMenuPresenter;
35import android.widget.AdapterView;
36import android.widget.Spinner;
37import android.widget.SpinnerAdapter;
38import android.widget.Toolbar;
39import com.android.internal.R;
40import com.android.internal.view.menu.ActionMenuItem;
41import com.android.internal.view.menu.MenuBuilder;
42import com.android.internal.view.menu.MenuPresenter;
43
44/**
45 * Internal class used to interact with the Toolbar widget without
46 * exposing interface methods to the public API.
47 *
48 * <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
49 * so that either variant acting as a
50 * {@link com.android.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
51 * in the same way.</p>
52 *
53 * @hide
54 */
55public class ToolbarWidgetWrapper implements DecorToolbar {
56    private static final String TAG = "ToolbarWidgetWrapper";
57
58    private static final int AFFECTS_LOGO_MASK =
59            ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
60
61    private Toolbar mToolbar;
62
63    private int mDisplayOpts;
64    private View mTabView;
65    private Spinner mSpinner;
66    private View mCustomView;
67
68    private Drawable mIcon;
69    private Drawable mLogo;
70    private Drawable mNavIcon;
71
72    private boolean mTitleSet;
73    private CharSequence mTitle;
74    private CharSequence mSubtitle;
75
76    private Window.Callback mWindowCallback;
77    private boolean mMenuPrepared;
78    private ActionMenuPresenter mActionMenuPresenter;
79
80    public ToolbarWidgetWrapper(Toolbar toolbar) {
81        mToolbar = toolbar;
82
83        final TypedArray a = toolbar.getContext().obtainStyledAttributes(null,
84                R.styleable.ActionBar, R.attr.actionBarStyle, 0);
85
86        final CharSequence title = a.getText(R.styleable.ActionBar_title);
87        if (title != null) {
88            setTitle(title);
89        }
90
91        final CharSequence subtitle = a.getText(R.styleable.ActionBar_subtitle);
92        if (subtitle != null) {
93            setSubtitle(subtitle);
94        }
95
96        final Drawable logo = a.getDrawable(R.styleable.ActionBar_logo);
97        if (logo != null) {
98            setLogo(logo);
99        }
100
101        final Drawable icon = a.getDrawable(R.styleable.ActionBar_icon);
102        if (icon != null) {
103            setIcon(icon);
104        }
105
106        final Drawable navIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
107        if (navIcon != null) {
108            setNavigationIcon(navIcon);
109        }
110
111        setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0));
112
113        final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
114        if (customNavId != 0) {
115            setCustomView(LayoutInflater.from(mToolbar.getContext()).inflate(customNavId,
116                    mToolbar, false));
117            setDisplayOptions(mDisplayOpts | ActionBar.DISPLAY_SHOW_CUSTOM);
118        }
119
120        final int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
121        if (height > 0) {
122            final ViewGroup.LayoutParams lp = mToolbar.getLayoutParams();
123            lp.height = height;
124            mToolbar.setLayoutParams(lp);
125        }
126
127        final int contentInsetStart = a.getDimensionPixelOffset(
128                R.styleable.ActionBar_contentInsetStart, 0);
129        final int contentInsetEnd = a.getDimensionPixelOffset(
130                R.styleable.ActionBar_contentInsetEnd, 0);
131        if (contentInsetStart > 0 || contentInsetEnd > 0) {
132            mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd);
133        }
134
135        a.recycle();
136
137        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
138            final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
139                    0, android.R.id.home, 0, 0, mTitle);
140            @Override
141            public void onClick(View v) {
142                if (mWindowCallback != null && mMenuPrepared) {
143                    mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mNavItem);
144                }
145            }
146        });
147    }
148
149    @Override
150    public ViewGroup getViewGroup() {
151        return mToolbar;
152    }
153
154    @Override
155    public Context getContext() {
156        return mToolbar.getContext();
157    }
158
159    @Override
160    public boolean isSplit() {
161        return false;
162    }
163
164    @Override
165    public boolean hasExpandedActionView() {
166        return mToolbar.hasExpandedActionView();
167    }
168
169    @Override
170    public void collapseActionView() {
171        mToolbar.collapseActionView();
172    }
173
174    @Override
175    public void setWindowCallback(Window.Callback cb) {
176        mWindowCallback = cb;
177    }
178
179    @Override
180    public void setWindowTitle(CharSequence title) {
181        // "Real" title always trumps window title.
182        if (!mTitleSet) {
183            setTitleInt(title);
184        }
185    }
186
187    @Override
188    public CharSequence getTitle() {
189        return mToolbar.getTitle();
190    }
191
192    @Override
193    public void setTitle(CharSequence title) {
194        mTitleSet = true;
195        setTitleInt(title);
196    }
197
198    private void setTitleInt(CharSequence title) {
199        mTitle = title;
200        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
201            mToolbar.setTitle(title);
202        }
203    }
204
205    @Override
206    public CharSequence getSubtitle() {
207        return mToolbar.getSubtitle();
208    }
209
210    @Override
211    public void setSubtitle(CharSequence subtitle) {
212        mSubtitle = subtitle;
213        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
214            mToolbar.setSubtitle(subtitle);
215        }
216    }
217
218    @Override
219    public void initProgress() {
220        Log.i(TAG, "Progress display unsupported");
221    }
222
223    @Override
224    public void initIndeterminateProgress() {
225        Log.i(TAG, "Progress display unsupported");
226    }
227
228    @Override
229    public boolean canSplit() {
230        return false;
231    }
232
233    @Override
234    public void setSplitView(ViewGroup splitView) {
235    }
236
237    @Override
238    public void setSplitToolbar(boolean split) {
239        if (split) {
240            throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar");
241        }
242    }
243
244    @Override
245    public void setSplitWhenNarrow(boolean splitWhenNarrow) {
246        // Ignore.
247    }
248
249    @Override
250    public boolean hasIcon() {
251        return mIcon != null;
252    }
253
254    @Override
255    public boolean hasLogo() {
256        return mLogo != null;
257    }
258
259    @Override
260    public void setIcon(int resId) {
261        setIcon(resId != 0 ? getContext().getDrawable(resId) : null);
262    }
263
264    @Override
265    public void setIcon(Drawable d) {
266        mIcon = d;
267        updateToolbarLogo();
268    }
269
270    @Override
271    public void setLogo(int resId) {
272        setLogo(resId != 0 ? getContext().getDrawable(resId) : null);
273    }
274
275    @Override
276    public void setLogo(Drawable d) {
277        mLogo = d;
278        updateToolbarLogo();
279    }
280
281    private void updateToolbarLogo() {
282        Drawable logo = null;
283        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_HOME) != 0) {
284            if ((mDisplayOpts & ActionBar.DISPLAY_USE_LOGO) != 0) {
285                logo = mLogo != null ? mLogo : mIcon;
286            } else {
287                logo = mIcon;
288            }
289        }
290        mToolbar.setLogo(logo);
291    }
292
293    @Override
294    public boolean canShowOverflowMenu() {
295        return mToolbar.canShowOverflowMenu();
296    }
297
298    @Override
299    public boolean isOverflowMenuShowing() {
300        return mToolbar.isOverflowMenuShowing();
301    }
302
303    @Override
304    public boolean isOverflowMenuShowPending() {
305        return mToolbar.isOverflowMenuShowPending();
306    }
307
308    @Override
309    public boolean showOverflowMenu() {
310        return mToolbar.showOverflowMenu();
311    }
312
313    @Override
314    public boolean hideOverflowMenu() {
315        return mToolbar.hideOverflowMenu();
316    }
317
318    @Override
319    public void setMenuPrepared() {
320        mMenuPrepared = true;
321    }
322
323    @Override
324    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
325        if (mActionMenuPresenter == null) {
326            mActionMenuPresenter = new ActionMenuPresenter(mToolbar.getContext());
327            mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
328        }
329        mActionMenuPresenter.setCallback(cb);
330        mToolbar.setMenu((MenuBuilder) menu, mActionMenuPresenter);
331    }
332
333    @Override
334    public void dismissPopupMenus() {
335        mToolbar.dismissPopupMenus();
336    }
337
338    @Override
339    public int getDisplayOptions() {
340        return mDisplayOpts;
341    }
342
343    @Override
344    public void setDisplayOptions(int newOpts) {
345        final int oldOpts = mDisplayOpts;
346        final int changed = oldOpts ^ newOpts;
347        mDisplayOpts = newOpts;
348        if (changed != 0) {
349            if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
350                if ((newOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
351                    mToolbar.setNavigationIcon(mNavIcon);
352                } else {
353                    mToolbar.setNavigationIcon(null);
354                }
355            }
356
357            if ((changed & AFFECTS_LOGO_MASK) != 0) {
358                updateToolbarLogo();
359            }
360
361            if ((changed & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
362                if ((newOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
363                    mToolbar.setTitle(mTitle);
364                    mToolbar.setSubtitle(mSubtitle);
365                } else {
366                    mToolbar.setTitle(null);
367                    mToolbar.setSubtitle(null);
368                }
369            }
370
371            if ((changed & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomView != null) {
372                if ((newOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
373                    mToolbar.addView(mCustomView);
374                } else {
375                    mToolbar.removeView(mCustomView);
376                }
377            }
378        }
379    }
380
381    @Override
382    public void setEmbeddedTabView(View tabView) {
383        mTabView = tabView;
384    }
385
386    @Override
387    public boolean hasEmbeddedTabs() {
388        return mTabView != null;
389    }
390
391    @Override
392    public boolean isTitleTruncated() {
393        return mToolbar.isTitleTruncated();
394    }
395
396    @Override
397    public void setCollapsible(boolean collapsible) {
398        // Ignore
399    }
400
401    @Override
402    public void setHomeButtonEnabled(boolean enable) {
403        // Ignore
404    }
405
406    @Override
407    public int getNavigationMode() {
408        return 0;
409    }
410
411    @Override
412    public void setNavigationMode(int mode) {
413        if (mode != ActionBar.NAVIGATION_MODE_STANDARD) {
414            throw new IllegalArgumentException(
415                    "Navigation modes not supported in this configuration");
416        }
417    }
418
419    @Override
420    public void setDropdownParams(SpinnerAdapter adapter,
421            AdapterView.OnItemSelectedListener listener) {
422        if (mSpinner == null) {
423            mSpinner = new Spinner(getContext());
424        }
425        mSpinner.setAdapter(adapter);
426        mSpinner.setOnItemSelectedListener(listener);
427    }
428
429    @Override
430    public void setDropdownSelectedPosition(int position) {
431        if (mSpinner == null) {
432            throw new IllegalStateException(
433                    "Can't set dropdown selected position without an adapter");
434        }
435        mSpinner.setSelection(position);
436    }
437
438    @Override
439    public int getDropdownSelectedPosition() {
440        return mSpinner != null ? mSpinner.getSelectedItemPosition() : 0;
441    }
442
443    @Override
444    public int getDropdownItemCount() {
445        return mSpinner != null ? mSpinner.getCount() : 0;
446    }
447
448    @Override
449    public void setCustomView(View view) {
450        if (mCustomView != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
451            mToolbar.removeView(mCustomView);
452        }
453        mCustomView = view;
454        if (view != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
455            mToolbar.addView(mCustomView);
456        }
457    }
458
459    @Override
460    public View getCustomView() {
461        return mCustomView;
462    }
463
464    @Override
465    public void animateToVisibility(int visibility) {
466        if (visibility == View.GONE) {
467            mToolbar.animate().translationY(mToolbar.getHeight()).alpha(0)
468                    .setListener(new AnimatorListenerAdapter() {
469                        private boolean mCanceled = false;
470                        @Override
471                        public void onAnimationEnd(Animator animation) {
472                            if (!mCanceled) {
473                                mToolbar.setVisibility(View.GONE);
474                            }
475                        }
476
477                        @Override
478                        public void onAnimationCancel(Animator animation) {
479                            mCanceled = true;
480                        }
481                    });
482        } else if (visibility == View.VISIBLE) {
483            mToolbar.animate().translationY(0).alpha(1)
484                    .setListener(new AnimatorListenerAdapter() {
485                        @Override
486                        public void onAnimationStart(Animator animation) {
487                            mToolbar.setVisibility(View.VISIBLE);
488                        }
489                    });
490        }
491    }
492
493    @Override
494    public void setNavigationIcon(Drawable icon) {
495        mNavIcon = icon;
496        if ((mDisplayOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
497            mToolbar.setNavigationIcon(icon);
498        }
499    }
500
501    @Override
502    public void setNavigationIcon(int resId) {
503        setNavigationIcon(mToolbar.getContext().getDrawable(resId));
504    }
505
506    @Override
507    public void setNavigationContentDescription(CharSequence description) {
508        mToolbar.setNavigationContentDescription(description);
509    }
510
511    @Override
512    public void setNavigationContentDescription(int resId) {
513        mToolbar.setNavigationContentDescription(resId);
514    }
515
516    @Override
517    public void saveHierarchyState(SparseArray<Parcelable> toolbarStates) {
518        mToolbar.saveHierarchyState(toolbarStates);
519    }
520
521    @Override
522    public void restoreHierarchyState(SparseArray<Parcelable> toolbarStates) {
523        mToolbar.restoreHierarchyState(toolbarStates);
524    }
525
526}
527