AppCompatDelegateImplV7.java revision 61c0bbe56a13fe55ce91a5b1d64e751164ecb894
1/* 2 * Copyright (C) 2013 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 17package android.support.v7.app; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.content.res.Resources; 22import android.content.res.TypedArray; 23import android.os.Bundle; 24import android.support.v4.app.NavUtils; 25import android.support.v4.view.ViewConfigurationCompat; 26import android.support.v4.view.WindowCompat; 27import android.support.v7.appcompat.R; 28import android.support.v7.internal.app.ToolbarActionBar; 29import android.support.v7.internal.app.WindowCallback; 30import android.support.v7.internal.app.WindowDecorActionBar; 31import android.support.v7.internal.view.menu.ListMenuPresenter; 32import android.support.v7.internal.view.menu.MenuBuilder; 33import android.support.v7.internal.view.menu.MenuPresenter; 34import android.support.v7.internal.view.menu.MenuView; 35import android.support.v7.internal.view.menu.MenuWrapperFactory; 36import android.support.v7.internal.widget.DecorContentParent; 37import android.support.v7.internal.widget.ProgressBarCompat; 38import android.support.v7.view.ActionMode; 39import android.support.v7.widget.Toolbar; 40import android.util.AttributeSet; 41import android.util.DisplayMetrics; 42import android.util.TypedValue; 43import android.view.ContextThemeWrapper; 44import android.view.LayoutInflater; 45import android.view.Menu; 46import android.view.MenuItem; 47import android.view.View; 48import android.view.ViewConfiguration; 49import android.view.ViewGroup; 50import android.view.Window; 51import android.widget.FrameLayout; 52 53class ActionBarActivityDelegateBase extends ActionBarActivityDelegate implements 54 MenuPresenter.Callback, MenuBuilder.Callback { 55 private static final String TAG = "ActionBarActivityDelegateBase"; 56 57 private static final int[] ACTION_BAR_DRAWABLE_TOGGLE_ATTRS = new int[] { 58 R.attr.homeAsUpIndicator 59 }; 60 61 private DecorContentParent mDecorContentParent; 62 private ListMenuPresenter mListMenuPresenter; 63 private MenuBuilder mMenu; 64 65 private ActionMode mActionMode; 66 67 // true if we have installed a window sub-decor layout. 68 private boolean mSubDecorInstalled; 69 70 private CharSequence mTitleToSet; 71 72 // Used to keep track of Progress Bar Window features 73 private boolean mFeatureProgress, mFeatureIndeterminateProgress; 74 75 // Used for emulating PanelFeatureState 76 private boolean mClosingActionMenu; 77 private boolean mPanelIsPrepared; 78 private boolean mPanelRefreshContent; 79 private Bundle mPanelFrozenActionViewState; 80 81 private boolean mEnableDefaultActionBarUp; 82 83 ActionBarActivityDelegateBase(ActionBarActivity activity) { 84 super(activity); 85 } 86 87 @Override 88 void onCreate(Bundle savedInstanceState) { 89 super.onCreate(savedInstanceState); 90 91 if (NavUtils.getParentActivityName(mActivity) != null) { 92 ActionBar ab = getSupportActionBar(); 93 if (ab == null) { 94 mEnableDefaultActionBarUp = true; 95 } else { 96 ab.setDefaultDisplayHomeAsUpEnabled(true); 97 } 98 } 99 } 100 101 @Override 102 public ActionBar createSupportActionBar() { 103 ensureSubDecor(); 104 ActionBar ab = new WindowDecorActionBar(mActivity, mOverlayActionBar); 105 ab.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp); 106 return ab; 107 } 108 109 @Override 110 void setSupportActionBar(Toolbar toolbar) { 111 if (getSupportActionBar() instanceof WindowDecorActionBar) { 112 throw new IllegalStateException("This Activity already has an action bar supplied " + 113 "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " + 114 "windowActionBar to false in your theme to use a Toolbar instead."); 115 } 116 ActionBar ab = new ToolbarActionBar(toolbar, mActivity.getTitle(), mWindowMenuCallback); 117 ab.invalidateOptionsMenu(); 118 setSupportActionBar(ab); 119 } 120 121 @Override 122 public void onConfigurationChanged(Configuration newConfig) { 123 // If this is called before sub-decor is installed, ActionBar will not 124 // be properly initialized. 125 if (mHasActionBar && mSubDecorInstalled) { 126 // Note: The action bar will need to access 127 // view changes from superclass. 128 ActionBar ab = getSupportActionBar(); 129 if (ab != null) { 130 ab.onConfigurationChanged(newConfig); 131 } 132 } 133 } 134 135 @Override 136 public void onStop() { 137 ActionBar ab = getSupportActionBar(); 138 if (ab != null) { 139 ab.setShowHideAnimationEnabled(false); 140 } 141 } 142 143 @Override 144 public void onPostResume() { 145 ActionBar ab = getSupportActionBar(); 146 if (ab != null) { 147 ab.setShowHideAnimationEnabled(true); 148 } 149 } 150 151 @Override 152 public void setContentView(View v) { 153 ensureSubDecor(); 154 ViewGroup contentParent = (ViewGroup) mActivity.findViewById(android.R.id.content); 155 contentParent.removeAllViews(); 156 contentParent.addView(v); 157 mActivity.onSupportContentChanged(); 158 } 159 160 @Override 161 public void setContentView(int resId) { 162 ensureSubDecor(); 163 ViewGroup contentParent = (ViewGroup) mActivity.findViewById(android.R.id.content); 164 contentParent.removeAllViews(); 165 mActivity.getLayoutInflater().inflate(resId, contentParent); 166 mActivity.onSupportContentChanged(); 167 } 168 169 @Override 170 public void setContentView(View v, ViewGroup.LayoutParams lp) { 171 ensureSubDecor(); 172 ViewGroup contentParent = (ViewGroup) mActivity.findViewById(android.R.id.content); 173 contentParent.removeAllViews(); 174 contentParent.addView(v, lp); 175 mActivity.onSupportContentChanged(); 176 } 177 178 @Override 179 public void addContentView(View v, ViewGroup.LayoutParams lp) { 180 ensureSubDecor(); 181 ViewGroup contentParent = (ViewGroup) mActivity.findViewById(android.R.id.content); 182 contentParent.addView(v, lp); 183 mActivity.onSupportContentChanged(); 184 } 185 186 @Override 187 public void onContentChanged() { 188 // Ignore all calls to this method as we call onSupportContentChanged manually above 189 } 190 191 final void ensureSubDecor() { 192 if (!mSubDecorInstalled) { 193 if (mHasActionBar) { 194 mActivity.superSetContentView(R.layout.abc_screen_toolbar); 195 196 ViewGroup root = (ViewGroup) mActivity.findViewById(R.id.action_bar_root); 197 if (root != null && root.getChildCount() == 0) { 198 /** 199 * This needs some explanation. As we can not use the android:theme attribute 200 * pre-L, we emulate it by manually creating a LayoutInflater using a 201 * ContextThemeWrapper pointing to actionBarTheme. 202 */ 203 TypedValue outValue = new TypedValue(); 204 mActivity.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true); 205 206 Context themedContext; 207 if (outValue.resourceId != 0) { 208 themedContext = new ContextThemeWrapper(mActivity, outValue.resourceId); 209 } else { 210 themedContext = mActivity; 211 } 212 213 LayoutInflater.from(themedContext) 214 .inflate(R.layout.abc_screen_toolbar_include, root, true); 215 } 216 217 mDecorContentParent = (DecorContentParent) mActivity.findViewById(R.id.decor_content_parent); 218 mDecorContentParent.setWindowCallback(mWindowMenuCallback); 219 220 /** 221 * Propagate features to DecorContentParent 222 */ 223 if (mOverlayActionBar) { 224 mDecorContentParent.initFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); 225 } 226 if (mFeatureProgress) { 227 mDecorContentParent.initFeature(Window.FEATURE_PROGRESS); 228 } 229 if (mFeatureIndeterminateProgress) { 230 mDecorContentParent.initFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 231 } 232 } else { 233 mActivity.superSetContentView(R.layout.abc_screen_simple); 234 } 235 236 // Change our content FrameLayout to use the android.R.id.content id. 237 // Useful for fragments. 238 View content = mActivity.findViewById(android.R.id.content); 239 content.setId(View.NO_ID); 240 View abcContent = mActivity.findViewById(R.id.action_bar_activity_content); 241 abcContent.setId(android.R.id.content); 242 243 // A title was set before we've install the decor so set it now. 244 if (mTitleToSet != null && mDecorContentParent != null) { 245 mDecorContentParent.setWindowTitle(mTitleToSet); 246 mTitleToSet = null; 247 } 248 249 applyFixedSizeWindow(); 250 251 onSubDecorInstalled(); 252 253 mSubDecorInstalled = true; 254 255 // Post supportInvalidateOptionsMenu() so that the menu is invalidated post-onCreate() 256 mActivity.getWindow().getDecorView().post(new Runnable() { 257 @Override 258 public void run() { 259 supportInvalidateOptionsMenu(); 260 } 261 }); 262 } 263 } 264 265 void onSubDecorInstalled() {} 266 267 private void applyFixedSizeWindow() { 268 TypedArray a = mActivity.obtainStyledAttributes(R.styleable.Theme); 269 270 TypedValue mFixedWidthMajor = null; 271 TypedValue mFixedWidthMinor = null; 272 TypedValue mFixedHeightMajor = null; 273 TypedValue mFixedHeightMinor = null; 274 275 if (a.hasValue(R.styleable.Theme_windowFixedWidthMajor)) { 276 if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); 277 a.getValue(R.styleable.Theme_windowFixedWidthMajor, mFixedWidthMajor); 278 } 279 if (a.hasValue(R.styleable.Theme_windowFixedWidthMinor)) { 280 if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); 281 a.getValue(R.styleable.Theme_windowFixedWidthMinor, mFixedWidthMinor); 282 } 283 if (a.hasValue(R.styleable.Theme_windowFixedHeightMajor)) { 284 if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); 285 a.getValue(R.styleable.Theme_windowFixedHeightMajor, mFixedHeightMajor); 286 } 287 if (a.hasValue(R.styleable.Theme_windowFixedHeightMinor)) { 288 if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); 289 a.getValue(R.styleable.Theme_windowFixedHeightMinor, mFixedHeightMinor); 290 } 291 292 final DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics(); 293 final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; 294 int w = ViewGroup.LayoutParams.MATCH_PARENT; 295 int h = ViewGroup.LayoutParams.MATCH_PARENT; 296 297 final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor; 298 if (tvw != null && tvw.type != TypedValue.TYPE_NULL) { 299 if (tvw.type == TypedValue.TYPE_DIMENSION) { 300 w = (int) tvw.getDimension(metrics); 301 } else if (tvw.type == TypedValue.TYPE_FRACTION) { 302 w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels); 303 } 304 } 305 306 final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor; 307 if (tvh != null && tvh.type != TypedValue.TYPE_NULL) { 308 if (tvh.type == TypedValue.TYPE_DIMENSION) { 309 h = (int) tvh.getDimension(metrics); 310 } else if (tvh.type == TypedValue.TYPE_FRACTION) { 311 h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels); 312 } 313 } 314 315 if (w != ViewGroup.LayoutParams.MATCH_PARENT || h != ViewGroup.LayoutParams.MATCH_PARENT) { 316 mActivity.getWindow().setLayout(w, h); 317 } 318 319 a.recycle(); 320 } 321 322 @Override 323 public boolean supportRequestWindowFeature(int featureId) { 324 switch (featureId) { 325 case WindowCompat.FEATURE_ACTION_BAR: 326 mHasActionBar = true; 327 return true; 328 case WindowCompat.FEATURE_ACTION_BAR_OVERLAY: 329 mOverlayActionBar = true; 330 return true; 331 case Window.FEATURE_PROGRESS: 332 mFeatureProgress = true; 333 return true; 334 case Window.FEATURE_INDETERMINATE_PROGRESS: 335 mFeatureIndeterminateProgress = true; 336 return true; 337 default: 338 return mActivity.requestWindowFeature(featureId); 339 } 340 } 341 342 @Override 343 public void onTitleChanged(CharSequence title) { 344 if (mDecorContentParent != null) { 345 mDecorContentParent.setWindowTitle(title); 346 } else if (getSupportActionBar() != null) { 347 getSupportActionBar().setTitle(title); 348 } else { 349 mTitleToSet = title; 350 } 351 } 352 353 @Override 354 public View onCreatePanelView(int featureId) { 355 View createdPanelView = null; 356 357 if (featureId == Window.FEATURE_OPTIONS_PANEL && preparePanel()) { 358 createdPanelView = (View) getListMenuView(mActivity, this); 359 } 360 361 return createdPanelView; 362 } 363 364 @Override 365 public boolean onCreatePanelMenu(int featureId, Menu menu) { 366 if (featureId != Window.FEATURE_OPTIONS_PANEL) { 367 return mActivity.superOnCreatePanelMenu(featureId, menu); 368 } 369 return false; 370 } 371 372 @Override 373 public boolean onPreparePanel(int featureId, View view, Menu menu) { 374 if (featureId != Window.FEATURE_OPTIONS_PANEL) { 375 return mActivity.superOnPreparePanel(featureId, view, menu); 376 } 377 return false; 378 } 379 380 @Override 381 public boolean onMenuItemSelected(int featureId, MenuItem item) { 382 if (featureId == Window.FEATURE_OPTIONS_PANEL) { 383 item = MenuWrapperFactory.createMenuItemWrapper(item); 384 } 385 return mActivity.superOnMenuItemSelected(featureId, item); 386 } 387 388 @Override 389 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 390 return mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); 391 } 392 393 @Override 394 public void onMenuModeChange(MenuBuilder menu) { 395 reopenMenu(menu, true); 396 } 397 398 @Override 399 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 400 if (mClosingActionMenu) { 401 return; 402 } 403 mClosingActionMenu = true; 404 mActivity.closeOptionsMenu(); 405 mDecorContentParent.dismissPopups(); 406 mClosingActionMenu = false; 407 } 408 409 @Override 410 public boolean onOpenSubMenu(MenuBuilder subMenu) { 411 return false; 412 } 413 414 @Override 415 public ActionMode startSupportActionMode(ActionMode.Callback callback) { 416 if (callback == null) { 417 throw new IllegalArgumentException("ActionMode callback can not be null."); 418 } 419 420 if (mActionMode != null) { 421 mActionMode.finish(); 422 } 423 424 final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); 425 426 ActionBar ab = getSupportActionBar(); 427 if (ab != null) { 428 mActionMode = ab.startActionMode(wrappedCallback); 429 } 430 431 if (mActionMode != null) { 432 mActivity.onSupportActionModeStarted(mActionMode); 433 } 434 return mActionMode; 435 } 436 437 @Override 438 public void supportInvalidateOptionsMenu() { 439 final ActionBar ab = getSupportActionBar(); 440 if (ab != null && ab.invalidateOptionsMenu()) return; 441 442 if (mMenu != null) { 443 Bundle savedActionViewStates = new Bundle(); 444 mMenu.saveActionViewStates(savedActionViewStates); 445 if (savedActionViewStates.size() > 0) { 446 mPanelFrozenActionViewState = savedActionViewStates; 447 } 448 // This will be started again when the panel is prepared. 449 mMenu.stopDispatchingItemsChanged(); 450 mMenu.clear(); 451 } 452 mPanelRefreshContent = true; 453 454 // Prepare the options panel if we have an action bar 455 if (mDecorContentParent != null) { 456 mPanelIsPrepared = false; 457 preparePanel(); 458 } 459 } 460 461 private void reopenMenu(MenuBuilder menu, boolean toggleMenuMode) { 462 if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() && 463 (!ViewConfigurationCompat.hasPermanentMenuKey(ViewConfiguration.get(mActivity)) || 464 mDecorContentParent.isOverflowMenuShowPending())) { 465 if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) { 466 mDecorContentParent.showOverflowMenu(); 467 } else { 468 mDecorContentParent.hideOverflowMenu(); 469 } 470 return; 471 } 472 473 menu.close(); 474 } 475 476 private MenuView getListMenuView(Context context, MenuPresenter.Callback cb) { 477 if (mMenu == null) { 478 return null; 479 } 480 481 if (mListMenuPresenter == null) { 482 TypedArray a = context.obtainStyledAttributes(R.styleable.Theme); 483 final int listPresenterTheme = a.getResourceId( 484 R.styleable.Theme_panelMenuListTheme, 485 R.style.Theme_AppCompat_CompactMenu); 486 a.recycle(); 487 488 mListMenuPresenter = new ListMenuPresenter( 489 R.layout.abc_list_menu_item_layout, listPresenterTheme); 490 mListMenuPresenter.setCallback(cb); 491 mMenu.addMenuPresenter(mListMenuPresenter); 492 } else { 493 // Make sure we update the ListView 494 mListMenuPresenter.updateMenuView(false); 495 } 496 497 return mListMenuPresenter.getMenuView(new FrameLayout(context)); 498 } 499 500 @Override 501 public boolean onBackPressed() { 502 // Back cancels action modes first. 503 if (mActionMode != null) { 504 mActionMode.finish(); 505 return true; 506 } 507 508 // Next collapse any expanded action views. 509 ActionBar ab = getSupportActionBar(); 510 if (ab != null && ab.collapseActionView()) { 511 return true; 512 } 513 514 return false; 515 } 516 517 @Override 518 void setSupportProgressBarVisibility(boolean visible) { 519 updateProgressBars(visible ? Window.PROGRESS_VISIBILITY_ON : 520 Window.PROGRESS_VISIBILITY_OFF); 521 } 522 523 @Override 524 void setSupportProgressBarIndeterminateVisibility(boolean visible) { 525 updateProgressBars(visible ? Window.PROGRESS_VISIBILITY_ON : 526 Window.PROGRESS_VISIBILITY_OFF); 527 } 528 529 @Override 530 void setSupportProgressBarIndeterminate(boolean indeterminate) { 531 updateProgressBars(indeterminate ? Window.PROGRESS_INDETERMINATE_ON 532 : Window.PROGRESS_INDETERMINATE_OFF); 533 } 534 535 @Override 536 void setSupportProgress(int progress) { 537 updateProgressBars(Window.PROGRESS_START + progress); 538 } 539 540 @Override 541 int getHomeAsUpIndicatorAttrId() { 542 return R.attr.homeAsUpIndicator; 543 } 544 545 /** 546 * Progress Bar function. Mostly extracted from PhoneWindow.java 547 */ 548 private void updateProgressBars(int value) { 549 ProgressBarCompat circularProgressBar = getCircularProgressBar(); 550 ProgressBarCompat horizontalProgressBar = getHorizontalProgressBar(); 551 552 if (value == Window.PROGRESS_VISIBILITY_ON) { 553 if (mFeatureProgress) { 554 int level = horizontalProgressBar.getProgress(); 555 int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? 556 View.VISIBLE : View.INVISIBLE; 557 horizontalProgressBar.setVisibility(visibility); 558 } 559 if (mFeatureIndeterminateProgress) { 560 circularProgressBar.setVisibility(View.VISIBLE); 561 } 562 } else if (value == Window.PROGRESS_VISIBILITY_OFF) { 563 if (mFeatureProgress) { 564 horizontalProgressBar.setVisibility(View.GONE); 565 } 566 if (mFeatureIndeterminateProgress) { 567 circularProgressBar.setVisibility(View.GONE); 568 } 569 } else if (value == Window.PROGRESS_INDETERMINATE_ON) { 570 horizontalProgressBar.setIndeterminate(true); 571 } else if (value == Window.PROGRESS_INDETERMINATE_OFF) { 572 horizontalProgressBar.setIndeterminate(false); 573 } else if (Window.PROGRESS_START <= value && value <= Window.PROGRESS_END) { 574 // We want to set the progress value before testing for visibility 575 // so that when the progress bar becomes visible again, it has the 576 // correct level. 577 horizontalProgressBar.setProgress(value - Window.PROGRESS_START); 578 579 if (value < Window.PROGRESS_END) { 580 showProgressBars(horizontalProgressBar, circularProgressBar); 581 } else { 582 hideProgressBars(horizontalProgressBar, circularProgressBar); 583 } 584 } 585 } 586 587 private void showProgressBars(ProgressBarCompat horizontalProgressBar, 588 ProgressBarCompat spinnyProgressBar) { 589 if (mFeatureIndeterminateProgress && spinnyProgressBar.getVisibility() == View.INVISIBLE) { 590 spinnyProgressBar.setVisibility(View.VISIBLE); 591 } 592 // Only show the progress bars if the primary progress is not complete 593 if (mFeatureProgress && horizontalProgressBar.getProgress() < 10000) { 594 horizontalProgressBar.setVisibility(View.VISIBLE); 595 } 596 } 597 598 private void hideProgressBars(ProgressBarCompat horizontalProgressBar, 599 ProgressBarCompat spinnyProgressBar) { 600 if (mFeatureIndeterminateProgress && spinnyProgressBar.getVisibility() == View.VISIBLE) { 601 spinnyProgressBar.setVisibility(View.INVISIBLE); 602 } 603 if (mFeatureProgress && horizontalProgressBar.getVisibility() == View.VISIBLE) { 604 horizontalProgressBar.setVisibility(View.INVISIBLE); 605 } 606 } 607 608 private ProgressBarCompat getCircularProgressBar() { 609 ProgressBarCompat pb = (ProgressBarCompat) mActivity.findViewById(R.id.progress_circular); 610 if (pb != null) { 611 pb.setVisibility(View.INVISIBLE); 612 } 613 return pb; 614 } 615 616 private ProgressBarCompat getHorizontalProgressBar() { 617 ProgressBarCompat pb = (ProgressBarCompat) mActivity.findViewById(R.id.progress_horizontal); 618 if (pb != null) { 619 pb.setVisibility(View.INVISIBLE); 620 } 621 return pb; 622 } 623 624 private boolean initializePanelMenu() { 625 Context context = mActivity; 626 627 if (mDecorContentParent != null) { 628 final TypedValue outValue = new TypedValue(); 629 final Resources.Theme baseTheme = context.getTheme(); 630 baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true); 631 632 Resources.Theme widgetTheme = null; 633 if (outValue.resourceId != 0) { 634 widgetTheme = context.getResources().newTheme(); 635 widgetTheme.setTo(baseTheme); 636 widgetTheme.applyStyle(outValue.resourceId, true); 637 widgetTheme.resolveAttribute( 638 R.attr.actionBarWidgetTheme, outValue, true); 639 } else { 640 baseTheme.resolveAttribute( 641 R.attr.actionBarWidgetTheme, outValue, true); 642 } 643 644 if (outValue.resourceId != 0) { 645 if (widgetTheme == null) { 646 widgetTheme = context.getResources().newTheme(); 647 widgetTheme.setTo(baseTheme); 648 } 649 widgetTheme.applyStyle(outValue.resourceId, true); 650 } 651 652 if (widgetTheme != null) { 653 context = new ContextThemeWrapper(context, 0); 654 context.getTheme().setTo(widgetTheme); 655 } 656 } 657 658 mMenu = new MenuBuilder(context); 659 mMenu.setCallback(this); 660 661 return true; 662 } 663 664 private boolean preparePanel() { 665 // Already prepared (isPrepared will be reset to false later) 666 if (mPanelIsPrepared) { 667 return true; 668 } 669 670 // Init the panel state's menu--return false if init failed 671 if (mMenu == null || mPanelRefreshContent) { 672 if (mMenu == null) { 673 if (!initializePanelMenu() || (mMenu == null)) { 674 return false; 675 } 676 } 677 678 if (mDecorContentParent != null) { 679 mDecorContentParent.setMenu(mMenu, this); 680 } 681 682 // Creating the panel menu will involve a lot of manipulation; 683 // don't dispatch change events to presenters until we're done. 684 mMenu.stopDispatchingItemsChanged(); 685 686 // Call callback, and return if it doesn't want to display menu. 687 if (!mActivity.superOnCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, mMenu)) { 688 // Ditch the menu created above 689 mMenu = null; 690 691 if (mDecorContentParent != null) { 692 // Don't show it in the action bar either 693 mDecorContentParent.setMenu(null, this); 694 } 695 696 return false; 697 } 698 699 mPanelRefreshContent = false; 700 } 701 702 // Preparing the panel menu can involve a lot of manipulation; 703 // don't dispatch change events to presenters until we're done. 704 mMenu.stopDispatchingItemsChanged(); 705 706 // Restore action view state before we prepare. This gives apps 707 // an opportunity to override frozen/restored state in onPrepare. 708 if (mPanelFrozenActionViewState != null) { 709 mMenu.restoreActionViewStates(mPanelFrozenActionViewState); 710 mPanelFrozenActionViewState = null; 711 } 712 713 // Callback and return if the callback does not want to show the menu 714 if (!mActivity.superOnPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, mMenu)) { 715 if (mDecorContentParent != null) { 716 // The app didn't want to show the menu for now but it still exists. 717 // Clear it out of the action bar. 718 mDecorContentParent.setMenu(null, this); 719 } 720 mMenu.startDispatchingItemsChanged(); 721 return false; 722 } 723 724 mMenu.startDispatchingItemsChanged(); 725 726 // Set other state 727 mPanelIsPrepared = true; 728 729 return true; 730 } 731 732 /** 733 * Clears out internal reference when the action mode is destroyed. 734 */ 735 private class ActionModeCallbackWrapper implements ActionMode.Callback { 736 private ActionMode.Callback mWrapped; 737 738 public ActionModeCallbackWrapper(ActionMode.Callback wrapped) { 739 mWrapped = wrapped; 740 } 741 742 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 743 return mWrapped.onCreateActionMode(mode, menu); 744 } 745 746 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 747 return mWrapped.onPrepareActionMode(mode, menu); 748 } 749 750 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 751 return mWrapped.onActionItemClicked(mode, item); 752 } 753 754 public void onDestroyActionMode(ActionMode mode) { 755 mWrapped.onDestroyActionMode(mode); 756 mActivity.onSupportActionModeFinished(mode); 757 mActionMode = null; 758 } 759 } 760 761} 762