[go: nahoru, domu]

1547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes/*
2547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * Copyright (C) 2015 The Android Open Source Project
3547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes *
4547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * you may not use this file except in compliance with the License.
6547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * You may obtain a copy of the License at
7547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes *
8547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes *
10547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * Unless required by applicable law or agreed to in writing, software
11547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * See the License for the specific language governing permissions and
14547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes * limitations under the License
15547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes */
16547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
17547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banespackage android.support.v7.app;
18547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
19547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banesimport android.content.Context;
20ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banesimport android.content.res.Configuration;
21ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banesimport android.content.res.Resources;
22ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banesimport android.os.Bundle;
2366698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.SupportActionModeWrapper;
24ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banesimport android.util.Log;
25547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banesimport android.view.ActionMode;
26547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banesimport android.view.Window;
27547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
28547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banesclass AppCompatDelegateImplV14 extends AppCompatDelegateImplV11 {
29547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
30ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    private static final String KEY_LOCAL_NIGHT_MODE = "appcompat:local_night_mode";
31ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
32ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    private static TwilightManager sTwilightManager;
33ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
34ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @NightMode
35ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    private int mLocalNightMode = MODE_NIGHT_UNSPECIFIED;
36ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    private boolean mApplyDayNightCalled;
37ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
38547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    private boolean mHandleNativeActionModes = true; // defaults to true
39547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
40547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    AppCompatDelegateImplV14(Context context, Window window, AppCompatCallback callback) {
41547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        super(context, window, callback);
42547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
43547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
44547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    @Override
45ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public void onCreate(Bundle savedInstanceState) {
46ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        super.onCreate(savedInstanceState);
47ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
48ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        if (savedInstanceState != null && mLocalNightMode == MODE_NIGHT_UNSPECIFIED) {
49ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            // If we have a icicle and we haven't had a local night mode set yet, try and read
50ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            // it from the icicle
51ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            mLocalNightMode = savedInstanceState.getInt(KEY_LOCAL_NIGHT_MODE,
52ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                    MODE_NIGHT_UNSPECIFIED);
53ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        }
54ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
55ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
56ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
57547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    Window.Callback wrapWindowCallback(Window.Callback callback) {
58547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        // Override the window callback so that we can intercept onWindowStartingActionMode()
59547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        // calls
60547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        return new AppCompatWindowCallbackV14(callback);
61547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
62547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
63547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    @Override
64547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    public void setHandleNativeActionModesEnabled(boolean enabled) {
65547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        mHandleNativeActionModes = enabled;
66547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
67547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
68547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    @Override
69547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    public boolean isHandleNativeActionModesEnabled() {
70547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        return mHandleNativeActionModes;
71547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
72547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
73ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
74ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public boolean applyDayNight() {
75ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        mApplyDayNightCalled = true;
76b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes
77b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes        final int modeToApply = mapNightMode(mLocalNightMode == MODE_NIGHT_UNSPECIFIED
78b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                ? getDefaultNightMode()
79b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                : mLocalNightMode);
80b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes
81b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes        if (modeToApply != MODE_NIGHT_FOLLOW_SYSTEM) {
82b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes            // If we're not following the system, we many need to update the configuration
83b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes            return updateConfigurationForNightMode(modeToApply);
84b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes        }
85b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes        return false;
86ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
87ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
88ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
89ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public void setLocalNightMode(@NightMode final int mode) {
90ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        switch (mode) {
91ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            case MODE_NIGHT_AUTO:
92ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            case MODE_NIGHT_NO:
93ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            case MODE_NIGHT_YES:
94fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes            case MODE_NIGHT_FOLLOW_SYSTEM:
95ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                if (mLocalNightMode != mode) {
96ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                    mLocalNightMode = mode;
97ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                    if (mApplyDayNightCalled) {
98ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                        // If we've already applied day night, re-apply since we won't be
99ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                        // called again
100ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                        applyDayNight();
101ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                    }
102ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                }
103ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                break;
104ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            default:
105ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                Log.d(TAG, "setLocalNightMode() called with an unknown mode");
106ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes                break;
107ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        }
108ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
109ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
110b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes    @ApplyableNightMode
111b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes    int mapNightMode(@NightMode final int mode) {
112fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes        switch (mode) {
113fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes            case MODE_NIGHT_AUTO:
114fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes                return getTwilightManager().isNight() ? MODE_NIGHT_YES : MODE_NIGHT_NO;
115b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes            case MODE_NIGHT_UNSPECIFIED:
116b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                // If we don't have a mode specified, just let the system handle it
117b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                return MODE_NIGHT_FOLLOW_SYSTEM;
118fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes            default:
119b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                return mode;
120fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes        }
121fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes    }
122fe20eed11b68512fcd16039f8f94c1909f2925f8Chris Banes
123ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    @Override
124ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    public void onSaveInstanceState(Bundle outState) {
125ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        super.onSaveInstanceState(outState);
126ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
127ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        if (mLocalNightMode != MODE_NIGHT_UNSPECIFIED) {
128ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            // If we have a local night mode set, save it
129ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            outState.putInt(KEY_LOCAL_NIGHT_MODE, mLocalNightMode);
130ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        }
131ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
132ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
133ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    /**
134ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes     * Updates the {@link Resources} configuration {@code uiMode} with the
135ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes     * chosen {@code UI_MODE_NIGHT} value.
136ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes     */
137b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes    private boolean updateConfigurationForNightMode(@ApplyableNightMode final int mode) {
138ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        final Resources res = mContext.getResources();
139ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        final Configuration conf = res.getConfiguration();
140ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        final int currentNightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK;
141ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
142b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes        final int newNightMode = (mode == MODE_NIGHT_YES)
143b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                ? Configuration.UI_MODE_NIGHT_YES
144b9579b37d2c3240b4bdaf44978b19d87ec9d3e59Chris Banes                : Configuration.UI_MODE_NIGHT_NO;
145ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
146ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        if (currentNightMode != newNightMode) {
1479800bd0698800fa28f9b95e05e2f4f89d31ff655Chris Banes            final Configuration newConf = new Configuration(conf);
1489800bd0698800fa28f9b95e05e2f4f89d31ff655Chris Banes            newConf.uiMode = (newConf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | newNightMode;
1499800bd0698800fa28f9b95e05e2f4f89d31ff655Chris Banes            res.updateConfiguration(newConf, null);
150ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            return true;
151ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        }
152ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        return false;
153ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
154ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
155ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    private TwilightManager getTwilightManager() {
156ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        if (sTwilightManager == null) {
157ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes            sTwilightManager = new TwilightManager(mContext.getApplicationContext());
158ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        }
159ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes        return sTwilightManager;
160ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes    }
161ff7f258a9b0781de5c6325358c7075128bf05a91Chris Banes
162547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    class AppCompatWindowCallbackV14 extends AppCompatWindowCallbackBase {
163547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        AppCompatWindowCallbackV14(Window.Callback callback) {
164547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            super(callback);
165547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        }
166547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
167547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        @Override
168547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
169547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            // We wrap in a support action mode on v14+ if enabled
170f5829201b976fc650789accc22f325a2541ed478Chris Banes            if (isHandleNativeActionModesEnabled()) {
171547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes                return startAsSupportActionMode(callback);
172547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            }
173547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            // Else, let the call fall through to the wrapped callback
174547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            return super.onWindowStartingActionMode(callback);
175547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        }
176547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
177547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        /**
178547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes         * Wrap the framework {@link ActionMode.Callback} in a support action mode and
179547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes         * let AppCompat display it.
180547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes         */
181547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        final ActionMode startAsSupportActionMode(ActionMode.Callback callback) {
182515e5121889e182cba12ce560493834470b8a42bChris Banes            // Wrap the callback as a v7 ActionMode.Callback
183515e5121889e182cba12ce560493834470b8a42bChris Banes            final SupportActionModeWrapper.CallbackWrapper callbackWrapper
184515e5121889e182cba12ce560493834470b8a42bChris Banes                    = new SupportActionModeWrapper.CallbackWrapper(mContext, callback);
185515e5121889e182cba12ce560493834470b8a42bChris Banes
186515e5121889e182cba12ce560493834470b8a42bChris Banes            // Try and start a support action mode using the wrapped callback
187515e5121889e182cba12ce560493834470b8a42bChris Banes            final android.support.v7.view.ActionMode supportActionMode
188515e5121889e182cba12ce560493834470b8a42bChris Banes                    = startSupportActionMode(callbackWrapper);
189547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes
190547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            if (supportActionMode != null) {
191547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes                // If we received a support action mode, wrap and return it
19233556e6b972f1aa8126a88605b455afd6d6ee0bdAdam Powell                return callbackWrapper.getActionModeWrapper(supportActionMode);
193547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            }
194547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes            return null;
195547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes        }
196547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes    }
197547a80d347e0dc9751bbe3cf91f947477145bdbaChris Banes}
198