• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui;
18 
19 import android.app.ActivityThread;
20 import android.app.Application;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.ApplicationInfo;
26 import android.content.res.Configuration;
27 import android.os.Process;
28 import android.os.SystemProperties;
29 import android.os.Trace;
30 import android.os.UserHandle;
31 import android.util.ArraySet;
32 import android.util.TimingsTraceLog;
33 import android.util.Log;
34 
35 import com.android.systemui.globalactions.GlobalActionsComponent;
36 import com.android.systemui.keyboard.KeyboardUI;
37 import com.android.systemui.keyguard.KeyguardViewMediator;
38 import com.android.systemui.media.RingtonePlayer;
39 import com.android.systemui.pip.PipUI;
40 import com.android.systemui.plugins.GlobalActions;
41 import com.android.systemui.plugins.OverlayPlugin;
42 import com.android.systemui.plugins.Plugin;
43 import com.android.systemui.plugins.PluginListener;
44 import com.android.systemui.plugins.PluginManager;
45 import com.android.systemui.power.PowerUI;
46 import com.android.systemui.recents.Recents;
47 import com.android.systemui.shortcut.ShortcutKeyDispatcher;
48 import com.android.systemui.stackdivider.Divider;
49 import com.android.systemui.statusbar.CommandQueue;
50 import com.android.systemui.statusbar.phone.StatusBar;
51 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
52 import com.android.systemui.usb.StorageNotification;
53 import com.android.systemui.util.NotificationChannels;
54 import com.android.systemui.util.leak.GarbageMonitor;
55 import com.android.systemui.volume.VolumeUI;
56 
57 import java.util.HashMap;
58 import java.util.Map;
59 
60 /**
61  * Application class for SystemUI.
62  */
63 public class SystemUIApplication extends Application implements SysUiServiceProvider {
64 
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[] {
72             Dependency.class,
73             NotificationChannels.class,
74             CommandQueue.CommandQueueStart.class,
75             KeyguardViewMediator.class,
76             Recents.class,
77             VolumeUI.class,
78             Divider.class,
79             SystemBars.class,
80             StorageNotification.class,
81             PowerUI.class,
82             RingtonePlayer.class,
83             KeyboardUI.class,
84             PipUI.class,
85             ShortcutKeyDispatcher.class,
86             VendorServices.class,
87             GarbageMonitor.Service.class,
88             LatencyTester.class,
89             GlobalActionsComponent.class,
90             RoundedCorners.class,
91     };
92 
93     /**
94      * 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[] {
98             Dependency.class,
99             NotificationChannels.class,
100             Recents.class
101     };
102 
103     /**
104      * Hold a reference on the stuff we start.
105      */
106     private final SystemUI[] mServices = new SystemUI[SERVICES.length];
107     private boolean mServicesStarted;
108     private boolean mBootCompleted;
109     private final Map<Class<?>, Object> mComponents = new HashMap<>();
110 
111     @Override
onCreate()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.Theme_SystemUI);
118 
119         SystemUIFactory.createFromConfig(this);
120 
121         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;
128 
129                     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                         }
137                     }
138                 }
139             }, filter);
140         } else {
141             // 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             }
148             // 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         }
154     }
155 
156     /**
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.
160      * <p>This method must only be called from the main thread.</p>
161      */
162 
startServicesIfNeeded()163     public void startServicesIfNeeded() {
164         startServicesIfNeeded(SERVICES);
165     }
166 
167     /**
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.
171      * <p>This method must only be called from the main thread.</p>
172      */
startSecondaryUserServicesIfNeeded()173     void startSecondaryUserServicesIfNeeded() {
174         startServicesIfNeeded(SERVICES_PER_USER);
175     }
176 
startServicesIfNeeded(Class<?>[] services)177     private void startServicesIfNeeded(Class<?>[] services) {
178         if (mServicesStarted) {
179             return;
180         }
181 
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 
191         Log.v(TAG, "Starting SystemUI services for user " +
192                 Process.myUserHandle().getIdentifier() + ".");
193         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
194                 Trace.TRACE_TAG_APP);
195         log.traceBegin("StartServices");
196         final int N = services.length;
197         for (int i = 0; i < N; i++) {
198             Class<?> cl = services[i];
199             if (DEBUG) Log.d(TAG, "loading: " + cl);
200             log.traceBegin("StartServices" + cl.getSimpleName());
201             long ti = System.currentTimeMillis();
202             try {
203 
204                 Object newService = SystemUIFactory.getInstance().createInstance(cl);
205                 mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
206             } catch (IllegalAccessException ex) {
207                 throw new RuntimeException(ex);
208             } catch (InstantiationException ex) {
209                 throw new RuntimeException(ex);
210             }
211 
212             mServices[i].mContext = this;
213             mServices[i].mComponents = mComponents;
214             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
215             mServices[i].start();
216             log.traceEnd();
217 
218             // Warn if initialization of component takes too long
219             ti = System.currentTimeMillis() - ti;
220             if (ti > 1000) {
221                 Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
222             }
223             if (mBootCompleted) {
224                 mServices[i].onBootCompleted();
225             }
226         }
227         log.traceEnd();
228         Dependency.get(PluginManager.class).addPluginListener(
229                 new PluginListener<OverlayPlugin>() {
230                     private ArraySet<OverlayPlugin> mOverlays;
231 
232                     @Override
233                     public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
234                         StatusBar statusBar = getComponent(StatusBar.class);
235                         if (statusBar != null) {
236                             plugin.setup(statusBar.getStatusBarWindow(),
237                                     statusBar.getNavigationBarView());
238                         }
239                         // Lazy init.
240                         if (mOverlays == null) mOverlays = new ArraySet<>();
241                         if (plugin.holdStatusBarOpen()) {
242                             mOverlays.add(plugin);
243                             Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
244                                     mOverlays.forEach(o -> o.setCollapseDesired(b)));
245                             Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
246                                     mOverlays.size() != 0);
247 
248                         }
249                     }
250 
251                     @Override
252                     public void onPluginDisconnected(OverlayPlugin plugin) {
253                         mOverlays.remove(plugin);
254                         Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
255                                 mOverlays.size() != 0);
256                     }
257                 }, OverlayPlugin.class, true /* Allow multiple plugins */);
258 
259         mServicesStarted = true;
260     }
261 
262     @Override
onConfigurationChanged(Configuration newConfig)263     public void onConfigurationChanged(Configuration newConfig) {
264         if (mServicesStarted) {
265             int len = mServices.length;
266             for (int i = 0; i < len; i++) {
267                 if (mServices[i] != null) {
268                     mServices[i].onConfigurationChanged(newConfig);
269                 }
270             }
271         }
272     }
273 
274     @SuppressWarnings("unchecked")
getComponent(Class<T> interfaceType)275     public <T> T getComponent(Class<T> interfaceType) {
276         return (T) mComponents.get(interfaceType);
277     }
278 
getServices()279     public SystemUI[] getServices() {
280         return mServices;
281     }
282 }
283