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