blob: c84701c9512e3c5345c8f6e65c6926c2c903f87c [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;
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -050035import com.android.systemui.dagger.SystemUIRootComponent;
Ned Burnsc7cfa692020-02-12 21:38:50 -050036import com.android.systemui.dump.DumpManager;
Dan Sandler8e032e12017-01-25 13:41:38 -050037import com.android.systemui.util.NotificationChannels;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010038
Dave Mankoffa5d8a392019-10-10 12:21:09 -040039import java.lang.reflect.Constructor;
40import java.lang.reflect.InvocationTargetException;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020041
42/**
43 * Application class for SystemUI.
44 */
Dave Mankoff95754e72019-11-14 11:39:18 -050045public class SystemUIApplication extends Application implements
Dave Mankoffe2294692019-08-14 11:53:13 -040046 SystemUIAppComponentFactory.ContextInitializer {
Jorim Jaggicff0acb2014-03-31 16:35:15 +020047
Dan Sandlerdc2ddd72018-01-24 16:09:53 -050048 public static final String TAG = "SystemUIService";
Jorim Jaggicff0acb2014-03-31 16:35:15 +020049 private static final boolean DEBUG = false;
50
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -040051 private ContextComponentHelper mComponentHelper;
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -050052 private BootCompleteCacheImpl mBootCompleteCache;
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -040053
Jorim Jaggicff0acb2014-03-31 16:35:15 +020054 /**
Jorim Jaggicff0acb2014-03-31 16:35:15 +020055 * Hold a reference on the stuff we start.
56 */
yoshiki iguchi61b37082017-11-29 16:46:32 +090057 private SystemUI[] mServices;
Jorim Jaggi3beffdf2014-04-03 17:37:37 +020058 private boolean mServicesStarted;
Dave Mankoffa4a71362019-08-27 14:40:05 -040059 private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
Dave Mankoff71fca1a2019-12-19 14:16:32 -050060 private SystemUIRootComponent mRootComponent;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020061
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070062 public SystemUIApplication() {
63 super();
64 Log.v(TAG, "SystemUIApplication constructed.");
65 }
66
Adrian Roos070a0b62014-04-10 23:25:03 +020067 @Override
68 public void onCreate() {
69 super.onCreate();
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070070 Log.v(TAG, "SystemUIApplication created.");
Dave Mankoff2ea5a832019-07-03 13:26:55 -040071 // This line is used to setup Dagger's dependency injection and should be kept at the
72 // top of this method.
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070073 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
74 Trace.TRACE_TAG_APP);
75 log.traceBegin("DependencyInjection");
Dave Mankoff2ea5a832019-07-03 13:26:55 -040076 mContextAvailableCallback.onContextAvailable(this);
Dave Mankoff71fca1a2019-12-19 14:16:32 -050077 mRootComponent = SystemUIFactory.getInstance().getRootComponent();
78 mComponentHelper = mRootComponent.getContextComponentHelper();
79 mBootCompleteCache = mRootComponent.provideBootCacheImpl();
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070080 log.traceEnd();
Dave Mankoff2ea5a832019-07-03 13:26:55 -040081
Adrian Roos070a0b62014-04-10 23:25:03 +020082 // Set the application theme that is inherited by all services. Note that setting the
83 // application theme in the manifest does only work for activities. Keep this in sync with
84 // the theme set there.
Lucas Dupine17ce522017-07-17 15:45:06 -070085 setTheme(R.style.Theme_SystemUI);
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040086
Winsonfe67aba2015-09-22 14:04:46 -070087 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
Beverly6ea063e2018-04-19 10:27:06 -040088 IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
89 bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Winsonfe67aba2015-09-22 14:04:46 -070090 registerReceiver(new BroadcastReceiver() {
91 @Override
92 public void onReceive(Context context, Intent intent) {
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -050093 if (mBootCompleteCache.isBootComplete()) return;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040094
Winsonfe67aba2015-09-22 14:04:46 -070095 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
96 unregisterReceiver(this);
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -050097 mBootCompleteCache.setBootComplete();
Winsonfe67aba2015-09-22 14:04:46 -070098 if (mServicesStarted) {
99 final int N = mServices.length;
100 for (int i = 0; i < N; i++) {
101 mServices[i].onBootCompleted();
102 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400103 }
104 }
Beverly6ea063e2018-04-19 10:27:06 -0400105 }, bootCompletedFilter);
106
107 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
108 registerReceiver(new BroadcastReceiver() {
109 @Override
110 public void onReceive(Context context, Intent intent) {
111 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -0500112 if (!mBootCompleteCache.isBootComplete()) return;
Beverly6ea063e2018-04-19 10:27:06 -0400113 // Update names of SystemUi notification channels
114 NotificationChannels.createAll(context);
115 }
116 }
117 }, localeChangedFilter);
Winsonfe67aba2015-09-22 14:04:46 -0700118 } else {
dooyoung.hwangb6479842016-08-31 14:15:22 +0900119 // We don't need to startServices for sub-process that is doing some tasks.
120 // (screenshots, sweetsweetdesserts or tuner ..)
121 String processName = ActivityThread.currentProcessName();
122 ApplicationInfo info = getApplicationInfo();
123 if (processName != null && processName.startsWith(info.processName + ":")) {
124 return;
125 }
Winsonfe67aba2015-09-22 14:04:46 -0700126 // For a secondary user, boot-completed will never be called because it has already
127 // been broadcasted on startup for the primary SystemUI process. Instead, for
128 // components which require the SystemUI component to be initialized per-user, we
129 // start those components now for the current non-system user.
yoshiki iguchi61b37082017-11-29 16:46:32 +0900130 startSecondaryUserServicesIfNeeded();
Winsonfe67aba2015-09-22 14:04:46 -0700131 }
Adrian Roos070a0b62014-04-10 23:25:03 +0200132 }
133
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200134 /**
135 * Makes sure that all the SystemUI services are running. If they are already running, this is a
136 * no-op. This is needed to conditinally start all the services, as we only need to have it in
137 * the main process.
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200138 * <p>This method must only be called from the main thread.</p>
139 */
Jason Monkbe3235a2017-04-05 09:29:53 -0400140
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200141 public void startServicesIfNeeded() {
Heemin Seog8277c312020-04-27 10:12:14 -0700142 String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
Heemin Seog7d884762019-11-08 10:09:10 -0800143 startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
Winsonfe67aba2015-09-22 14:04:46 -0700144 }
145
Winson3c2c34b2016-04-04 17:47:41 -0700146 /**
147 * Ensures that all the Secondary user SystemUI services are running. If they are already
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -0700148 * running, this is a no-op. This is needed to conditionally start all the services, as we only
Winson3c2c34b2016-04-04 17:47:41 -0700149 * need to have it in the main process.
Winson3c2c34b2016-04-04 17:47:41 -0700150 * <p>This method must only be called from the main thread.</p>
151 */
152 void startSecondaryUserServicesIfNeeded() {
Heemin Seog8277c312020-04-27 10:12:14 -0700153 String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponentsPerUser(
154 getResources());
Heemin Seog7d884762019-11-08 10:09:10 -0800155 startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
Winson3c2c34b2016-04-04 17:47:41 -0700156 }
157
Heemin Seog7d884762019-11-08 10:09:10 -0800158 private void startServicesIfNeeded(String metricsPrefix, String[] services) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200159 if (mServicesStarted) {
160 return;
161 }
yoshiki iguchi61b37082017-11-29 16:46:32 +0900162 mServices = new SystemUI[services.length];
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400163
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -0500164 if (!mBootCompleteCache.isBootComplete()) {
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400165 // check to see if maybe it was already completed long before we began
166 // see ActivityManagerService.finishBooting()
167 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -0500168 mBootCompleteCache.setBootComplete();
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -0700169 if (DEBUG) {
170 Log.v(TAG, "BOOT_COMPLETED was already sent");
171 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400172 }
173 }
174
Ned Burnsc7cfa692020-02-12 21:38:50 -0500175 final DumpManager dumpManager = mRootComponent.createDumpManager();
176
Winsonfe67aba2015-09-22 14:04:46 -0700177 Log.v(TAG, "Starting SystemUI services for user " +
178 Process.myUserHandle().getIdentifier() + ".");
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -0700179 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700180 Trace.TRACE_TAG_APP);
Heemin Seog7d884762019-11-08 10:09:10 -0800181 log.traceBegin(metricsPrefix);
Winsonfe67aba2015-09-22 14:04:46 -0700182 final int N = services.length;
Jason Monk421a9412017-02-06 09:15:21 -0800183 for (int i = 0; i < N; i++) {
yoshiki iguchi61b37082017-11-29 16:46:32 +0900184 String clsName = services[i];
185 if (DEBUG) Log.d(TAG, "loading: " + clsName);
Heemin Seog7d884762019-11-08 10:09:10 -0800186 log.traceBegin(metricsPrefix + clsName);
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700187 long ti = System.currentTimeMillis();
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200188 try {
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400189 SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
190 if (obj == null) {
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400191 Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
192 obj = (SystemUI) constructor.newInstance(this);
Jason Monk27d01a622018-12-10 15:57:09 -0500193 }
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400194 mServices[i] = obj;
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400195 } catch (ClassNotFoundException
196 | NoSuchMethodException
197 | IllegalAccessException
198 | InstantiationException
199 | InvocationTargetException ex) {
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200200 throw new RuntimeException(ex);
201 }
Muyuan Li94ce94e2016-02-24 16:20:54 -0800202
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200203 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
204 mServices[i].start();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700205 log.traceEnd();
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400206
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700207 // Warn if initialization of component takes too long
208 ti = System.currentTimeMillis() - ti;
209 if (ti > 1000) {
Dave Mankoffaa8b7ae2019-09-04 18:03:21 -0400210 Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700211 }
Fabian Kozynski1cb4aae2019-11-25 14:27:00 -0500212 if (mBootCompleteCache.isBootComplete()) {
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400213 mServices[i].onBootCompleted();
214 }
Ned Burnsc7cfa692020-02-12 21:38:50 -0500215
216 dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200217 }
Dave Mankoff71fca1a2019-12-19 14:16:32 -0500218 mRootComponent.getInitController().executePostInitTasks();
Fyodor Kupolovf3591352017-06-23 18:20:40 -0700219 log.traceEnd();
Jason Monk86bc3312016-08-16 13:17:56 -0400220
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200221 mServicesStarted = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200222 }
223
224 @Override
225 public void onConfigurationChanged(Configuration newConfig) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200226 if (mServicesStarted) {
Dave Mankoff71fca1a2019-12-19 14:16:32 -0500227 mRootComponent.getConfigurationController().onConfigurationChanged(newConfig);
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200228 int len = mServices.length;
229 for (int i = 0; i < len; i++) {
Winson94a14852015-09-23 12:44:33 -0700230 if (mServices[i] != null) {
231 mServices[i].onConfigurationChanged(newConfig);
232 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200233 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200234 }
235 }
236
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200237 public SystemUI[] getServices() {
238 return mServices;
239 }
Dave Mankoff2ea5a832019-07-03 13:26:55 -0400240
Dave Mankoffa4a71362019-08-27 14:40:05 -0400241 @Override
242 public void setContextAvailableCallback(
243 SystemUIAppComponentFactory.ContextAvailableCallback callback) {
Dave Mankoff2ea5a832019-07-03 13:26:55 -0400244 mContextAvailableCallback = callback;
245 }
246
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200247}