ToolbarWidgetWrapper.java revision 6bb10554ba3a0b6127402951a477412d961d1072
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.text.TextUtils; 28import android.util.Log; 29import android.util.SparseArray; 30import android.view.Gravity; 31import android.view.LayoutInflater; 32import android.view.Menu; 33import android.view.View; 34import android.view.ViewGroup; 35import android.view.Window; 36import android.widget.ActionMenuPresenter; 37import android.widget.AdapterView; 38import android.widget.Spinner; 39import android.widget.SpinnerAdapter; 40import android.widget.Toolbar; 41import com.android.internal.R; 42import com.android.internal.view.menu.ActionMenuItem; 43import com.android.internal.view.menu.MenuBuilder; 44import com.android.internal.view.menu.MenuPresenter; 45 46/** 47 * Internal class used to interact with the Toolbar widget without 48 * exposing interface methods to the public API. 49 * 50 * <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView 51 * so that either variant acting as a 52 * {@link com.android.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave 53 * in the same way.</p> 54 * 55 * @hide 56 */ 57public class ToolbarWidgetWrapper implements DecorToolbar { 58 private static final String TAG = "ToolbarWidgetWrapper"; 59 60 private static final int AFFECTS_LOGO_MASK = 61 ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO; 62 63 private Toolbar mToolbar; 64 65 private int mDisplayOpts; 66 private View mTabView; 67 private Spinner mSpinner; 68 private View mCustomView; 69 70 private Drawable mIcon; 71 private Drawable mLogo; 72 private Drawable mNavIcon; 73 74 private boolean mTitleSet; 75 private CharSequence mTitle; 76 private CharSequence mSubtitle; 77 78 private Window.Callback mWindowCallback; 79 private boolean mMenuPrepared; 80 private ActionMenuPresenter mActionMenuPresenter; 81 82 private int mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD; 83 84 public ToolbarWidgetWrapper(Toolbar toolbar) { 85 mToolbar = toolbar; 86 87 mTitle = toolbar.getTitle(); 88 mSubtitle = toolbar.getSubtitle(); 89 mTitleSet = !TextUtils.isEmpty(mTitle); 90 91 final TypedArray a = toolbar.getContext().obtainStyledAttributes(null, 92 R.styleable.ActionBar, R.attr.actionBarStyle, 0); 93 94 final CharSequence title = a.getText(R.styleable.ActionBar_title); 95 if (!TextUtils.isEmpty(title)) { 96 setTitle(title); 97 } 98 99 final CharSequence subtitle = a.getText(R.styleable.ActionBar_subtitle); 100 if (!TextUtils.isEmpty(subtitle)) { 101 setSubtitle(subtitle); 102 } 103 104 final Drawable logo = a.getDrawable(R.styleable.ActionBar_logo); 105 if (logo != null) { 106 setLogo(logo); 107 } 108 109 final Drawable icon = a.getDrawable(R.styleable.ActionBar_icon); 110 if (icon != null) { 111 setIcon(icon); 112 } 113 114 final Drawable navIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator); 115 if (navIcon != null) { 116 setNavigationIcon(navIcon); 117 } 118 119 setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0)); 120 121 final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0); 122 if (customNavId != 0) { 123 setCustomView(LayoutInflater.from(mToolbar.getContext()).inflate(customNavId, 124 mToolbar, false)); 125 setDisplayOptions(mDisplayOpts | ActionBar.DISPLAY_SHOW_CUSTOM); 126 } 127 128 final int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0); 129 if (height > 0) { 130 final ViewGroup.LayoutParams lp = mToolbar.getLayoutParams(); 131 lp.height = height; 132 mToolbar.setLayoutParams(lp); 133 } 134 135 final int contentInsetStart = a.getDimensionPixelOffset( 136 R.styleable.ActionBar_contentInsetStart, 0); 137 final int contentInsetEnd = a.getDimensionPixelOffset( 138 R.styleable.ActionBar_contentInsetEnd, 0); 139 if (contentInsetStart > 0 || contentInsetEnd > 0) { 140 mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd); 141 } 142 143 final int titleTextStyle = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0); 144 if (titleTextStyle != 0) { 145 mToolbar.setTitleTextAppearance(mToolbar.getContext(), titleTextStyle); 146 } 147 148 final int subtitleTextStyle = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0); 149 if (subtitleTextStyle != 0) { 150 mToolbar.setSubtitleTextAppearance(mToolbar.getContext(), subtitleTextStyle); 151 } 152 153 a.recycle(); 154 155 mToolbar.setNavigationOnClickListener(new View.OnClickListener() { 156 final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(), 157 0, android.R.id.home, 0, 0, mTitle); 158 @Override 159 public void onClick(View v) { 160 if (mWindowCallback != null && mMenuPrepared) { 161 mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mNavItem); 162 } 163 } 164 }); 165 } 166 167 @Override 168 public ViewGroup getViewGroup() { 169 return mToolbar; 170 } 171 172 @Override 173 public Context getContext() { 174 return mToolbar.getContext(); 175 } 176 177 @Override 178 public boolean isSplit() { 179 return false; 180 } 181 182 @Override 183 public boolean hasExpandedActionView() { 184 return mToolbar.hasExpandedActionView(); 185 } 186 187 @Override 188 public void collapseActionView() { 189 mToolbar.collapseActionView(); 190 } 191 192 @Override 193 public void setWindowCallback(Window.Callback cb) { 194 mWindowCallback = cb; 195 } 196 197 @Override 198 public void setWindowTitle(CharSequence title) { 199 // "Real" title always trumps window title. 200 if (!mTitleSet) { 201 setTitleInt(title); 202 } 203 } 204 205 @Override 206 public CharSequence getTitle() { 207 return mToolbar.getTitle(); 208 } 209 210 @Override 211 public void setTitle(CharSequence title) { 212 mTitleSet = true; 213 setTitleInt(title); 214 } 215 216 private void setTitleInt(CharSequence title) { 217 mTitle = title; 218 if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) { 219 mToolbar.setTitle(title); 220 } 221 } 222 223 @Override 224 public CharSequence getSubtitle() { 225 return mToolbar.getSubtitle(); 226 } 227 228 @Override 229 public void setSubtitle(CharSequence subtitle) { 230 mSubtitle = subtitle; 231 if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) { 232 mToolbar.setSubtitle(subtitle); 233 } 234 } 235 236 @Override 237 public void initProgress() { 238 Log.i(TAG, "Progress display unsupported"); 239 } 240 241 @Override 242 public void initIndeterminateProgress() { 243 Log.i(TAG, "Progress display unsupported"); 244 } 245 246 @Override 247 public boolean canSplit() { 248 return false; 249 } 250 251 @Override 252 public void setSplitView(ViewGroup splitView) { 253 } 254 255 @Override 256 public void setSplitToolbar(boolean split) { 257 if (split) { 258 throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar"); 259 } 260 } 261 262 @Override 263 public void setSplitWhenNarrow(boolean splitWhenNarrow) { 264 // Ignore. 265 } 266 267 @Override 268 public boolean hasIcon() { 269 return mIcon != null; 270 } 271 272 @Override 273 public boolean hasLogo() { 274 return mLogo != null; 275 } 276 277 @Override 278 public void setIcon(int resId) { 279 setIcon(resId != 0 ? getContext().getDrawable(resId) : null); 280 } 281 282 @Override 283 public void setIcon(Drawable d) { 284 mIcon = d; 285 updateToolbarLogo(); 286 } 287 288 @Override 289 public void setLogo(int resId) { 290 setLogo(resId != 0 ? getContext().getDrawable(resId) : null); 291 } 292 293 @Override 294 public void setLogo(Drawable d) { 295 mLogo = d; 296 updateToolbarLogo(); 297 } 298 299 private void updateToolbarLogo() { 300 Drawable logo = null; 301 if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_HOME) != 0) { 302 if ((mDisplayOpts & ActionBar.DISPLAY_USE_LOGO) != 0) { 303 logo = mLogo != null ? mLogo : mIcon; 304 } else { 305 logo = mIcon; 306 } 307 } 308 mToolbar.setLogo(logo); 309 } 310 311 @Override 312 public boolean canShowOverflowMenu() { 313 return mToolbar.canShowOverflowMenu(); 314 } 315 316 @Override 317 public boolean isOverflowMenuShowing() { 318 return mToolbar.isOverflowMenuShowing(); 319 } 320 321 @Override 322 public boolean isOverflowMenuShowPending() { 323 return mToolbar.isOverflowMenuShowPending(); 324 } 325 326 @Override 327 public boolean showOverflowMenu() { 328 return mToolbar.showOverflowMenu(); 329 } 330 331 @Override 332 public boolean hideOverflowMenu() { 333 return mToolbar.hideOverflowMenu(); 334 } 335 336 @Override 337 public void setMenuPrepared() { 338 mMenuPrepared = true; 339 } 340 341 @Override 342 public void setMenu(Menu menu, MenuPresenter.Callback cb) { 343 if (mActionMenuPresenter == null) { 344 mActionMenuPresenter = new ActionMenuPresenter(mToolbar.getContext()); 345 mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter); 346 } 347 mActionMenuPresenter.setCallback(cb); 348 mToolbar.setMenu((MenuBuilder) menu, mActionMenuPresenter); 349 } 350 351 @Override 352 public void dismissPopupMenus() { 353 mToolbar.dismissPopupMenus(); 354 } 355 356 @Override 357 public int getDisplayOptions() { 358 return mDisplayOpts; 359 } 360 361 @Override 362 public void setDisplayOptions(int newOpts) { 363 final int oldOpts = mDisplayOpts; 364 final int changed = oldOpts ^ newOpts; 365 mDisplayOpts = newOpts; 366 if (changed != 0) { 367 if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) { 368 if ((newOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) { 369 mToolbar.setNavigationIcon(mNavIcon); 370 } else { 371 mToolbar.setNavigationIcon(null); 372 } 373 } 374 375 if ((changed & AFFECTS_LOGO_MASK) != 0) { 376 updateToolbarLogo(); 377 } 378 379 if ((changed & ActionBar.DISPLAY_SHOW_TITLE) != 0) { 380 if ((newOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) { 381 mToolbar.setTitle(mTitle); 382 mToolbar.setSubtitle(mSubtitle); 383 } else { 384 mToolbar.setTitle(null); 385 mToolbar.setSubtitle(null); 386 } 387 } 388 389 if ((changed & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomView != null) { 390 if ((newOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { 391 mToolbar.addView(mCustomView); 392 } else { 393 mToolbar.removeView(mCustomView); 394 } 395 } 396 } 397 } 398 399 @Override 400 public void setEmbeddedTabView(ScrollingTabContainerView tabView) { 401 if (mTabView != null && mTabView.getParent() == mToolbar) { 402 mToolbar.removeView(mTabView); 403 } 404 mTabView = tabView; 405 if (tabView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) { 406 mToolbar.addView(mTabView, 0); 407 Toolbar.LayoutParams lp = (Toolbar.LayoutParams) mTabView.getLayoutParams(); 408 lp.width = ViewGroup.LayoutParams.WRAP_CONTENT; 409 lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 410 lp.gravity = Gravity.START | Gravity.BOTTOM; 411 tabView.setAllowCollapse(true); 412 } 413 } 414 415 @Override 416 public boolean hasEmbeddedTabs() { 417 return mTabView != null; 418 } 419 420 @Override 421 public boolean isTitleTruncated() { 422 return mToolbar.isTitleTruncated(); 423 } 424 425 @Override 426 public void setCollapsible(boolean collapsible) { 427 mToolbar.setCollapsible(collapsible); 428 } 429 430 @Override 431 public void setHomeButtonEnabled(boolean enable) { 432 // Ignore 433 } 434 435 @Override 436 public int getNavigationMode() { 437 return mNavigationMode; 438 } 439 440 @Override 441 public void setNavigationMode(int mode) { 442 final int oldMode = mNavigationMode; 443 if (mode != oldMode) { 444 switch (oldMode) { 445 case ActionBar.NAVIGATION_MODE_LIST: 446 if (mSpinner != null && mSpinner.getParent() == mToolbar) { 447 mToolbar.removeView(mSpinner); 448 } 449 break; 450 case ActionBar.NAVIGATION_MODE_TABS: 451 if (mTabView != null && mTabView.getParent() == mToolbar) { 452 mToolbar.removeView(mTabView); 453 } 454 break; 455 } 456 457 mNavigationMode = mode; 458 459 switch (mode) { 460 case ActionBar.NAVIGATION_MODE_STANDARD: 461 break; 462 case ActionBar.NAVIGATION_MODE_LIST: 463 ensureSpinner(); 464 mToolbar.addView(mSpinner, 0); 465 break; 466 case ActionBar.NAVIGATION_MODE_TABS: 467 if (mTabView != null) { 468 mToolbar.addView(mTabView, 0); 469 Toolbar.LayoutParams lp = (Toolbar.LayoutParams) mTabView.getLayoutParams(); 470 lp.width = ViewGroup.LayoutParams.WRAP_CONTENT; 471 lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 472 lp.gravity = Gravity.START | Gravity.BOTTOM; 473 } 474 break; 475 default: 476 throw new IllegalArgumentException("Invalid navigation mode " + mode); 477 } 478 } 479 } 480 481 private void ensureSpinner() { 482 if (mSpinner == null) { 483 mSpinner = new Spinner(getContext()); 484 Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 485 ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL); 486 mSpinner.setLayoutParams(lp); 487 } 488 } 489 490 @Override 491 public void setDropdownParams(SpinnerAdapter adapter, 492 AdapterView.OnItemSelectedListener listener) { 493 ensureSpinner(); 494 mSpinner.setAdapter(adapter); 495 mSpinner.setOnItemSelectedListener(listener); 496 } 497 498 @Override 499 public void setDropdownSelectedPosition(int position) { 500 if (mSpinner == null) { 501 throw new IllegalStateException( 502 "Can't set dropdown selected position without an adapter"); 503 } 504 mSpinner.setSelection(position); 505 } 506 507 @Override 508 public int getDropdownSelectedPosition() { 509 return mSpinner != null ? mSpinner.getSelectedItemPosition() : 0; 510 } 511 512 @Override 513 public int getDropdownItemCount() { 514 return mSpinner != null ? mSpinner.getCount() : 0; 515 } 516 517 @Override 518 public void setCustomView(View view) { 519 if (mCustomView != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { 520 mToolbar.removeView(mCustomView); 521 } 522 mCustomView = view; 523 if (view != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { 524 mToolbar.addView(mCustomView); 525 } 526 } 527 528 @Override 529 public View getCustomView() { 530 return mCustomView; 531 } 532 533 @Override 534 public void animateToVisibility(int visibility) { 535 if (visibility == View.GONE) { 536 mToolbar.animate().translationY(mToolbar.getHeight()).alpha(0) 537 .setListener(new AnimatorListenerAdapter() { 538 private boolean mCanceled = false; 539 @Override 540 public void onAnimationEnd(Animator animation) { 541 if (!mCanceled) { 542 mToolbar.setVisibility(View.GONE); 543 } 544 } 545 546 @Override 547 public void onAnimationCancel(Animator animation) { 548 mCanceled = true; 549 } 550 }); 551 } else if (visibility == View.VISIBLE) { 552 mToolbar.animate().translationY(0).alpha(1) 553 .setListener(new AnimatorListenerAdapter() { 554 @Override 555 public void onAnimationStart(Animator animation) { 556 mToolbar.setVisibility(View.VISIBLE); 557 } 558 }); 559 } 560 } 561 562 @Override 563 public void setNavigationIcon(Drawable icon) { 564 mNavIcon = icon; 565 if ((mDisplayOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) { 566 mToolbar.setNavigationIcon(icon); 567 } 568 } 569 570 @Override 571 public void setNavigationIcon(int resId) { 572 setNavigationIcon(resId != 0 ? mToolbar.getContext().getDrawable(resId) : null); 573 } 574 575 @Override 576 public void setNavigationContentDescription(CharSequence description) { 577 mToolbar.setNavigationContentDescription(description); 578 } 579 580 @Override 581 public void setNavigationContentDescription(int resId) { 582 mToolbar.setNavigationContentDescription(resId); 583 } 584 585 @Override 586 public void saveHierarchyState(SparseArray<Parcelable> toolbarStates) { 587 mToolbar.saveHierarchyState(toolbarStates); 588 } 589 590 @Override 591 public void restoreHierarchyState(SparseArray<Parcelable> toolbarStates) { 592 mToolbar.restoreHierarchyState(toolbarStates); 593 } 594 595} 596