blob: f0317b4a02d0761e494b88b9db55e9706e96940b [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;
Winsonfe67aba2015-09-22 14:04:46 -070027import android.os.Process;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040028import android.os.SystemProperties;
Fyodor Kupolovf3591352017-06-23 18:20:40 -070029import android.os.Trace;
Winsonfe67aba2015-09-22 14:04:46 -070030import android.os.UserHandle;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020031import android.util.Log;
Beverly70dcd002018-03-29 17:09:16 -040032import android.util.TimingsTraceLog;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020033
Dave Mankofff4736812019-10-18 17:25:50 -040034import com.android.systemui.dagger.ContextComponentHelper;
Dan Sandler8e032e12017-01-25 13:41:38 -050035import com.android.systemui.util.NotificationChannels;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010036
Dave Mankoffa5d8a392019-10-10 12:21:09 -040037import java.lang.reflect.Constructor;
38import java.lang.reflect.InvocationTargetException;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020039
40/**
41 * Application class for SystemUI.
42 */
Dave Mankoff95754e72019-11-14 11:39:18 -050043public class SystemUIApplication extends Application implements
Dave Mankoffe2294692019-08-14 11:53:13 -040044 SystemUIAppComponentFactory.ContextInitializer {
Jorim Jaggicff0acb2014-03-31 16:35:15 +020045
Dan Sandlerdc2ddd72018-01-24 16:09:53 -050046 public static final String TAG = "SystemUIService";
Jorim Jaggicff0acb2014-03-31 16:35:15 +020047 private static final boolean DEBUG = false;
48
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -040049 private ContextComponentHelper mComponentHelper;
50
Jorim Jaggicff0acb2014-03-31 16:35:15 +020051 /**
Jorim Jaggicff0acb2014-03-31 16:35:15 +020052 * Hold a reference on the stuff we start.
53 */
yoshiki iguchi61b37082017-11-29 16:46:32 +090054 private SystemUI[] mServices;
Jorim Jaggi3beffdf2014-04-03 17:37:37 +020055 private boolean mServicesStarted;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040056 private boolean mBootCompleted;
Dave Mankoffa4a71362019-08-27 14:40:05 -040057 private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020058
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070059 public SystemUIApplication() {
60 super();
61 Log.v(TAG, "SystemUIApplication constructed.");
62 }
63
Adrian Roos070a0b62014-04-10 23:25:03 +020064 @Override
65 public void onCreate() {
66 super.onCreate();
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070067 Log.v(TAG, "SystemUIApplication created.");
Dave Mankoff2ea5a832019-07-03 13:26:55 -040068 // This line is used to setup Dagger's dependency injection and should be kept at the
69 // top of this method.
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070070 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
71 Trace.TRACE_TAG_APP);
72 log.traceBegin("DependencyInjection");
Dave Mankoff2ea5a832019-07-03 13:26:55 -040073 mContextAvailableCallback.onContextAvailable(this);
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -040074 mComponentHelper = SystemUIFactory
75 .getInstance().getRootComponent().getContextComponentHelper();
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070076 log.traceEnd();
Dave Mankoff2ea5a832019-07-03 13:26:55 -040077
Adrian Roos070a0b62014-04-10 23:25:03 +020078 // Set the application theme that is inherited by all services. Note that setting the
79 // application theme in the manifest does only work for activities. Keep this in sync with
80 // the theme set there.
Lucas Dupine17ce522017-07-17 15:45:06 -070081 setTheme(R.style.Theme_SystemUI);
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040082
Winsonfe67aba2015-09-22 14:04:46 -070083 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
Beverly6ea063e2018-04-19 10:27:06 -040084 IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
85 bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Winsonfe67aba2015-09-22 14:04:46 -070086 registerReceiver(new BroadcastReceiver() {
87 @Override
88 public void onReceive(Context context, Intent intent) {
89 if (mBootCompleted) return;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040090
Winsonfe67aba2015-09-22 14:04:46 -070091 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
92 unregisterReceiver(this);
93 mBootCompleted = true;
94 if (mServicesStarted) {
95 final int N = mServices.length;
96 for (int i = 0; i < N; i++) {
97 mServices[i].onBootCompleted();
98 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040099 }
Beverly70dcd002018-03-29 17:09:16 -0400100
Beverly6ea063e2018-04-19 10:27:06 -0400101
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400102 }
Beverly6ea063e2018-04-19 10:27:06 -0400103 }, bootCompletedFilter);
104
105 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
106 registerReceiver(new BroadcastReceiver() {
107 @Override
108 public void onReceive(Context context, Intent intent) {
109 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
110 if (!mBootCompleted) return;
111 // Update names of SystemUi notification channels
112 NotificationChannels.createAll(context);
113 }
114 }
115 }, localeChangedFilter);
Winsonfe67aba2015-09-22 14:04:46 -0700116 } else {
dooyoung.hwangb6479842016-08-31 14:15:22 +0900117 // We don't need to startServices for sub-process that is doing some tasks.
118 // (screenshots, sweetsweetdesserts or tuner ..)
119 String processName = ActivityThread.currentProcessName();
120 ApplicationInfo info = getApplicationInfo();
121 if (processName != null && processName.startsWith(info.processName + ":")) {
122 return;
123 }
Winsonfe67aba2015-09-22 14:04:46 -0700124 // For a secondary user, boot-completed will never be called because it has already
125 // been broadcasted on startup for the primary SystemUI process. Instead, for
126 // components which require the SystemUI component to be initialized per-user, we
127 // start those components now for the current non-system user.
yoshiki iguchi61b37082017-11-29 16:46:32 +0900128 startSecondaryUserServicesIfNeeded();
Winsonfe67aba2015-09-22 14:04:46 -0700129 }
Adrian Roos070a0b62014-04-10 23:25:03 +0200130 }
131
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200132 /**
133 * Makes sure that all the SystemUI services are running. If they are already running, this is a
134 * no-op. This is needed to conditinally start all the services, as we only need to have it in
135 * the main process.
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200136 * <p>This method must only be called from the main thread.</p>
137 */
Jason Monkbe3235a2017-04-05 09:29:53 -0400138
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200139 public void startServicesIfNeeded() {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900140 String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
Heemin Seog7d884762019-11-08 10:09:10 -0800141 startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
Winsonfe67aba2015-09-22 14:04:46 -0700142 }
143
Winson3c2c34b2016-04-04 17:47:41 -0700144 /**
145 * Ensures that all the Secondary user SystemUI services are running. If they are already
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -0700146 * running, this is a no-op. This is needed to conditionally start all the services, as we only
Winson3c2c34b2016-04-04 17:47:41 -0700147 * need to have it in the main process.
Winson3c2c34b2016-04-04 17:47:41 -0700148 * <p>This method must only be called from the main thread.</p>
149 */
150 void startSecondaryUserServicesIfNeeded() {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900151 String[] names =
152 getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
Heemin Seog7d884762019-11-08 10:09:10 -0800153 startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
Winson3c2c34b2016-04-04 17:47:41 -0700154 }
155
Heemin Seog7d884762019-11-08 10:09:10 -0800156 private void startServicesIfNeeded(String metricsPrefix, String[] services) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200157 if (mServicesStarted) {
158 return;
159 }
yoshiki iguchi61b37082017-11-29 16:46:32 +0900160 mServices = new SystemUI[services.length];
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400161
162 if (!mBootCompleted) {
163 // check to see if maybe it was already completed long before we began
164 // see ActivityManagerService.finishBooting()
165 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
166 mBootCompleted = true;
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -0700167 if (DEBUG) {
168 Log.v(TAG, "BOOT_COMPLETED was already sent");
169 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400170 }
171 }
172
Winsonfe67aba2015-09-22 14:04:46 -0700173 Log.v(TAG, "Starting SystemUI services for user " +
174 Process.myUserHandle().getIdentifier() + ".");
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -0700175 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700176 Trace.TRACE_TAG_APP);
Heemin Seog7d884762019-11-08 10:09:10 -0800177 log.traceBegin(metricsPrefix);
Winsonfe67aba2015-09-22 14:04:46 -0700178 final int N = services.length;
Jason Monk421a9412017-02-06 09:15:21 -0800179 for (int i = 0; i < N; i++) {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900180 String clsName = services[i];
181 if (DEBUG) Log.d(TAG, "loading: " + clsName);
Heemin Seog7d884762019-11-08 10:09:10 -0800182 log.traceBegin(metricsPrefix + clsName);
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700183 long ti = System.currentTimeMillis();
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200184 try {
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400185 SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
186 if (obj == null) {
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400187 Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
188 obj = (SystemUI) constructor.newInstance(this);
Jason Monk27d01a622018-12-10 15:57:09 -0500189 }
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400190 mServices[i] = obj;
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400191 } catch (ClassNotFoundException
192 | NoSuchMethodException
193 | IllegalAccessException
194 | InstantiationException
195 | InvocationTargetException ex) {
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200196 throw new RuntimeException(ex);
197 }
Muyuan Li94ce94e2016-02-24 16:20:54 -0800198
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200199 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
200 mServices[i].start();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700201 log.traceEnd();
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400202
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700203 // Warn if initialization of component takes too long
204 ti = System.currentTimeMillis() - ti;
205 if (ti > 1000) {
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400206 Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700207 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400208 if (mBootCompleted) {
209 mServices[i].onBootCompleted();
210 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200211 }
Jason Monk297c04e2018-08-23 17:16:59 -0400212 Dependency.get(InitController.class).executePostInitTasks();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700213 log.traceEnd();
Jason Monk86bc3312016-08-16 13:17:56 -0400214
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200215 mServicesStarted = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200216 }
217
218 @Override
219 public void onConfigurationChanged(Configuration newConfig) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200220 if (mServicesStarted) {
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -0700221 Dependency.staticOnConfigurationChanged(newConfig);
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200222 int len = mServices.length;
223 for (int i = 0; i < len; i++) {
Winson94a14852015-09-23 12:44:33 -0700224 if (mServices[i] != null) {
225 mServices[i].onConfigurationChanged(newConfig);
226 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200227 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200228 }
229 }
230
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200231 public SystemUI[] getServices() {
232 return mServices;
233 }
Dave Mankoff2ea5a832019-07-03 13:26:55 -0400234
Dave Mankoffa4a71362019-08-27 14:40:05 -0400235 @Override
236 public void setContextAvailableCallback(
237 SystemUIAppComponentFactory.ContextAvailableCallback callback) {
Dave Mankoff2ea5a832019-07-03 13:26:55 -0400238 mContextAvailableCallback = callback;
239 }
240
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200241}