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