1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15package com.android.systemui; 16 17import android.content.Context; 18import android.content.res.Configuration; 19import android.os.Handler; 20import android.os.HandlerThread; 21import android.os.Looper; 22import android.os.Process; 23import android.util.ArrayMap; 24 25import com.android.internal.annotations.VisibleForTesting; 26import com.android.internal.app.NightDisplayController; 27import com.android.internal.logging.MetricsLogger; 28import com.android.internal.util.Preconditions; 29import com.android.settingslib.bluetooth.LocalBluetoothManager; 30import com.android.systemui.assist.AssistManager; 31import com.android.systemui.fragments.FragmentService; 32import com.android.systemui.plugins.ActivityStarter; 33import com.android.systemui.plugins.PluginDependencyProvider; 34import com.android.systemui.plugins.PluginManager; 35import com.android.systemui.plugins.PluginManagerImpl; 36import com.android.systemui.plugins.VolumeDialogController; 37import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; 38import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; 39import com.android.systemui.statusbar.phone.ManagedProfileController; 40import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; 41import com.android.systemui.statusbar.phone.StatusBarWindowManager; 42import com.android.systemui.statusbar.phone.StatusBarIconController; 43import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; 44import com.android.systemui.statusbar.policy.AccessibilityController; 45import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; 46import com.android.systemui.statusbar.policy.BatteryController; 47import com.android.systemui.statusbar.policy.BatteryControllerImpl; 48import com.android.systemui.statusbar.policy.BluetoothController; 49import com.android.systemui.statusbar.policy.BluetoothControllerImpl; 50import com.android.systemui.statusbar.policy.CastController; 51import com.android.systemui.statusbar.policy.CastControllerImpl; 52import com.android.systemui.statusbar.policy.ConfigurationController; 53import com.android.systemui.statusbar.policy.DarkIconDispatcher; 54import com.android.systemui.statusbar.policy.DataSaverController; 55import com.android.systemui.statusbar.policy.DeviceProvisionedController; 56import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; 57import com.android.systemui.statusbar.policy.ExtensionController; 58import com.android.systemui.statusbar.policy.ExtensionControllerImpl; 59import com.android.systemui.statusbar.policy.FlashlightController; 60import com.android.systemui.statusbar.policy.FlashlightControllerImpl; 61import com.android.systemui.statusbar.policy.HotspotController; 62import com.android.systemui.statusbar.policy.HotspotControllerImpl; 63import com.android.systemui.statusbar.policy.KeyguardMonitor; 64import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; 65import com.android.systemui.statusbar.policy.LocationController; 66import com.android.systemui.statusbar.policy.LocationControllerImpl; 67import com.android.systemui.statusbar.policy.NetworkController; 68import com.android.systemui.statusbar.policy.NetworkControllerImpl; 69import com.android.systemui.statusbar.policy.NextAlarmController; 70import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; 71import com.android.systemui.statusbar.policy.RotationLockController; 72import com.android.systemui.statusbar.policy.RotationLockControllerImpl; 73import com.android.systemui.statusbar.policy.SecurityController; 74import com.android.systemui.statusbar.policy.SecurityControllerImpl; 75import com.android.systemui.statusbar.policy.UserInfoController; 76import com.android.systemui.statusbar.policy.UserInfoControllerImpl; 77import com.android.systemui.statusbar.policy.UserSwitcherController; 78import com.android.systemui.statusbar.policy.ZenModeController; 79import com.android.systemui.statusbar.policy.ZenModeControllerImpl; 80import com.android.systemui.tuner.TunerService; 81import com.android.systemui.tuner.TunerServiceImpl; 82import com.android.systemui.util.leak.GarbageMonitor; 83import com.android.systemui.util.leak.LeakDetector; 84import com.android.systemui.util.leak.LeakReporter; 85import com.android.systemui.volume.VolumeDialogControllerImpl; 86 87import java.io.FileDescriptor; 88import java.io.PrintWriter; 89import java.util.HashMap; 90import java.util.function.Consumer; 91 92/** 93 * Class to handle ugly dependencies throughout sysui until we determine the 94 * long-term dependency injection solution. 95 * 96 * Classes added here should be things that are expected to live the lifetime of sysui, 97 * and are generally applicable to many parts of sysui. They will be lazily 98 * initialized to ensure they aren't created on form factors that don't need them 99 * (e.g. HotspotController on TV). Despite being lazily initialized, it is expected 100 * that all dependencies will be gotten during sysui startup, and not during runtime 101 * to avoid jank. 102 * 103 * All classes used here are expected to manage their own lifecycle, meaning if 104 * they have no clients they should not have any registered resources like bound 105 * services, registered receivers, etc. 106 */ 107public class Dependency extends SystemUI { 108 109 /** 110 * Key for getting a background Looper for background work. 111 */ 112 public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>("background_looper"); 113 /** 114 * Key for getting a Handler for receiving time tick broadcasts on. 115 */ 116 public static final DependencyKey<Handler> TIME_TICK_HANDLER = 117 new DependencyKey<>("time_tick_handler"); 118 /** 119 * Generic handler on the main thread. 120 */ 121 public static final DependencyKey<Handler> MAIN_HANDLER = new DependencyKey<>("main_handler"); 122 123 /** 124 * An email address to send memory leak reports to by default. 125 */ 126 public static final DependencyKey<String> LEAK_REPORT_EMAIL 127 = new DependencyKey<>("leak_report_email"); 128 129 private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>(); 130 private final ArrayMap<Object, DependencyProvider> mProviders = new ArrayMap<>(); 131 132 @Override 133 public void start() { 134 sDependency = this; 135 // TODO: Think about ways to push these creation rules out of Dependency to cut down 136 // on imports. 137 mProviders.put(TIME_TICK_HANDLER, () -> { 138 HandlerThread thread = new HandlerThread("TimeTick"); 139 thread.start(); 140 return new Handler(thread.getLooper()); 141 }); 142 mProviders.put(BG_LOOPER, () -> { 143 HandlerThread thread = new HandlerThread("SysUiBg", 144 Process.THREAD_PRIORITY_BACKGROUND); 145 thread.start(); 146 return thread.getLooper(); 147 }); 148 mProviders.put(MAIN_HANDLER, () -> new Handler(Looper.getMainLooper())); 149 mProviders.put(ActivityStarter.class, () -> new ActivityStarterDelegate()); 150 mProviders.put(ActivityStarterDelegate.class, () -> 151 getDependency(ActivityStarter.class)); 152 153 mProviders.put(BluetoothController.class, () -> 154 new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER))); 155 156 mProviders.put(LocationController.class, () -> 157 new LocationControllerImpl(mContext, getDependency(BG_LOOPER))); 158 159 mProviders.put(RotationLockController.class, () -> 160 new RotationLockControllerImpl(mContext)); 161 162 mProviders.put(NetworkController.class, () -> 163 new NetworkControllerImpl(mContext, getDependency(BG_LOOPER), 164 getDependency(DeviceProvisionedController.class))); 165 166 mProviders.put(ZenModeController.class, () -> 167 new ZenModeControllerImpl(mContext, getDependency(MAIN_HANDLER))); 168 169 mProviders.put(HotspotController.class, () -> 170 new HotspotControllerImpl(mContext)); 171 172 mProviders.put(CastController.class, () -> 173 new CastControllerImpl(mContext)); 174 175 mProviders.put(FlashlightController.class, () -> 176 new FlashlightControllerImpl(mContext)); 177 178 mProviders.put(KeyguardMonitor.class, () -> 179 new KeyguardMonitorImpl(mContext)); 180 181 mProviders.put(UserSwitcherController.class, () -> 182 new UserSwitcherController(mContext, getDependency(KeyguardMonitor.class), 183 getDependency(MAIN_HANDLER), getDependency(ActivityStarter.class))); 184 185 mProviders.put(UserInfoController.class, () -> 186 new UserInfoControllerImpl(mContext)); 187 188 mProviders.put(BatteryController.class, () -> 189 new BatteryControllerImpl(mContext)); 190 191 mProviders.put(NightDisplayController.class, () -> 192 new NightDisplayController(mContext)); 193 194 mProviders.put(ManagedProfileController.class, () -> 195 new ManagedProfileControllerImpl(mContext)); 196 197 mProviders.put(NextAlarmController.class, () -> 198 new NextAlarmControllerImpl(mContext)); 199 200 mProviders.put(DataSaverController.class, () -> 201 get(NetworkController.class).getDataSaverController()); 202 203 mProviders.put(AccessibilityController.class, () -> 204 new AccessibilityController(mContext)); 205 206 mProviders.put(DeviceProvisionedController.class, () -> 207 new DeviceProvisionedControllerImpl(mContext)); 208 209 mProviders.put(PluginManager.class, () -> 210 new PluginManagerImpl(mContext)); 211 212 mProviders.put(AssistManager.class, () -> 213 new AssistManager(getDependency(DeviceProvisionedController.class), mContext)); 214 215 mProviders.put(SecurityController.class, () -> 216 new SecurityControllerImpl(mContext)); 217 218 mProviders.put(LeakDetector.class, LeakDetector::create); 219 220 mProviders.put(LEAK_REPORT_EMAIL, () -> null); 221 222 mProviders.put(LeakReporter.class, () -> new LeakReporter( 223 mContext, 224 getDependency(LeakDetector.class), 225 getDependency(LEAK_REPORT_EMAIL))); 226 227 mProviders.put(GarbageMonitor.class, () -> new GarbageMonitor( 228 getDependency(BG_LOOPER), 229 getDependency(LeakDetector.class), 230 getDependency(LeakReporter.class))); 231 232 mProviders.put(TunerService.class, () -> 233 new TunerServiceImpl(mContext)); 234 235 mProviders.put(StatusBarWindowManager.class, () -> 236 new StatusBarWindowManager(mContext)); 237 238 mProviders.put(DarkIconDispatcher.class, () -> 239 new DarkIconDispatcherImpl(mContext)); 240 241 mProviders.put(ConfigurationController.class, () -> 242 new ConfigurationControllerImpl(mContext)); 243 244 mProviders.put(StatusBarIconController.class, () -> 245 new StatusBarIconControllerImpl(mContext)); 246 247 mProviders.put(FragmentService.class, () -> 248 new FragmentService(mContext)); 249 250 mProviders.put(ExtensionController.class, () -> 251 new ExtensionControllerImpl()); 252 253 mProviders.put(PluginDependencyProvider.class, () -> 254 new PluginDependencyProvider(get(PluginManager.class))); 255 256 mProviders.put(LocalBluetoothManager.class, () -> 257 LocalBluetoothManager.getInstance(mContext, null)); 258 259 mProviders.put(VolumeDialogController.class, () -> 260 new VolumeDialogControllerImpl(mContext)); 261 262 mProviders.put(MetricsLogger.class, () -> new MetricsLogger()); 263 264 mProviders.put(AccessibilityManagerWrapper.class, 265 () -> new AccessibilityManagerWrapper(mContext)); 266 267 mProviders.put(ForegroundServiceController.class, 268 () -> new ForegroundServiceControllerImpl(mContext)); 269 270 mProviders.put(UiOffloadThread.class, UiOffloadThread::new); 271 272 // Put all dependencies above here so the factory can override them if it wants. 273 SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); 274 } 275 276 @Override 277 public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 278 super.dump(fd, pw, args); 279 pw.println("Dumping existing controllers:"); 280 mDependencies.values().stream().filter(obj -> obj instanceof Dumpable) 281 .forEach(o -> ((Dumpable) o).dump(fd, pw, args)); 282 } 283 284 @Override 285 protected synchronized void onConfigurationChanged(Configuration newConfig) { 286 super.onConfigurationChanged(newConfig); 287 mDependencies.values().stream().filter(obj -> obj instanceof ConfigurationChangedReceiver) 288 .forEach(o -> ((ConfigurationChangedReceiver) o).onConfigurationChanged(newConfig)); 289 } 290 291 protected final <T> T getDependency(Class<T> cls) { 292 return getDependencyInner(cls); 293 } 294 295 protected final <T> T getDependency(DependencyKey<T> key) { 296 return getDependencyInner(key); 297 } 298 299 private synchronized <T> T getDependencyInner(Object key) { 300 @SuppressWarnings("unchecked") 301 T obj = (T) mDependencies.get(key); 302 if (obj == null) { 303 obj = createDependency(key); 304 mDependencies.put(key, obj); 305 } 306 return obj; 307 } 308 309 @VisibleForTesting 310 protected <T> T createDependency(Object cls) { 311 Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>); 312 313 @SuppressWarnings("unchecked") 314 DependencyProvider<T> provider = mProviders.get(cls); 315 if (provider == null) { 316 throw new IllegalArgumentException("Unsupported dependency " + cls); 317 } 318 return provider.createDependency(); 319 } 320 321 private static Dependency sDependency; 322 323 public interface DependencyProvider<T> { 324 T createDependency(); 325 } 326 327 private <T> void destroyDependency(Class<T> cls, Consumer<T> destroy) { 328 T dep = (T) mDependencies.remove(cls); 329 if (dep != null && destroy != null) { 330 destroy.accept(dep); 331 } 332 } 333 334 /** 335 * Used in separate processes (like tuner settings) to init the dependencies. 336 */ 337 public static void initDependencies(Context context) { 338 if (sDependency != null) return; 339 Dependency d = new Dependency(); 340 d.mContext = context; 341 d.mComponents = new HashMap<>(); 342 d.start(); 343 } 344 345 /** 346 * Used in separate process teardown to ensure the context isn't leaked. 347 * 348 * TODO: Remove once PreferenceFragment doesn't reference getActivity() 349 * anymore and these context hacks are no longer needed. 350 */ 351 public static void clearDependencies() { 352 sDependency = null; 353 } 354 355 /** 356 * Checks to see if a dependency is instantiated, if it is it removes it from 357 * the cache and calls the destroy callback. 358 */ 359 public static <T> void destroy(Class<T> cls, Consumer<T> destroy) { 360 sDependency.destroyDependency(cls, destroy); 361 } 362 363 public static <T> T get(Class<T> cls) { 364 return sDependency.getDependency(cls); 365 } 366 367 public static <T> T get(DependencyKey<T> cls) { 368 return sDependency.getDependency(cls); 369 } 370 371 public static final class DependencyKey<V> { 372 private final String mDisplayName; 373 374 public DependencyKey(String displayName) { 375 mDisplayName = displayName; 376 } 377 378 @Override 379 public String toString() { 380 return mDisplayName; 381 } 382 } 383} 384