blob: 4a459974fcb63fcb663bdabdd3d7ffd6b1c8422e [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;
Jason Monk421a9412017-02-06 09:15:21 -080030import android.util.ArraySet;
Jorim Jaggicff0acb2014-03-31 16:35:15 +020031import android.util.Log;
32
Jason Monkbbac1212016-10-31 10:18:20 -040033import com.android.systemui.fragments.FragmentService;
Jason Monk361915c2017-03-21 20:33:59 -040034import com.android.systemui.globalactions.GlobalActionsComponent;
Jorim Jaggic3fe2042016-10-07 18:52:48 +020035import com.android.systemui.keyboard.KeyboardUI;
36import com.android.systemui.keyguard.KeyguardViewMediator;
37import com.android.systemui.media.RingtonePlayer;
Jason Monk97a06a12016-11-09 15:53:30 -050038import com.android.systemui.pip.PipUI;
Jason Monk361915c2017-03-21 20:33:59 -040039import com.android.systemui.plugins.GlobalActions;
Jason Monk86bc3312016-08-16 13:17:56 -040040import com.android.systemui.plugins.OverlayPlugin;
Jason Monk5bec68f2017-02-08 20:45:10 -080041import com.android.systemui.plugins.Plugin;
Jason Monk86bc3312016-08-16 13:17:56 -040042import com.android.systemui.plugins.PluginListener;
43import com.android.systemui.plugins.PluginManager;
Jorim Jaggic3fe2042016-10-07 18:52:48 +020044import com.android.systemui.power.PowerUI;
45import com.android.systemui.recents.Recents;
46import com.android.systemui.shortcut.ShortcutKeyDispatcher;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010047import com.android.systemui.stackdivider.Divider;
Jason Monkb5b092012017-01-05 11:35:34 -050048import com.android.systemui.statusbar.CommandQueue;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050049import com.android.systemui.statusbar.phone.StatusBar;
Jason Monk421a9412017-02-06 09:15:21 -080050import com.android.systemui.statusbar.phone.StatusBarWindowManager;
Jorim Jaggic3fe2042016-10-07 18:52:48 +020051import com.android.systemui.tuner.TunerService;
Jorim Jaggic3fe2042016-10-07 18:52:48 +020052import com.android.systemui.usb.StorageNotification;
Dan Sandler8e032e12017-01-25 13:41:38 -050053import com.android.systemui.util.NotificationChannels;
Adrian Roos91250682017-02-06 14:48:15 -080054import com.android.systemui.util.leak.GarbageMonitor;
Jorim Jaggic3fe2042016-10-07 18:52:48 +020055import com.android.systemui.volume.VolumeUI;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010056
Jorim Jaggicff0acb2014-03-31 16:35:15 +020057import java.util.HashMap;
58import java.util.Map;
59
60/**
61 * Application class for SystemUI.
62 */
Jason Monk49fa0162017-01-11 09:21:56 -050063public class SystemUIApplication extends Application implements SysUiServiceProvider {
Jorim Jaggicff0acb2014-03-31 16:35:15 +020064
65 private static final String TAG = "SystemUIService";
66 private static final boolean DEBUG = false;
67
68 /**
69 * The classes of the stuff to start.
70 */
71 private final Class<?>[] SERVICES = new Class[] {
Jason Monk9c7844c2017-01-18 15:21:53 -050072 Dependency.class,
Dan Sandler8e032e12017-01-25 13:41:38 -050073 NotificationChannels.class,
Jason Monkb5b092012017-01-05 11:35:34 -050074 CommandQueue.CommandQueueStart.class,
Jorim Jaggic3fe2042016-10-07 18:52:48 +020075 KeyguardViewMediator.class,
76 Recents.class,
77 VolumeUI.class,
Jorim Jaggidd98d412015-11-18 15:57:38 -080078 Divider.class,
Jorim Jaggic3fe2042016-10-07 18:52:48 +020079 SystemBars.class,
80 StorageNotification.class,
81 PowerUI.class,
82 RingtonePlayer.class,
83 KeyboardUI.class,
84 PipUI.class,
85 ShortcutKeyDispatcher.class,
86 VendorServices.class,
Adrian Roos91250682017-02-06 14:48:15 -080087 GarbageMonitor.Service.class,
Adrian Roosf9d13f62016-11-08 15:42:20 -080088 LatencyTester.class,
Jason Monk361915c2017-03-21 20:33:59 -040089 GlobalActionsComponent.class,
Jason Monkd4afe152017-05-01 15:37:43 -040090 RoundedCorners.class,
Jorim Jaggicff0acb2014-03-31 16:35:15 +020091 };
92
93 /**
Winsonfe67aba2015-09-22 14:04:46 -070094 * The classes of the stuff to start for each user. This is a subset of the services listed
95 * above.
96 */
97 private final Class<?>[] SERVICES_PER_USER = new Class[] {
Winson Chung0c7592f2017-02-06 09:04:07 -080098 Dependency.class,
Geoffrey Pitsch790e0912017-03-24 13:37:13 -040099 NotificationChannels.class,
Winson Chung853c99a2017-03-21 22:16:42 -0700100 Recents.class
Winsonfe67aba2015-09-22 14:04:46 -0700101 };
102
103 /**
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200104 * Hold a reference on the stuff we start.
105 */
106 private final SystemUI[] mServices = new SystemUI[SERVICES.length];
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200107 private boolean mServicesStarted;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400108 private boolean mBootCompleted;
Winsonfe67aba2015-09-22 14:04:46 -0700109 private final Map<Class<?>, Object> mComponents = new HashMap<>();
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200110
Adrian Roos070a0b62014-04-10 23:25:03 +0200111 @Override
112 public void onCreate() {
113 super.onCreate();
114 // Set the application theme that is inherited by all services. Note that setting the
115 // application theme in the manifest does only work for activities. Keep this in sync with
116 // the theme set there.
117 setTheme(R.style.systemui_theme);
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400118
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800119 SystemUIFactory.createFromConfig(this);
120
Winsonfe67aba2015-09-22 14:04:46 -0700121 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
122 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
123 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
124 registerReceiver(new BroadcastReceiver() {
125 @Override
126 public void onReceive(Context context, Intent intent) {
127 if (mBootCompleted) return;
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400128
Winsonfe67aba2015-09-22 14:04:46 -0700129 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
130 unregisterReceiver(this);
131 mBootCompleted = true;
132 if (mServicesStarted) {
133 final int N = mServices.length;
134 for (int i = 0; i < N; i++) {
135 mServices[i].onBootCompleted();
136 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400137 }
138 }
Winsonfe67aba2015-09-22 14:04:46 -0700139 }, filter);
140 } else {
dooyoung.hwangb6479842016-08-31 14:15:22 +0900141 // We don't need to startServices for sub-process that is doing some tasks.
142 // (screenshots, sweetsweetdesserts or tuner ..)
143 String processName = ActivityThread.currentProcessName();
144 ApplicationInfo info = getApplicationInfo();
145 if (processName != null && processName.startsWith(info.processName + ":")) {
146 return;
147 }
Winsonfe67aba2015-09-22 14:04:46 -0700148 // For a secondary user, boot-completed will never be called because it has already
149 // been broadcasted on startup for the primary SystemUI process. Instead, for
150 // components which require the SystemUI component to be initialized per-user, we
151 // start those components now for the current non-system user.
152 startServicesIfNeeded(SERVICES_PER_USER);
153 }
Adrian Roos070a0b62014-04-10 23:25:03 +0200154 }
155
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200156 /**
157 * Makes sure that all the SystemUI services are running. If they are already running, this is a
158 * no-op. This is needed to conditinally start all the services, as we only need to have it in
159 * the main process.
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200160 * <p>This method must only be called from the main thread.</p>
161 */
Jason Monkbe3235a2017-04-05 09:29:53 -0400162
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200163 public void startServicesIfNeeded() {
Winsonfe67aba2015-09-22 14:04:46 -0700164 startServicesIfNeeded(SERVICES);
165 }
166
Winson3c2c34b2016-04-04 17:47:41 -0700167 /**
168 * Ensures that all the Secondary user SystemUI services are running. If they are already
169 * running, this is a no-op. This is needed to conditinally start all the services, as we only
170 * need to have it in the main process.
Winson3c2c34b2016-04-04 17:47:41 -0700171 * <p>This method must only be called from the main thread.</p>
172 */
173 void startSecondaryUserServicesIfNeeded() {
174 startServicesIfNeeded(SERVICES_PER_USER);
175 }
176
Winsonfe67aba2015-09-22 14:04:46 -0700177 private void startServicesIfNeeded(Class<?>[] services) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200178 if (mServicesStarted) {
179 return;
180 }
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400181
182 if (!mBootCompleted) {
183 // check to see if maybe it was already completed long before we began
184 // see ActivityManagerService.finishBooting()
185 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
186 mBootCompleted = true;
187 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
188 }
189 }
190
Winsonfe67aba2015-09-22 14:04:46 -0700191 Log.v(TAG, "Starting SystemUI services for user " +
192 Process.myUserHandle().getIdentifier() + ".");
193 final int N = services.length;
Jason Monk421a9412017-02-06 09:15:21 -0800194 for (int i = 0; i < N; i++) {
Winsonfe67aba2015-09-22 14:04:46 -0700195 Class<?> cl = services[i];
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200196 if (DEBUG) Log.d(TAG, "loading: " + cl);
197 try {
Muyuan Li94ce94e2016-02-24 16:20:54 -0800198 Object newService = SystemUIFactory.getInstance().createInstance(cl);
199 mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200200 } catch (IllegalAccessException ex) {
201 throw new RuntimeException(ex);
202 } catch (InstantiationException ex) {
203 throw new RuntimeException(ex);
204 }
Muyuan Li94ce94e2016-02-24 16:20:54 -0800205
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200206 mServices[i].mContext = this;
207 mServices[i].mComponents = mComponents;
208 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
209 mServices[i].start();
Dan Sandlerdc5f16b2014-04-22 11:51:42 -0400210
211 if (mBootCompleted) {
212 mServices[i].onBootCompleted();
213 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200214 }
Jason Monk5bec68f2017-02-08 20:45:10 -0800215 Dependency.get(PluginManager.class).addPluginListener(
Jason Monk86bc3312016-08-16 13:17:56 -0400216 new PluginListener<OverlayPlugin>() {
Jason Monk421a9412017-02-06 09:15:21 -0800217 private ArraySet<OverlayPlugin> mOverlays;
218
219 @Override
220 public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
221 StatusBar statusBar = getComponent(StatusBar.class);
222 if (statusBar != null) {
223 plugin.setup(statusBar.getStatusBarWindow(),
224 statusBar.getNavigationBarView());
225 }
226 // Lazy init.
227 if (mOverlays == null) mOverlays = new ArraySet<>();
228 if (plugin.holdStatusBarOpen()) {
229 mOverlays.add(plugin);
230 Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
231 mOverlays.forEach(o -> o.setCollapseDesired(b)));
232 Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
233 mOverlays.size() != 0);
234
235 }
236 }
237
238 @Override
239 public void onPluginDisconnected(OverlayPlugin plugin) {
240 mOverlays.remove(plugin);
241 Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
242 mOverlays.size() != 0);
243 }
Jason Monk5bec68f2017-02-08 20:45:10 -0800244 }, OverlayPlugin.class, true /* Allow multiple plugins */);
Jason Monk86bc3312016-08-16 13:17:56 -0400245
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200246 mServicesStarted = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200247 }
248
249 @Override
250 public void onConfigurationChanged(Configuration newConfig) {
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200251 if (mServicesStarted) {
252 int len = mServices.length;
253 for (int i = 0; i < len; i++) {
Winson94a14852015-09-23 12:44:33 -0700254 if (mServices[i] != null) {
255 mServices[i].onConfigurationChanged(newConfig);
256 }
Jorim Jaggi3beffdf2014-04-03 17:37:37 +0200257 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200258 }
259 }
260
261 @SuppressWarnings("unchecked")
262 public <T> T getComponent(Class<T> interfaceType) {
263 return (T) mComponents.get(interfaceType);
264 }
265
266 public SystemUI[] getServices() {
267 return mServices;
268 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200269}