blob: 4b9ae2a37c6f7df4ceaf3aad8a86e9b093d73a20 [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;
Winsonfe67aba2015-09-22 14:04:46 -070029import android.os.UserHandle;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020030import android.util.Log;
31
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010032import com.android.systemui.stackdivider.Divider;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010033
Jorim Jaggicff0acb2014-03-31 16:35:15 +020034import java.util.HashMap;
35import java.util.Map;
36
37/**
38 * Application class for SystemUI.
39 */
40public class SystemUIApplication extends Application {
41
42 private static final String TAG = "SystemUIService";
43 private static final boolean DEBUG = false;
44
45 /**
46 * The classes of the stuff to start.
47 */
48 private final Class<?>[] SERVICES = new Class[] {
Jason Monk5e745172015-06-02 19:14:44 -040049 com.android.systemui.tuner.TunerService.class,
Jorim Jaggicff0acb2014-03-31 16:35:15 +020050 com.android.systemui.keyguard.KeyguardViewMediator.class,
Jorim Jaggid61f2272014-12-19 20:35:35 +010051 com.android.systemui.recents.Recents.class,
John Spurlock86005342014-05-23 11:58:00 -040052 com.android.systemui.volume.VolumeUI.class,
Jorim Jaggidd98d412015-11-18 15:57:38 -080053 Divider.class,
Jorim Jaggicff0acb2014-03-31 16:35:15 +020054 com.android.systemui.statusbar.SystemBars.class,
55 com.android.systemui.usb.StorageNotification.class,
56 com.android.systemui.power.PowerUI.class,
Jason Monk5e745172015-06-02 19:14:44 -040057 com.android.systemui.media.RingtonePlayer.class,
Michael Wright9209c9c2015-09-03 17:57:01 +010058 com.android.systemui.keyboard.KeyboardUI.class,
Muyuan Li94ce94e2016-02-24 16:20:54 -080059 com.android.systemui.tv.pip.PipUI.class,
Adrian Roos40ea0832016-07-14 14:19:55 -070060 com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
61 com.android.systemui.VendorServices.class
Jorim Jaggicff0acb2014-03-31 16:35:15 +020062 };
63
64 /**
Winsonfe67aba2015-09-22 14:04:46 -070065 * The classes of the stuff to start for each user. This is a subset of the services listed
66 * above.
67 */
68 private final Class<?>[] SERVICES_PER_USER = new Class[] {
Jaewan Kim6a29c3e2016-04-12 18:07:07 +090069 com.android.systemui.recents.Recents.class,
70 com.android.systemui.tv.pip.PipUI.class
Winsonfe67aba2015-09-22 14:04:46 -070071 };
72
73 /**
Jorim Jaggicff0acb2014-03-31 16:35:15 +020074 * Hold a reference on the stuff we start.
75 */
76 private final SystemUI[] mServices = new SystemUI[SERVICES.length];
Jorim Jaggi3beffdf2014-04-03 17:37:37 +020077 private boolean mServicesStarted;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040078 private boolean mBootCompleted;
Winsonfe67aba2015-09-22 14:04:46 -070079 private final Map<Class<?>, Object> mComponents = new HashMap<>();
Jorim Jaggicff0acb2014-03-31 16:35:15 +020080
Adrian Roos070a0b62014-04-10 23:25:03 +020081 @Override
82 public void onCreate() {
83 super.onCreate();
84 // Set the application theme that is inherited by all services. Note that setting the
85 // application theme in the manifest does only work for activities. Keep this in sync with
86 // the theme set there.
87 setTheme(R.style.systemui_theme);
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040088
Xiyuan Xia1b30f792016-01-06 08:50:30 -080089 SystemUIFactory.createFromConfig(this);
90
Winsonfe67aba2015-09-22 14:04:46 -070091 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
92 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
93 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
94 registerReceiver(new BroadcastReceiver() {
95 @Override
96 public void onReceive(Context context, Intent intent) {
97 if (mBootCompleted) return;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -040098
Winsonfe67aba2015-09-22 14:04:46 -070099 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
100 unregisterReceiver(this);
101 mBootCompleted = true;
102 if (mServicesStarted) {
103 final int N = mServices.length;
104 for (int i = 0; i < N; i++) {
105 mServices[i].onBootCompleted();
106 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400107 }
108 }
Winsonfe67aba2015-09-22 14:04:46 -0700109 }, filter);
110 } else {
dooyoung.hwangb6479842016-08-31 14:15:22 +0900111 // We don't need to startServices for sub-process that is doing some tasks.
112 // (screenshots, sweetsweetdesserts or tuner ..)
113 String processName = ActivityThread.currentProcessName();
114 ApplicationInfo info = getApplicationInfo();
115 if (processName != null && processName.startsWith(info.processName + ":")) {
116 return;
117 }
Winsonfe67aba2015-09-22 14:04:46 -0700118 // For a secondary user, boot-completed will never be called because it has already
119 // been broadcasted on startup for the primary SystemUI process. Instead, for
120 // components which require the SystemUI component to be initialized per-user, we
121 // start those components now for the current non-system user.
122 startServicesIfNeeded(SERVICES_PER_USER);
123 }
Adrian Roos070a0b62014-04-10 23:25:03 +0200124 }
125
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200126 /**
127 * Makes sure that all the SystemUI services are running. If they are already running, this is a
128 * no-op. This is needed to conditinally start all the services, as we only need to have it in
129 * the main process.
130 *
131 * <p>This method must only be called from the main thread.</p>
132 */
133 public void startServicesIfNeeded() {
Winsonfe67aba2015-09-22 14:04:46 -0700134 startServicesIfNeeded(SERVICES);
135 }
136
Winson3c2c34b2016-04-04 17:47:41 -0700137 /**
138 * Ensures that all the Secondary user SystemUI services are running. If they are already
139 * running, this is a no-op. This is needed to conditinally start all the services, as we only
140 * need to have it in the main process.
141 *
142 * <p>This method must only be called from the main thread.</p>
143 */
144 void startSecondaryUserServicesIfNeeded() {
145 startServicesIfNeeded(SERVICES_PER_USER);
146 }
147
Winsonfe67aba2015-09-22 14:04:46 -0700148 private void startServicesIfNeeded(Class<?>[] services) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200149 if (mServicesStarted) {
150 return;
151 }
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() + ".");
164 final int N = services.length;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200165 for (int i=0; i<N; i++) {
Winsonfe67aba2015-09-22 14:04:46 -0700166 Class<?> cl = services[i];
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200167 if (DEBUG) Log.d(TAG, "loading: " + cl);
168 try {
Muyuan Li94ce94e2016-02-24 16:20:54 -0800169 Object newService = SystemUIFactory.getInstance().createInstance(cl);
170 mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200171 } catch (IllegalAccessException ex) {
172 throw new RuntimeException(ex);
173 } catch (InstantiationException ex) {
174 throw new RuntimeException(ex);
175 }
Muyuan Li94ce94e2016-02-24 16:20:54 -0800176
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200177 mServices[i].mContext = this;
178 mServices[i].mComponents = mComponents;
179 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
180 mServices[i].start();
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400181
182 if (mBootCompleted) {
183 mServices[i].onBootCompleted();
184 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200185 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200186 mServicesStarted = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200187 }
188
189 @Override
190 public void onConfigurationChanged(Configuration newConfig) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200191 if (mServicesStarted) {
192 int len = mServices.length;
193 for (int i = 0; i < len; i++) {
Winson94a14852015-09-23 12:44:33 -0700194 if (mServices[i] != null) {
195 mServices[i].onConfigurationChanged(newConfig);
196 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200197 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200198 }
199 }
200
201 @SuppressWarnings("unchecked")
202 public <T> T getComponent(Class<T> interfaceType) {
203 return (T) mComponents.get(interfaceType);
204 }
205
206 public SystemUI[] getServices() {
207 return mServices;
208 }
209}