1f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes/*
2f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * Copyright (C) 2013 The Android Open Source Project
3f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes *
4f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * you may not use this file except in compliance with the License.
6f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * You may obtain a copy of the License at
7f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes *
8f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes *
10f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * Unless required by applicable law or agreed to in writing, software
11f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * See the License for the specific language governing permissions and
14f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes * limitations under the License.
15f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes */
16f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
17f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banespackage android.support.v7.app;
18f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
19f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.app.Activity;
20f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.content.Context;
2119ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banesimport android.content.res.Resources;
22f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.graphics.drawable.Drawable;
2319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banesimport android.os.Build;
24ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banesimport android.os.Bundle;
258f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi;
26f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.support.v7.appcompat.R;
27f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.support.v7.view.ActionMode;
2866698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.SupportMenuInflater;
2966698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.WindowCallbackWrapper;
3066698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuBuilder;
3166698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.widget.TintTypedArray;
32f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.view.KeyEvent;
33f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.view.Menu;
34f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.view.MenuInflater;
35f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.view.View;
36f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesimport android.view.Window;
37f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
38d38b36c6370fe2aa448b7b824e8fb399fb3f0b97Alan Viverette@RequiresApi(14)
39f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banesabstract class AppCompatDelegateImplBase extends AppCompatDelegate {
40f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
4112acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    static final boolean DEBUG = false;
4212acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes
4319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes    private static boolean sInstalledExceptionHandler;
4419ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes    private static final boolean SHOULD_INSTALL_EXCEPTION_HANDLER = Build.VERSION.SDK_INT < 21;
4519ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
462c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas    static final String EXCEPTION_HANDLER_MESSAGE_SUFFIX= ". If the resource you are"
4719ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            + " trying to use is a vector resource, you may be referencing it in an unsupported"
4819ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            + " way. See AppCompatDelegate.setCompatVectorFromResourcesEnabled() for more info.";
4919ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
5019ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes    static {
5119ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes        if (SHOULD_INSTALL_EXCEPTION_HANDLER && !sInstalledExceptionHandler) {
5219ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            final Thread.UncaughtExceptionHandler defHandler
5319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    = Thread.getDefaultUncaughtExceptionHandler();
5419ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
5519ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
5619ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                @Override
5719ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                public void uncaughtException(Thread thread, final Throwable thowable) {
5819ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    if (shouldWrapException(thowable)) {
5919ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        // Now wrap the throwable, but append some extra information to the message
6019ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        final Throwable wrapped = new Resources.NotFoundException(
6119ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                                thowable.getMessage() + EXCEPTION_HANDLER_MESSAGE_SUFFIX);
6219ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        wrapped.initCause(thowable.getCause());
6319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        wrapped.setStackTrace(thowable.getStackTrace());
6419ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        defHandler.uncaughtException(thread, wrapped);
6519ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    } else {
6619ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        defHandler.uncaughtException(thread, thowable);
6719ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    }
6819ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                }
6919ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
7019ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                private boolean shouldWrapException(Throwable throwable) {
7119ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    if (throwable instanceof Resources.NotFoundException) {
7219ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        final String message = throwable.getMessage();
7319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                        return message != null && (message.contains("drawable")
7419ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                                || message.contains("Drawable"));
7519ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    }
7619ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                    return false;
7719ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes                }
7819ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            });
7919ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
8019ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes            sInstalledExceptionHandler = true;
8119ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes        }
8219ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes    }
8319ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes
84593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes    private static final int[] sWindowBackgroundStyleable = {android.R.attr.windowBackground};
85593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes
8616e8d4dd91083260223c007c797e46bc8f631055Chris Banes    final Context mContext;
8716e8d4dd91083260223c007c797e46bc8f631055Chris Banes    final Window mWindow;
8816e8d4dd91083260223c007c797e46bc8f631055Chris Banes    final Window.Callback mOriginalWindowCallback;
898d4765883ff24f0f79bf64fea23d4687d50cec85Chris Banes    final Window.Callback mAppCompatWindowCallback;
9016e8d4dd91083260223c007c797e46bc8f631055Chris Banes    final AppCompatCallback mAppCompatCallback;
91f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
928122ad54f129c2214631fad86cabda82815cc0d8Chris Banes    ActionBar mActionBar;
935ecdb2c5042da49d36d7cda3fa08f1d9151a1fbdChris Banes    MenuInflater mMenuInflater;
94f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
95f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    // true if this activity has an action bar.
96f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    boolean mHasActionBar;
97f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    // true if this activity's action bar overlays other activity content.
98f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    boolean mOverlayActionBar;
99f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    // true if this any action modes should overlay the activity content
100f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    boolean mOverlayActionMode;
101f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    // true if this activity is floating (e.g. Dialog)
102f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    boolean mIsFloating;
1030f58401dc72db8ea2a201e3c0220f6529f2a7b33Chris Banes    // true if this activity has no title
1040f58401dc72db8ea2a201e3c0220f6529f2a7b33Chris Banes    boolean mWindowNoTitle;
105f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
10616e8d4dd91083260223c007c797e46bc8f631055Chris Banes    private CharSequence mTitle;
10716e8d4dd91083260223c007c797e46bc8f631055Chris Banes
10812acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    private boolean mIsStarted;
109f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    private boolean mIsDestroyed;
1108a6d3a17d966d841ff7a02521ca2783d896d696dEvan Rosky    private boolean mEatKeyUpEvent;
111f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
11216e8d4dd91083260223c007c797e46bc8f631055Chris Banes    AppCompatDelegateImplBase(Context context, Window window, AppCompatCallback callback) {
11316e8d4dd91083260223c007c797e46bc8f631055Chris Banes        mContext = context;
11416e8d4dd91083260223c007c797e46bc8f631055Chris Banes        mWindow = window;
115f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        mAppCompatCallback = callback;
11616e8d4dd91083260223c007c797e46bc8f631055Chris Banes
11716e8d4dd91083260223c007c797e46bc8f631055Chris Banes        mOriginalWindowCallback = mWindow.getCallback();
118547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        if (mOriginalWindowCallback instanceof AppCompatWindowCallbackBase) {
11916e8d4dd91083260223c007c797e46bc8f631055Chris Banes            throw new IllegalStateException(
12016e8d4dd91083260223c007c797e46bc8f631055Chris Banes                    "AppCompat has already installed itself into the Window");
12116e8d4dd91083260223c007c797e46bc8f631055Chris Banes        }
1228d4765883ff24f0f79bf64fea23d4687d50cec85Chris Banes        mAppCompatWindowCallback = wrapWindowCallback(mOriginalWindowCallback);
12316e8d4dd91083260223c007c797e46bc8f631055Chris Banes        // Now install the new callback
1248d4765883ff24f0f79bf64fea23d4687d50cec85Chris Banes        mWindow.setCallback(mAppCompatWindowCallback);
125593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes
126593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
127593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes                context, null, sWindowBackgroundStyleable);
128593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes        final Drawable winBg = a.getDrawableIfKnown(0);
129593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes        if (winBg != null) {
130593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes            mWindow.setBackgroundDrawable(winBg);
131593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes        }
132593d8bcc82c01a559f737dfcbc6e806005300a64Chris Banes        a.recycle();
133f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
134f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
1358122ad54f129c2214631fad86cabda82815cc0d8Chris Banes    abstract void initWindowDecorActionBar();
136f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
137547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    Window.Callback wrapWindowCallback(Window.Callback callback) {
138547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        return new AppCompatWindowCallbackBase(callback);
139547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
140547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
141f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    @Override
142f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    public ActionBar getSupportActionBar() {
143f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        // The Action Bar should be lazily created as hasActionBar
144f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        // could change after onCreate
1458122ad54f129c2214631fad86cabda82815cc0d8Chris Banes        initWindowDecorActionBar();
146f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return mActionBar;
147f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
148f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
149f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    final ActionBar peekSupportActionBar() {
150f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return mActionBar;
151f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
152f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
153f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    @Override
154f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    public MenuInflater getMenuInflater() {
1555ecdb2c5042da49d36d7cda3fa08f1d9151a1fbdChris Banes        // Make sure that action views can get an appropriate theme.
156f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        if (mMenuInflater == null) {
1575ecdb2c5042da49d36d7cda3fa08f1d9151a1fbdChris Banes            initWindowDecorActionBar();
1585ecdb2c5042da49d36d7cda3fa08f1d9151a1fbdChris Banes            mMenuInflater = new SupportMenuInflater(
1595ecdb2c5042da49d36d7cda3fa08f1d9151a1fbdChris Banes                    mActionBar != null ? mActionBar.getThemedContext() : mContext);
160f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
161f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return mMenuInflater;
162f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
163f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
164f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    // Methods used to create and respond to options menu
165d25af35061a9f20d59b25329d613c62c20184dadChris Banes    abstract void onPanelClosed(int featureId, Menu menu);
166f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
167f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    abstract boolean onMenuOpened(int featureId, Menu menu);
168f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
169f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    abstract boolean dispatchKeyEvent(KeyEvent event);
170f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
171f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    abstract boolean onKeyShortcut(int keyCode, KeyEvent event);
172f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
173f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    @Override
174ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public void setLocalNightMode(@NightMode int mode) {
175ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        // no-op
176ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
177ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
178ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
179f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    public final ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() {
180f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return new ActionBarDrawableToggleImpl();
181f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
182f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
183f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    final Context getActionBarThemedContext() {
184f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        Context context = null;
185f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
186f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        // If we have an action bar, let it return a themed context
187f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        ActionBar ab = getSupportActionBar();
188f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        if (ab != null) {
189f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            context = ab.getThemedContext();
190f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
191f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
192f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        if (context == null) {
19316e8d4dd91083260223c007c797e46bc8f631055Chris Banes            context = mContext;
194f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
195f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return context;
196f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
197f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
198f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    private class ActionBarDrawableToggleImpl implements ActionBarDrawerToggle.Delegate {
1992c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        ActionBarDrawableToggleImpl() {
2002c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas        }
2012c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas
202f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
203f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public Drawable getThemeUpIndicator() {
204f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
205f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                    getActionBarThemedContext(), null, new int[]{ R.attr.homeAsUpIndicator });
206f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            final Drawable result = a.getDrawable(0);
207f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            a.recycle();
208f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            return result;
209f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
210f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
211f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
212f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public Context getActionBarThemedContext() {
213f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            return AppCompatDelegateImplBase.this.getActionBarThemedContext();
214f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
215f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
216f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
217f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public boolean isNavigationVisible() {
218f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            final ActionBar ab = getSupportActionBar();
219f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            return ab != null && (ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0;
220f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
221f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
222f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
223f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public void setActionBarUpIndicator(Drawable upDrawable, int contentDescRes) {
224f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            ActionBar ab = getSupportActionBar();
225f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            if (ab != null) {
226f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                ab.setHomeAsUpIndicator(upDrawable);
227f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                ab.setHomeActionContentDescription(contentDescRes);
228f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            }
229f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
230f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
231f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
232f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public void setActionBarDescription(int contentDescRes) {
233f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            ActionBar ab = getSupportActionBar();
234f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            if (ab != null) {
235f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                ab.setHomeActionContentDescription(contentDescRes);
236f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            }
237f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
238f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
239f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
240f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    abstract ActionMode startSupportActionModeFromWindow(ActionMode.Callback callback);
241f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
242f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    @Override
24312acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    public void onStart() {
24412acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes        mIsStarted = true;
24512acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    }
24612acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes
24712acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    @Override
24812acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    public void onStop() {
24912acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes        mIsStarted = false;
25012acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    }
25112acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes
25212acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    @Override
253733d0b2acb07ede7455b9d020901a10586053923Chris Banes    public void onDestroy() {
254f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        mIsDestroyed = true;
255f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
256f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
257547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    @Override
258547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    public void setHandleNativeActionModesEnabled(boolean enabled) {
259547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        // no-op pre-v14
260547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
261547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
262547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    @Override
263547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    public boolean isHandleNativeActionModesEnabled() {
264547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        // Always false pre-v14
265547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        return false;
266547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
267547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
268ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
269ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public boolean applyDayNight() {
270ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        // no-op on v7
271ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        return false;
272ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
273ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
274f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    final boolean isDestroyed() {
275f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        return mIsDestroyed;
276f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
277f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
27812acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    final boolean isStarted() {
27912acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes        return mIsStarted;
28012acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes    }
28112acd8f6d6926aaa5cc16543386e0aeee64716edChris Banes
282f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    final Window.Callback getWindowCallback() {
28316e8d4dd91083260223c007c797e46bc8f631055Chris Banes        return mWindow.getCallback();
284f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
285f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
28616e8d4dd91083260223c007c797e46bc8f631055Chris Banes    @Override
28716e8d4dd91083260223c007c797e46bc8f631055Chris Banes    public final void setTitle(CharSequence title) {
28816e8d4dd91083260223c007c797e46bc8f631055Chris Banes        mTitle = title;
28916e8d4dd91083260223c007c797e46bc8f631055Chris Banes        onTitleChanged(title);
29016e8d4dd91083260223c007c797e46bc8f631055Chris Banes    }
291f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
292ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
293ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public void onSaveInstanceState(Bundle outState) {
294ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        // no-op
295ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
296ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
29716e8d4dd91083260223c007c797e46bc8f631055Chris Banes    abstract void onTitleChanged(CharSequence title);
298f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
29916e8d4dd91083260223c007c797e46bc8f631055Chris Banes    final CharSequence getTitle() {
30044ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls        // If the original window callback is an Activity, we'll use its title
30116e8d4dd91083260223c007c797e46bc8f631055Chris Banes        if (mOriginalWindowCallback instanceof Activity) {
30216e8d4dd91083260223c007c797e46bc8f631055Chris Banes            return ((Activity) mOriginalWindowCallback).getTitle();
30316e8d4dd91083260223c007c797e46bc8f631055Chris Banes        }
30416e8d4dd91083260223c007c797e46bc8f631055Chris Banes        // Else, we'll return the title we have recorded ourselves
30516e8d4dd91083260223c007c797e46bc8f631055Chris Banes        return mTitle;
306f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
307f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
308547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    class AppCompatWindowCallbackBase extends WindowCallbackWrapper {
309547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        AppCompatWindowCallbackBase(Window.Callback callback) {
310f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            super(callback);
311f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
312f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
313f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
314f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public boolean dispatchKeyEvent(KeyEvent event) {
315559fa14454cc053127b3b96c0e63c48c06937e38Chris Banes            return AppCompatDelegateImplBase.this.dispatchKeyEvent(event)
316559fa14454cc053127b3b96c0e63c48c06937e38Chris Banes                    || super.dispatchKeyEvent(event);
317d25af35061a9f20d59b25329d613c62c20184dadChris Banes        }
318d25af35061a9f20d59b25329d613c62c20184dadChris Banes
319d25af35061a9f20d59b25329d613c62c20184dadChris Banes        @Override
320d25af35061a9f20d59b25329d613c62c20184dadChris Banes        public boolean dispatchKeyShortcutEvent(KeyEvent event) {
321d25af35061a9f20d59b25329d613c62c20184dadChris Banes            return super.dispatchKeyShortcutEvent(event)
322d25af35061a9f20d59b25329d613c62c20184dadChris Banes                    || AppCompatDelegateImplBase.this.onKeyShortcut(event.getKeyCode(), event);
323f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
324f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
325f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
326f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public boolean onCreatePanelMenu(int featureId, Menu menu) {
327f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            if (featureId == Window.FEATURE_OPTIONS_PANEL && !(menu instanceof MenuBuilder)) {
328f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                // If this is an options menu but it's not an AppCompat menu, we eat the event
329f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                // and return false
330f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                return false;
331f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            }
332f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            return super.onCreatePanelMenu(featureId, menu);
333f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
334f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
335f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
336d25af35061a9f20d59b25329d613c62c20184dadChris Banes        public void onContentChanged() {
337d25af35061a9f20d59b25329d613c62c20184dadChris Banes            // We purposely do not propagate this call as this is called when we install
338d25af35061a9f20d59b25329d613c62c20184dadChris Banes            // our sub-decor rather than the user's content
339d25af35061a9f20d59b25329d613c62c20184dadChris Banes        }
340d25af35061a9f20d59b25329d613c62c20184dadChris Banes
341d25af35061a9f20d59b25329d613c62c20184dadChris Banes        @Override
342f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public boolean onPreparePanel(int featureId, View view, Menu menu) {
3434e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
3444e411251159c965caccb3bf3727c2921d74f06c1Chris Banes
3454e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            if (featureId == Window.FEATURE_OPTIONS_PANEL && mb == null) {
346f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                // If this is an options menu but it's not an AppCompat menu, we eat the event
347f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                // and return false
348f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes                return false;
349f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            }
350f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
3514e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            // On ICS and below devices, onPreparePanel calls menu.hasVisibleItems() to determine
3524e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            // if a panel is prepared. This interferes with any initially invisible items, which
3534e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            // are later made visible. We workaround it by making hasVisibleItems() always
3544e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            // return true during the onPreparePanel call.
3554e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            if (mb != null) {
3564e411251159c965caccb3bf3727c2921d74f06c1Chris Banes                mb.setOverrideVisibleItems(true);
3574e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            }
3584e411251159c965caccb3bf3727c2921d74f06c1Chris Banes
3594e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            final boolean handled = super.onPreparePanel(featureId, view, menu);
3604e411251159c965caccb3bf3727c2921d74f06c1Chris Banes
3614e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            if (mb != null) {
3624e411251159c965caccb3bf3727c2921d74f06c1Chris Banes                mb.setOverrideVisibleItems(false);
363f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            }
364f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
3654e411251159c965caccb3bf3727c2921d74f06c1Chris Banes            return handled;
366f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
367f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
368f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
369f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public boolean onMenuOpened(int featureId, Menu menu) {
370ef45ec823d39029e03ff29eb618eaa5a78839470Chris Banes            super.onMenuOpened(featureId, menu);
371ef45ec823d39029e03ff29eb618eaa5a78839470Chris Banes            AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
372ef45ec823d39029e03ff29eb618eaa5a78839470Chris Banes            return true;
373f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
374f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes
375f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        @Override
376f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        public void onPanelClosed(int featureId, Menu menu) {
377f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes            super.onPanelClosed(featureId, menu);
378d25af35061a9f20d59b25329d613c62c20184dadChris Banes            AppCompatDelegateImplBase.this.onPanelClosed(featureId, menu);
379f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes        }
380f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes    }
381f3ad1351d8b40ec5defe35e79d3430ad3c384b6dChris Banes}
382