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