1cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi/*
2cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
3cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi *
4cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
5cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * you may not use this file except in compliance with the License.
6cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * You may obtain a copy of the License at
7cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi *
8cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
9cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi *
10cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
11cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
12cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * See the License for the specific language governing permissions and
14cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * limitations under the License
15cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi */
16cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
17cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggipackage com.android.systemui;
18cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
19b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwangimport android.app.ActivityThread;
20cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggiimport android.app.Application;
21dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandlerimport android.content.BroadcastReceiver;
22dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandlerimport android.content.Context;
23dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandlerimport android.content.Intent;
24dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandlerimport android.content.IntentFilter;
25b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwangimport android.content.pm.ApplicationInfo;
26cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggiimport android.content.res.Configuration;
27fe67abac68d628043604e8f24fb1915aca298e0cWinsonimport android.os.Process;
28dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandlerimport android.os.SystemProperties;
29f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolovimport android.os.Trace;
30fe67abac68d628043604e8f24fb1915aca298e0cWinsonimport android.os.UserHandle;
31421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monkimport android.util.ArraySet;
32cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggiimport android.util.Log;
3370dcd00d4a8dd3fa52983121a8052c99e66368bfBeverlyimport android.util.TimingsTraceLog;
34cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
3586bc33188948e7b6beb07dbb5ddba59b5ea3c1fcJason Monkimport com.android.systemui.plugins.OverlayPlugin;
3686bc33188948e7b6beb07dbb5ddba59b5ea3c1fcJason Monkimport com.android.systemui.plugins.PluginListener;
3786bc33188948e7b6beb07dbb5ddba59b5ea3c1fcJason Monkimport com.android.systemui.plugins.PluginManager;
382a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monkimport com.android.systemui.statusbar.phone.StatusBar;
39421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monkimport com.android.systemui.statusbar.phone.StatusBarWindowManager;
408e032e15e6b1b6a2f44fd3d5063ee83f45d71189Dan Sandlerimport com.android.systemui.util.NotificationChannels;
4161f39a7b988f6a22681a3f9e0bf8121f72ff88c4Jorim Jaggi
42cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggiimport java.util.HashMap;
43cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggiimport java.util.Map;
44cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
45cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi/**
46cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi * Application class for SystemUI.
47cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi */
4849fa016a98cef9940c883b3f620a0e90537a204eJason Monkpublic class SystemUIApplication extends Application implements SysUiServiceProvider {
49cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
50dc2ddd7e3e1b6a4f3ecc24a0a05d17a4e89cef28Dan Sandler    public static final String TAG = "SystemUIService";
51cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    private static final boolean DEBUG = false;
52cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
53cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    /**
54cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi     * Hold a reference on the stuff we start.
55cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi     */
5661b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi    private SystemUI[] mServices;
573beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi    private boolean mServicesStarted;
58dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler    private boolean mBootCompleted;
59fe67abac68d628043604e8f24fb1915aca298e0cWinson    private final Map<Class<?>, Object> mComponents = new HashMap<>();
60cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
61070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos    @Override
62070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos    public void onCreate() {
63070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos        super.onCreate();
64070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos        // Set the application theme that is inherited by all services. Note that setting the
65070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos        // application theme in the manifest does only work for activities. Keep this in sync with
66070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos        // the theme set there.
67e17ce5286f2c25c2ce440b30f476e9e88a6d1e8eLucas Dupin        setTheme(R.style.Theme_SystemUI);
68dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler
691b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia        SystemUIFactory.createFromConfig(this);
701b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia
71fe67abac68d628043604e8f24fb1915aca298e0cWinson        if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
726ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
736ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
74fe67abac68d628043604e8f24fb1915aca298e0cWinson            registerReceiver(new BroadcastReceiver() {
75fe67abac68d628043604e8f24fb1915aca298e0cWinson                @Override
76fe67abac68d628043604e8f24fb1915aca298e0cWinson                public void onReceive(Context context, Intent intent) {
77fe67abac68d628043604e8f24fb1915aca298e0cWinson                    if (mBootCompleted) return;
78dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler
79fe67abac68d628043604e8f24fb1915aca298e0cWinson                    if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
80fe67abac68d628043604e8f24fb1915aca298e0cWinson                    unregisterReceiver(this);
81fe67abac68d628043604e8f24fb1915aca298e0cWinson                    mBootCompleted = true;
82fe67abac68d628043604e8f24fb1915aca298e0cWinson                    if (mServicesStarted) {
83fe67abac68d628043604e8f24fb1915aca298e0cWinson                        final int N = mServices.length;
84fe67abac68d628043604e8f24fb1915aca298e0cWinson                        for (int i = 0; i < N; i++) {
85fe67abac68d628043604e8f24fb1915aca298e0cWinson                            mServices[i].onBootCompleted();
86fe67abac68d628043604e8f24fb1915aca298e0cWinson                        }
87dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler                    }
8870dcd00d4a8dd3fa52983121a8052c99e66368bfBeverly
896ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly
906ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                }
916ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            }, bootCompletedFilter);
926ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly
936ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
946ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            registerReceiver(new BroadcastReceiver() {
956ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                @Override
966ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                public void onReceive(Context context, Intent intent) {
976ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                    if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
986ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                        if (!mBootCompleted) return;
996ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                        // Update names of SystemUi notification channels
1006ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                        NotificationChannels.createAll(context);
1016ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly                    }
102dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler                }
1036ea063eb5f1d4d7c6242915f378e68048ea51d70Beverly            }, localeChangedFilter);
104fe67abac68d628043604e8f24fb1915aca298e0cWinson        } else {
105b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            // We don't need to startServices for sub-process that is doing some tasks.
106b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            // (screenshots, sweetsweetdesserts or tuner ..)
107b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            String processName = ActivityThread.currentProcessName();
108b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            ApplicationInfo info = getApplicationInfo();
109b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            if (processName != null && processName.startsWith(info.processName + ":")) {
110b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang                return;
111b647984f04a8cff6f98ee9654336854ddf872278dooyoung.hwang            }
112fe67abac68d628043604e8f24fb1915aca298e0cWinson            // For a secondary user, boot-completed will never be called because it has already
113fe67abac68d628043604e8f24fb1915aca298e0cWinson            // been broadcasted on startup for the primary SystemUI process.  Instead, for
114fe67abac68d628043604e8f24fb1915aca298e0cWinson            // components which require the SystemUI component to be initialized per-user, we
115fe67abac68d628043604e8f24fb1915aca298e0cWinson            // start those components now for the current non-system user.
11661b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            startSecondaryUserServicesIfNeeded();
117fe67abac68d628043604e8f24fb1915aca298e0cWinson        }
118070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos    }
119070a0b61cd416b9d54d57bf52ba6583f9b111ee6Adrian Roos
1203beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi    /**
1213beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi     * Makes sure that all the SystemUI services are running. If they are already running, this is a
1223beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi     * no-op. This is needed to conditinally start all the services, as we only need to have it in
1233beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi     * the main process.
1243beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi     * <p>This method must only be called from the main thread.</p>
1253beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi     */
126be3235abcddbcab63e60184de416c6243697abb7Jason Monk
1273beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi    public void startServicesIfNeeded() {
12861b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi        String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
12961b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi        startServicesIfNeeded(names);
130fe67abac68d628043604e8f24fb1915aca298e0cWinson    }
131fe67abac68d628043604e8f24fb1915aca298e0cWinson
1323c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson    /**
1333c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson     * Ensures that all the Secondary user SystemUI services are running. If they are already
1343c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson     * running, this is a no-op. This is needed to conditinally start all the services, as we only
1353c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson     * need to have it in the main process.
1363c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson     * <p>This method must only be called from the main thread.</p>
1373c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson     */
1383c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson    void startSecondaryUserServicesIfNeeded() {
13961b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi        String[] names =
14061b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi                  getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
14161b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi        startServicesIfNeeded(names);
1423c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson    }
1433c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson
14461b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi    private void startServicesIfNeeded(String[] services) {
1453beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi        if (mServicesStarted) {
1463beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi            return;
1473beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi        }
14861b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi        mServices = new SystemUI[services.length];
149dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler
150dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler        if (!mBootCompleted) {
151dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            // check to see if maybe it was already completed long before we began
152dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            // see ActivityManagerService.finishBooting()
153dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
154dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler                mBootCompleted = true;
155dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler                if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
156dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            }
157dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler        }
158dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler
159fe67abac68d628043604e8f24fb1915aca298e0cWinson        Log.v(TAG, "Starting SystemUI services for user " +
160fe67abac68d628043604e8f24fb1915aca298e0cWinson                Process.myUserHandle().getIdentifier() + ".");
1616e3461b67cae27a42a4d77fa277ba2d844ea0cdeFyodor Kupolov        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
162f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov                Trace.TRACE_TAG_APP);
163f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov        log.traceBegin("StartServices");
164fe67abac68d628043604e8f24fb1915aca298e0cWinson        final int N = services.length;
165421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk        for (int i = 0; i < N; i++) {
16661b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            String clsName = services[i];
16761b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            if (DEBUG) Log.d(TAG, "loading: " + clsName);
16861b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            log.traceBegin("StartServices" + clsName);
169f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            long ti = System.currentTimeMillis();
17061b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            Class cls;
171cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            try {
17261b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi                cls = Class.forName(clsName);
17361b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi                mServices[i] = (SystemUI) cls.newInstance();
17461b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi            } catch(ClassNotFoundException ex){
17561b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi                throw new RuntimeException(ex);
176cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            } catch (IllegalAccessException ex) {
177cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi                throw new RuntimeException(ex);
178cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            } catch (InstantiationException ex) {
179cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi                throw new RuntimeException(ex);
180cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            }
18194ce94e96069ab6c2ece4864ba4c7692f3168352Muyuan Li
182cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            mServices[i].mContext = this;
183cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            mServices[i].mComponents = mComponents;
184cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
185cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi            mServices[i].start();
186f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            log.traceEnd();
187dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler
188f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            // Warn if initialization of component takes too long
189f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            ti = System.currentTimeMillis() - ti;
190f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            if (ti > 1000) {
19161b37088337753a7e631579829040c5cae9d72c4yoshiki iguchi                Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
192f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov            }
193dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            if (mBootCompleted) {
194dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler                mServices[i].onBootCompleted();
195dc5f16bf096796d2f822bce8a720fc26e898da5eDan Sandler            }
196cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        }
197f3591359b9841a1571545a39b038802ce7ed77bbFyodor Kupolov        log.traceEnd();
1985bec68fbea1a02d7debc2eeeaf01b9478de216e5Jason Monk        Dependency.get(PluginManager.class).addPluginListener(
19986bc33188948e7b6beb07dbb5ddba59b5ea3c1fcJason Monk                new PluginListener<OverlayPlugin>() {
200421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    private ArraySet<OverlayPlugin> mOverlays;
201421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk
202421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    @Override
203421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
204421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        StatusBar statusBar = getComponent(StatusBar.class);
205421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        if (statusBar != null) {
206421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                            plugin.setup(statusBar.getStatusBarWindow(),
207421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                                    statusBar.getNavigationBarView());
208421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        }
209421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        // Lazy init.
210421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        if (mOverlays == null) mOverlays = new ArraySet<>();
211421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        if (plugin.holdStatusBarOpen()) {
212421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                            mOverlays.add(plugin);
213421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                            Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
214421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                                    mOverlays.forEach(o -> o.setCollapseDesired(b)));
215421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                            Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
216421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                                    mOverlays.size() != 0);
217421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk
218421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        }
219421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    }
220421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk
221421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    @Override
222421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    public void onPluginDisconnected(OverlayPlugin plugin) {
223421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        mOverlays.remove(plugin);
224421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                        Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
225421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                                mOverlays.size() != 0);
226421a9410b462770544c6ae9a554542fa2fe1acb1Jason Monk                    }
2275bec68fbea1a02d7debc2eeeaf01b9478de216e5Jason Monk                }, OverlayPlugin.class, true /* Allow multiple plugins */);
22886bc33188948e7b6beb07dbb5ddba59b5ea3c1fcJason Monk
2293beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi        mServicesStarted = true;
230cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    }
231cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
232cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    @Override
233cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    public void onConfigurationChanged(Configuration newConfig) {
2343beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi        if (mServicesStarted) {
2353beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi            int len = mServices.length;
2363beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi            for (int i = 0; i < len; i++) {
23794a148594d56e87920c3771ab630a5337612bd52Winson                if (mServices[i] != null) {
23894a148594d56e87920c3771ab630a5337612bd52Winson                    mServices[i].onConfigurationChanged(newConfig);
23994a148594d56e87920c3771ab630a5337612bd52Winson                }
2403beffdf4a0081a97356f46d50e10541b1a213153Jorim Jaggi            }
241cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        }
242cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    }
243cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
244cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    @SuppressWarnings("unchecked")
245cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    public <T> T getComponent(Class<T> interfaceType) {
246cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        return (T) mComponents.get(interfaceType);
247cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    }
248cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi
249cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    public SystemUI[] getServices() {
250cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi        return mServices;
251cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi    }
252cff0acb6b1eea23c3f44a078a0a5e81c11faea35Jorim Jaggi}
253