Home | History | Annotate | Download | only in systemui
      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
    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 
    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      */
    173     void startSecondaryUserServicesIfNeeded() {
    174         startServicesIfNeeded(SERVICES_PER_USER);
    175     }
    176 
    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
    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")
    275     public <T> T getComponent(Class<T> interfaceType) {
    276         return (T) mComponents.get(interfaceType);
    277     }
    278 
    279     public SystemUI[] getServices() {
    280         return mServices;
    281     }
    282 }
    283