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