• 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.Log;
33 import android.util.TimingsTraceLog;
34 
35 import com.android.systemui.plugins.OverlayPlugin;
36 import com.android.systemui.plugins.PluginListener;
37 import com.android.systemui.plugins.PluginManager;
38 import com.android.systemui.statusbar.phone.StatusBar;
39 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
40 import com.android.systemui.util.NotificationChannels;
41 
42 import java.util.HashMap;
43 import java.util.Map;
44 
45 /**
46  * Application class for SystemUI.
47  */
48 public class SystemUIApplication extends Application implements SysUiServiceProvider {
49 
50     public static final String TAG = "SystemUIService";
51     private static final boolean DEBUG = false;
52 
53     /**
54      * Hold a reference on the stuff we start.
55      */
56     private SystemUI[] mServices;
57     private boolean mServicesStarted;
58     private boolean mBootCompleted;
59     private final Map<Class<?>, Object> mComponents = new HashMap<>();
60 
61     @Override
onCreate()62     public void onCreate() {
63         super.onCreate();
64         // Set the application theme that is inherited by all services. Note that setting the
65         // application theme in the manifest does only work for activities. Keep this in sync with
66         // the theme set there.
67         setTheme(R.style.Theme_SystemUI);
68 
69         SystemUIFactory.createFromConfig(this);
70 
71         if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
72             IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
73             bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
74             registerReceiver(new BroadcastReceiver() {
75                 @Override
76                 public void onReceive(Context context, Intent intent) {
77                     if (mBootCompleted) return;
78 
79                     if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
80                     unregisterReceiver(this);
81                     mBootCompleted = true;
82                     if (mServicesStarted) {
83                         final int N = mServices.length;
84                         for (int i = 0; i < N; i++) {
85                             mServices[i].onBootCompleted();
86                         }
87                     }
88 
89 
90                 }
91             }, bootCompletedFilter);
92 
93             IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
94             registerReceiver(new BroadcastReceiver() {
95                 @Override
96                 public void onReceive(Context context, Intent intent) {
97                     if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
98                         if (!mBootCompleted) return;
99                         // Update names of SystemUi notification channels
100                         NotificationChannels.createAll(context);
101                     }
102                 }
103             }, localeChangedFilter);
104         } else {
105             // We don't need to startServices for sub-process that is doing some tasks.
106             // (screenshots, sweetsweetdesserts or tuner ..)
107             String processName = ActivityThread.currentProcessName();
108             ApplicationInfo info = getApplicationInfo();
109             if (processName != null && processName.startsWith(info.processName + ":")) {
110                 return;
111             }
112             // For a secondary user, boot-completed will never be called because it has already
113             // been broadcasted on startup for the primary SystemUI process.  Instead, for
114             // components which require the SystemUI component to be initialized per-user, we
115             // start those components now for the current non-system user.
116             startSecondaryUserServicesIfNeeded();
117         }
118     }
119 
120     /**
121      * Makes sure that all the SystemUI services are running. If they are already running, this is a
122      * no-op. This is needed to conditinally start all the services, as we only need to have it in
123      * the main process.
124      * <p>This method must only be called from the main thread.</p>
125      */
126 
startServicesIfNeeded()127     public void startServicesIfNeeded() {
128         String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
129         startServicesIfNeeded(names);
130     }
131 
132     /**
133      * Ensures that all the Secondary user SystemUI services are running. If they are already
134      * running, this is a no-op. This is needed to conditinally start all the services, as we only
135      * need to have it in the main process.
136      * <p>This method must only be called from the main thread.</p>
137      */
startSecondaryUserServicesIfNeeded()138     void startSecondaryUserServicesIfNeeded() {
139         String[] names =
140                   getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
141         startServicesIfNeeded(names);
142     }
143 
startServicesIfNeeded(String[] services)144     private void startServicesIfNeeded(String[] services) {
145         if (mServicesStarted) {
146             return;
147         }
148         mServices = new SystemUI[services.length];
149 
150         if (!mBootCompleted) {
151             // check to see if maybe it was already completed long before we began
152             // see ActivityManagerService.finishBooting()
153             if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
154                 mBootCompleted = true;
155                 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
156             }
157         }
158 
159         Log.v(TAG, "Starting SystemUI services for user " +
160                 Process.myUserHandle().getIdentifier() + ".");
161         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
162                 Trace.TRACE_TAG_APP);
163         log.traceBegin("StartServices");
164         final int N = services.length;
165         for (int i = 0; i < N; i++) {
166             String clsName = services[i];
167             if (DEBUG) Log.d(TAG, "loading: " + clsName);
168             log.traceBegin("StartServices" + clsName);
169             long ti = System.currentTimeMillis();
170             Class cls;
171             try {
172                 cls = Class.forName(clsName);
173                 mServices[i] = (SystemUI) cls.newInstance();
174             } catch(ClassNotFoundException ex){
175                 throw new RuntimeException(ex);
176             } catch (IllegalAccessException ex) {
177                 throw new RuntimeException(ex);
178             } catch (InstantiationException ex) {
179                 throw new RuntimeException(ex);
180             }
181 
182             mServices[i].mContext = this;
183             mServices[i].mComponents = mComponents;
184             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
185             mServices[i].start();
186             log.traceEnd();
187 
188             // Warn if initialization of component takes too long
189             ti = System.currentTimeMillis() - ti;
190             if (ti > 1000) {
191                 Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
192             }
193             if (mBootCompleted) {
194                 mServices[i].onBootCompleted();
195             }
196         }
197         log.traceEnd();
198         Dependency.get(PluginManager.class).addPluginListener(
199                 new PluginListener<OverlayPlugin>() {
200                     private ArraySet<OverlayPlugin> mOverlays;
201 
202                     @Override
203                     public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
204                         StatusBar statusBar = getComponent(StatusBar.class);
205                         if (statusBar != null) {
206                             plugin.setup(statusBar.getStatusBarWindow(),
207                                     statusBar.getNavigationBarView());
208                         }
209                         // Lazy init.
210                         if (mOverlays == null) mOverlays = new ArraySet<>();
211                         if (plugin.holdStatusBarOpen()) {
212                             mOverlays.add(plugin);
213                             Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
214                                     mOverlays.forEach(o -> o.setCollapseDesired(b)));
215                             Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
216                                     mOverlays.size() != 0);
217 
218                         }
219                     }
220 
221                     @Override
222                     public void onPluginDisconnected(OverlayPlugin plugin) {
223                         mOverlays.remove(plugin);
224                         Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
225                                 mOverlays.size() != 0);
226                     }
227                 }, OverlayPlugin.class, true /* Allow multiple plugins */);
228 
229         mServicesStarted = true;
230     }
231 
232     @Override
onConfigurationChanged(Configuration newConfig)233     public void onConfigurationChanged(Configuration newConfig) {
234         if (mServicesStarted) {
235             int len = mServices.length;
236             for (int i = 0; i < len; i++) {
237                 if (mServices[i] != null) {
238                     mServices[i].onConfigurationChanged(newConfig);
239                 }
240             }
241         }
242     }
243 
244     @SuppressWarnings("unchecked")
getComponent(Class<T> interfaceType)245     public <T> T getComponent(Class<T> interfaceType) {
246         return (T) mComponents.get(interfaceType);
247     }
248 
getServices()249     public SystemUI[] getServices() {
250         return mServices;
251     }
252 }
253