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