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.Application;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.res.Configuration;
25 import android.os.Process;
26 import android.os.SystemProperties;
27 import android.os.UserHandle;
28 import android.util.Log;
29 
30 import com.android.systemui.stackdivider.Divider;
31 
32 import java.util.HashMap;
33 import java.util.Map;
34 
35 /**
36  * Application class for SystemUI.
37  */
38 public class SystemUIApplication extends Application {
39 
40     private static final String TAG = "SystemUIService";
41     private static final boolean DEBUG = false;
42 
43     /**
44      * The classes of the stuff to start.
45      */
46     private final Class<?>[] SERVICES = new Class[] {
47             com.android.systemui.tuner.TunerService.class,
48             com.android.systemui.keyguard.KeyguardViewMediator.class,
49             com.android.systemui.recents.Recents.class,
50             com.android.systemui.volume.VolumeUI.class,
51             Divider.class,
52             com.android.systemui.statusbar.SystemBars.class,
53             com.android.systemui.usb.StorageNotification.class,
54             com.android.systemui.power.PowerUI.class,
55             com.android.systemui.media.RingtonePlayer.class,
56             com.android.systemui.keyboard.KeyboardUI.class,
57             com.android.systemui.tv.pip.PipUI.class,
58             com.android.systemui.shortcut.ShortcutKeyDispatcher.class
59     };
60 
61     /**
62      * The classes of the stuff to start for each user.  This is a subset of the services listed
63      * above.
64      */
65     private final Class<?>[] SERVICES_PER_USER = new Class[] {
66             com.android.systemui.recents.Recents.class,
67             com.android.systemui.tv.pip.PipUI.class
68     };
69 
70     /**
71      * Hold a reference on the stuff we start.
72      */
73     private final SystemUI[] mServices = new SystemUI[SERVICES.length];
74     private boolean mServicesStarted;
75     private boolean mBootCompleted;
76     private final Map<Class<?>, Object> mComponents = new HashMap<>();
77 
78     @Override
onCreate()79     public void onCreate() {
80         super.onCreate();
81         // Set the application theme that is inherited by all services. Note that setting the
82         // application theme in the manifest does only work for activities. Keep this in sync with
83         // the theme set there.
84         setTheme(R.style.systemui_theme);
85 
86         SystemUIFactory.createFromConfig(this);
87 
88         if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
89             IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
90             filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
91             registerReceiver(new BroadcastReceiver() {
92                 @Override
93                 public void onReceive(Context context, Intent intent) {
94                     if (mBootCompleted) return;
95 
96                     if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
97                     unregisterReceiver(this);
98                     mBootCompleted = true;
99                     if (mServicesStarted) {
100                         final int N = mServices.length;
101                         for (int i = 0; i < N; i++) {
102                             mServices[i].onBootCompleted();
103                         }
104                     }
105                 }
106             }, filter);
107         } else {
108             // For a secondary user, boot-completed will never be called because it has already
109             // been broadcasted on startup for the primary SystemUI process.  Instead, for
110             // components which require the SystemUI component to be initialized per-user, we
111             // start those components now for the current non-system user.
112             startServicesIfNeeded(SERVICES_PER_USER);
113         }
114     }
115 
116     /**
117      * Makes sure that all the SystemUI services are running. If they are already running, this is a
118      * no-op. This is needed to conditinally start all the services, as we only need to have it in
119      * the main process.
120      *
121      * <p>This method must only be called from the main thread.</p>
122      */
startServicesIfNeeded()123     public void startServicesIfNeeded() {
124         startServicesIfNeeded(SERVICES);
125     }
126 
127     /**
128      * Ensures that all the Secondary user SystemUI services are running. If they are already
129      * running, this is a no-op. This is needed to conditinally start all the services, as we only
130      * need to have it in the main process.
131      *
132      * <p>This method must only be called from the main thread.</p>
133      */
startSecondaryUserServicesIfNeeded()134     void startSecondaryUserServicesIfNeeded() {
135         startServicesIfNeeded(SERVICES_PER_USER);
136     }
137 
startServicesIfNeeded(Class<?>[] services)138     private void startServicesIfNeeded(Class<?>[] services) {
139         if (mServicesStarted) {
140             return;
141         }
142 
143         if (!mBootCompleted) {
144             // check to see if maybe it was already completed long before we began
145             // see ActivityManagerService.finishBooting()
146             if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
147                 mBootCompleted = true;
148                 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
149             }
150         }
151 
152         Log.v(TAG, "Starting SystemUI services for user " +
153                 Process.myUserHandle().getIdentifier() + ".");
154         final int N = services.length;
155         for (int i=0; i<N; i++) {
156             Class<?> cl = services[i];
157             if (DEBUG) Log.d(TAG, "loading: " + cl);
158             try {
159                 Object newService = SystemUIFactory.getInstance().createInstance(cl);
160                 mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
161             } catch (IllegalAccessException ex) {
162                 throw new RuntimeException(ex);
163             } catch (InstantiationException ex) {
164                 throw new RuntimeException(ex);
165             }
166 
167             mServices[i].mContext = this;
168             mServices[i].mComponents = mComponents;
169             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
170             mServices[i].start();
171 
172             if (mBootCompleted) {
173                 mServices[i].onBootCompleted();
174             }
175         }
176         mServicesStarted = true;
177     }
178 
179     @Override
onConfigurationChanged(Configuration newConfig)180     public void onConfigurationChanged(Configuration newConfig) {
181         if (mServicesStarted) {
182             int len = mServices.length;
183             for (int i = 0; i < len; i++) {
184                 if (mServices[i] != null) {
185                     mServices[i].onConfigurationChanged(newConfig);
186                 }
187             }
188         }
189     }
190 
191     @SuppressWarnings("unchecked")
getComponent(Class<T> interfaceType)192     public <T> T getComponent(Class<T> interfaceType) {
193         return (T) mComponents.get(interfaceType);
194     }
195 
getServices()196     public SystemUI[] getServices() {
197         return mServices;
198     }
199 }
200