blob: e89e6cb269f803a31d10549b0661b8dd19ac57f5 [file] [log] [blame]
Jorim Jaggicff0acb2014-03-31 16:35:15 +02001/*
2 * Copyright (C) 2014 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 com.android.systemui;
18
dooyoung.hwangb6479842016-08-31 14:15:22 +090019import android.app.ActivityThread;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020020import android.app.Application;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040021import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
dooyoung.hwangb6479842016-08-31 14:15:22 +090025import android.content.pm.ApplicationInfo;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020026import android.content.res.Configuration;
Beverly97b8ce12019-02-01 16:55:48 -050027import android.os.Handler;
28import android.os.Looper;
Winsonfe67aba2015-09-22 14:04:46 -070029import android.os.Process;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040030import android.os.SystemProperties;
Fyodor Kupolovf3591352017-06-23 18:20:40 -070031import android.os.Trace;
Winsonfe67aba2015-09-22 14:04:46 -070032import android.os.UserHandle;
Jason Monk421a9412017-02-06 09:15:21 -080033import android.util.ArraySet;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020034import android.util.Log;
Beverly70dcd002018-03-29 17:09:16 -040035import android.util.TimingsTraceLog;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020036
Jason Monk86bc3312016-08-16 13:17:56 -040037import com.android.systemui.plugins.OverlayPlugin;
38import com.android.systemui.plugins.PluginListener;
Tony Wickham023cb192018-09-13 15:23:04 -070039import com.android.systemui.shared.plugins.PluginManager;
Beverly1488f692019-06-07 09:32:46 -040040import com.android.systemui.statusbar.phone.DozeParameters;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050041import com.android.systemui.statusbar.phone.StatusBar;
Lucas Dupin1a8588d2018-08-21 12:18:47 -070042import com.android.systemui.statusbar.phone.StatusBarWindowController;
Dan Sandler8e032e12017-01-25 13:41:38 -050043import com.android.systemui.util.NotificationChannels;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010044
Jorim Jaggicff0acb2014-03-31 16:35:15 +020045import java.util.HashMap;
46import java.util.Map;
47
48/**
49 * Application class for SystemUI.
50 */
Jason Monk49fa0162017-01-11 09:21:56 -050051public class SystemUIApplication extends Application implements SysUiServiceProvider {
Jorim Jaggicff0acb2014-03-31 16:35:15 +020052
Dan Sandlerdc2ddd72018-01-24 16:09:53 -050053 public static final String TAG = "SystemUIService";
Jorim Jaggicff0acb2014-03-31 16:35:15 +020054 private static final boolean DEBUG = false;
55
56 /**
Jorim Jaggicff0acb2014-03-31 16:35:15 +020057 * Hold a reference on the stuff we start.
58 */
yoshiki iguchi61b37082017-11-29 16:46:32 +090059 private SystemUI[] mServices;
Jorim Jaggi3beffdf2014-04-03 17:37:37 +020060 private boolean mServicesStarted;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040061 private boolean mBootCompleted;
Winsonfe67aba2015-09-22 14:04:46 -070062 private final Map<Class<?>, Object> mComponents = new HashMap<>();
Jorim Jaggicff0acb2014-03-31 16:35:15 +020063
Adrian Roos070a0b62014-04-10 23:25:03 +020064 @Override
65 public void onCreate() {
66 super.onCreate();
67 // Set the application theme that is inherited by all services. Note that setting the
68 // application theme in the manifest does only work for activities. Keep this in sync with
69 // the theme set there.
Lucas Dupine17ce522017-07-17 15:45:06 -070070 setTheme(R.style.Theme_SystemUI);
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040071
Xiyuan Xia1b30f792016-01-06 08:50:30 -080072 SystemUIFactory.createFromConfig(this);
73
Winsonfe67aba2015-09-22 14:04:46 -070074 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
Beverly6ea063e2018-04-19 10:27:06 -040075 IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
76 bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Winsonfe67aba2015-09-22 14:04:46 -070077 registerReceiver(new BroadcastReceiver() {
78 @Override
79 public void onReceive(Context context, Intent intent) {
80 if (mBootCompleted) return;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040081
Winsonfe67aba2015-09-22 14:04:46 -070082 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
83 unregisterReceiver(this);
84 mBootCompleted = true;
85 if (mServicesStarted) {
86 final int N = mServices.length;
87 for (int i = 0; i < N; i++) {
88 mServices[i].onBootCompleted();
89 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040090 }
Beverly70dcd002018-03-29 17:09:16 -040091
Beverly6ea063e2018-04-19 10:27:06 -040092
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040093 }
Beverly6ea063e2018-04-19 10:27:06 -040094 }, bootCompletedFilter);
95
96 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
97 registerReceiver(new BroadcastReceiver() {
98 @Override
99 public void onReceive(Context context, Intent intent) {
100 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
101 if (!mBootCompleted) return;
102 // Update names of SystemUi notification channels
103 NotificationChannels.createAll(context);
104 }
105 }
106 }, localeChangedFilter);
Winsonfe67aba2015-09-22 14:04:46 -0700107 } else {
dooyoung.hwangb6479842016-08-31 14:15:22 +0900108 // We don't need to startServices for sub-process that is doing some tasks.
109 // (screenshots, sweetsweetdesserts or tuner ..)
110 String processName = ActivityThread.currentProcessName();
111 ApplicationInfo info = getApplicationInfo();
112 if (processName != null && processName.startsWith(info.processName + ":")) {
113 return;
114 }
Winsonfe67aba2015-09-22 14:04:46 -0700115 // For a secondary user, boot-completed will never be called because it has already
116 // been broadcasted on startup for the primary SystemUI process. Instead, for
117 // components which require the SystemUI component to be initialized per-user, we
118 // start those components now for the current non-system user.
yoshiki iguchi61b37082017-11-29 16:46:32 +0900119 startSecondaryUserServicesIfNeeded();
Winsonfe67aba2015-09-22 14:04:46 -0700120 }
Adrian Roos070a0b62014-04-10 23:25:03 +0200121 }
122
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200123 /**
124 * Makes sure that all the SystemUI services are running. If they are already running, this is a
125 * no-op. This is needed to conditinally start all the services, as we only need to have it in
126 * the main process.
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200127 * <p>This method must only be called from the main thread.</p>
128 */
Jason Monkbe3235a2017-04-05 09:29:53 -0400129
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200130 public void startServicesIfNeeded() {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900131 String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
132 startServicesIfNeeded(names);
Winsonfe67aba2015-09-22 14:04:46 -0700133 }
134
Winson3c2c34b2016-04-04 17:47:41 -0700135 /**
136 * Ensures that all the Secondary user SystemUI services are running. If they are already
137 * running, this is a no-op. This is needed to conditinally start all the services, as we only
138 * need to have it in the main process.
Winson3c2c34b2016-04-04 17:47:41 -0700139 * <p>This method must only be called from the main thread.</p>
140 */
141 void startSecondaryUserServicesIfNeeded() {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900142 String[] names =
143 getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
144 startServicesIfNeeded(names);
Winson3c2c34b2016-04-04 17:47:41 -0700145 }
146
yoshiki iguchi61b37082017-11-29 16:46:32 +0900147 private void startServicesIfNeeded(String[] services) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200148 if (mServicesStarted) {
149 return;
150 }
yoshiki iguchi61b37082017-11-29 16:46:32 +0900151 mServices = new SystemUI[services.length];
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400152
153 if (!mBootCompleted) {
154 // check to see if maybe it was already completed long before we began
155 // see ActivityManagerService.finishBooting()
156 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
157 mBootCompleted = true;
158 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
159 }
160 }
161
Winsonfe67aba2015-09-22 14:04:46 -0700162 Log.v(TAG, "Starting SystemUI services for user " +
163 Process.myUserHandle().getIdentifier() + ".");
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -0700164 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700165 Trace.TRACE_TAG_APP);
166 log.traceBegin("StartServices");
Winsonfe67aba2015-09-22 14:04:46 -0700167 final int N = services.length;
Jason Monk421a9412017-02-06 09:15:21 -0800168 for (int i = 0; i < N; i++) {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900169 String clsName = services[i];
170 if (DEBUG) Log.d(TAG, "loading: " + clsName);
171 log.traceBegin("StartServices" + clsName);
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700172 long ti = System.currentTimeMillis();
yoshiki iguchi61b37082017-11-29 16:46:32 +0900173 Class cls;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200174 try {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900175 cls = Class.forName(clsName);
Jason Monk27d01a622018-12-10 15:57:09 -0500176 Object o = cls.newInstance();
177 if (o instanceof SystemUI.Injector) {
178 o = ((SystemUI.Injector) o).apply(this);
179 }
180 mServices[i] = (SystemUI) o;
yoshiki iguchi61b37082017-11-29 16:46:32 +0900181 } catch(ClassNotFoundException ex){
182 throw new RuntimeException(ex);
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200183 } catch (IllegalAccessException ex) {
184 throw new RuntimeException(ex);
185 } catch (InstantiationException ex) {
186 throw new RuntimeException(ex);
187 }
Muyuan Li94ce94e2016-02-24 16:20:54 -0800188
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200189 mServices[i].mContext = this;
190 mServices[i].mComponents = mComponents;
191 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
192 mServices[i].start();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700193 log.traceEnd();
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400194
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700195 // Warn if initialization of component takes too long
196 ti = System.currentTimeMillis() - ti;
197 if (ti > 1000) {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900198 Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700199 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400200 if (mBootCompleted) {
201 mServices[i].onBootCompleted();
202 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200203 }
Jason Monk297c04e2018-08-23 17:16:59 -0400204 Dependency.get(InitController.class).executePostInitTasks();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700205 log.traceEnd();
Beverly97b8ce12019-02-01 16:55:48 -0500206 final Handler mainHandler = new Handler(Looper.getMainLooper());
Jason Monk5bec68f2017-02-08 20:45:10 -0800207 Dependency.get(PluginManager.class).addPluginListener(
Jason Monk86bc3312016-08-16 13:17:56 -0400208 new PluginListener<OverlayPlugin>() {
beverlytf9dfd232019-05-06 12:14:22 -0700209 private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
Jason Monk421a9412017-02-06 09:15:21 -0800210
211 @Override
212 public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
Beverly97b8ce12019-02-01 16:55:48 -0500213 mainHandler.post(new Runnable() {
214 @Override
215 public void run() {
216 StatusBar statusBar = getComponent(StatusBar.class);
217 if (statusBar != null) {
218 plugin.setup(statusBar.getStatusBarWindow(),
Beverly1488f692019-06-07 09:32:46 -0400219 statusBar.getNavigationBarView(), new Callback(plugin),
220 DozeParameters.getInstance(getBaseContext()));
Beverly97b8ce12019-02-01 16:55:48 -0500221 }
222 }
223 });
Jason Monk421a9412017-02-06 09:15:21 -0800224 }
225
226 @Override
227 public void onPluginDisconnected(OverlayPlugin plugin) {
Beverly97b8ce12019-02-01 16:55:48 -0500228 mainHandler.post(new Runnable() {
229 @Override
230 public void run() {
231 mOverlays.remove(plugin);
232 Dependency.get(StatusBarWindowController.class).setForcePluginOpen(
233 mOverlays.size() != 0);
234 }
235 });
Jason Monk421a9412017-02-06 09:15:21 -0800236 }
beverlytf9dfd232019-05-06 12:14:22 -0700237
238 class Callback implements OverlayPlugin.Callback {
239 private final OverlayPlugin mPlugin;
240
241 Callback(OverlayPlugin plugin) {
242 mPlugin = plugin;
243 }
244
245 @Override
246 public void onHoldStatusBarOpenChange() {
247 if (mPlugin.holdStatusBarOpen()) {
248 mOverlays.add(mPlugin);
249 } else {
250 mOverlays.remove(mPlugin);
251 }
252 mainHandler.post(new Runnable() {
253 @Override
254 public void run() {
255 Dependency.get(StatusBarWindowController.class)
256 .setStateListener(b -> mOverlays.forEach(
257 o -> o.setCollapseDesired(b)));
258 Dependency.get(StatusBarWindowController.class)
259 .setForcePluginOpen(mOverlays.size() != 0);
260 }
261 });
262 }
263 }
Jason Monk5bec68f2017-02-08 20:45:10 -0800264 }, OverlayPlugin.class, true /* Allow multiple plugins */);
Jason Monk86bc3312016-08-16 13:17:56 -0400265
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200266 mServicesStarted = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200267 }
268
269 @Override
270 public void onConfigurationChanged(Configuration newConfig) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200271 if (mServicesStarted) {
272 int len = mServices.length;
273 for (int i = 0; i < len; i++) {
Winson94a14852015-09-23 12:44:33 -0700274 if (mServices[i] != null) {
275 mServices[i].onConfigurationChanged(newConfig);
276 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200277 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200278 }
279 }
280
281 @SuppressWarnings("unchecked")
282 public <T> T getComponent(Class<T> interfaceType) {
283 return (T) mComponents.get(interfaceType);
284 }
285
286 public SystemUI[] getServices() {
287 return mServices;
288 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200289}