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 15 package com.android.systemui; 16 17 import android.annotation.Nullable; 18 import android.os.Handler; 19 import android.os.Looper; 20 import android.util.ArrayMap; 21 22 import com.android.internal.annotations.VisibleForTesting; 23 import com.android.internal.logging.MetricsLogger; 24 import com.android.internal.logging.UiEventLogger; 25 import com.android.internal.util.Preconditions; 26 import com.android.keyguard.KeyguardUpdateMonitor; 27 import com.android.systemui.animation.DialogTransitionAnimator; 28 import com.android.systemui.assist.AssistManager; 29 import com.android.systemui.broadcast.BroadcastDispatcher; 30 import com.android.systemui.dagger.SysUISingleton; 31 import com.android.systemui.dagger.qualifiers.Background; 32 import com.android.systemui.dump.DumpManager; 33 import com.android.systemui.flags.FeatureFlags; 34 import com.android.systemui.fragments.FragmentService; 35 import com.android.systemui.media.NotificationMediaManager; 36 import com.android.systemui.model.SysUiState; 37 import com.android.systemui.navigationbar.NavigationBarController; 38 import com.android.systemui.navigationbar.NavigationModeController; 39 import com.android.systemui.plugins.DarkIconDispatcher; 40 import com.android.systemui.plugins.PluginManager; 41 import com.android.systemui.plugins.VolumeDialogController; 42 import com.android.systemui.plugins.statusbar.StatusBarStateController; 43 import com.android.systemui.recents.LauncherProxyService; 44 import com.android.systemui.settings.UserTracker; 45 import com.android.systemui.statusbar.CommandQueue; 46 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; 47 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; 48 import com.android.systemui.statusbar.notification.stack.AmbientState; 49 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; 50 import com.android.systemui.statusbar.phone.LightBarController; 51 import com.android.systemui.statusbar.phone.ScreenOffAnimationController; 52 import com.android.systemui.statusbar.phone.SystemUIDialogManager; 53 import com.android.systemui.statusbar.policy.BluetoothController; 54 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 55 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore; 56 import com.android.systemui.tuner.TunerService; 57 58 import dagger.Lazy; 59 60 import java.util.function.Consumer; 61 62 import javax.inject.Inject; 63 import javax.inject.Named; 64 65 /** 66 * Class to handle ugly dependencies throughout sysui until we determine the 67 * long-term dependency injection solution. 68 * 69 * Classes added here should be things that are expected to live the lifetime of sysui, 70 * and are generally applicable to many parts of sysui. They will be lazily 71 * initialized to ensure they aren't created on form factors that don't need them 72 * (e.g. HotspotController on TV). Despite being lazily initialized, it is expected 73 * that all dependencies will be gotten during sysui startup, and not during runtime 74 * to avoid jank. 75 * 76 * All classes used here are expected to manage their own lifecycle, meaning if 77 * they have no clients they should not have any registered resources like bound 78 * services, registered receivers, etc. 79 */ 80 @SysUISingleton 81 public class Dependency { 82 83 /** 84 * Key for getting a background Looper for background work. 85 */ 86 private static final String BG_LOOPER_NAME = "background_looper"; 87 /** 88 * Key for getting a Handler for receiving time tick broadcasts on. 89 */ 90 public static final String TIME_TICK_HANDLER_NAME = "time_tick_handler"; 91 92 /** 93 * An email address to send memory leak reports to by default. 94 */ 95 public static final String LEAK_REPORT_EMAIL_NAME = "leak_report_email"; 96 97 /** 98 * Whether this platform supports long-pressing notifications to show notification channel 99 * settings. 100 */ 101 public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress"; 102 103 /** 104 * Key for getting a background Looper for background work. 105 */ 106 public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME); 107 /** 108 * Key for getting a Handler for receiving time tick broadcasts on. 109 */ 110 public static final DependencyKey<Handler> TIME_TICK_HANDLER = 111 new DependencyKey<>(TIME_TICK_HANDLER_NAME); 112 113 private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>(); 114 private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>(); 115 116 @Inject DumpManager mDumpManager; 117 118 @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher; 119 @Inject Lazy<BluetoothController> mBluetoothController; 120 @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor; 121 @Inject Lazy<DeviceProvisionedController> mDeviceProvisionedController; 122 @Inject Lazy<PluginManager> mPluginManager; 123 @Inject Lazy<AssistManager> mAssistManager; 124 @Inject Lazy<TunerService> mTunerService; 125 @Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher; 126 @Inject Lazy<FragmentService> mFragmentService; 127 @Nullable 128 @Inject Lazy<VolumeDialogController> mVolumeDialogController; 129 @Inject Lazy<MetricsLogger> mMetricsLogger; 130 @Inject Lazy<UiOffloadThread> mUiOffloadThread; 131 @Inject Lazy<LightBarController> mLightBarController; 132 @Inject Lazy<LauncherProxyService> mLauncherProxyService; 133 @Inject Lazy<NavigationModeController> mNavBarModeController; 134 @Inject Lazy<NavigationBarController> mNavigationBarController; 135 @Inject Lazy<StatusBarStateController> mStatusBarStateController; 136 @Inject Lazy<NotificationMediaManager> mNotificationMediaManager; 137 @Inject @Background Lazy<Looper> mBgLooper; 138 @Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler; 139 @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; 140 @Inject Lazy<CommandQueue> mCommandQueue; 141 @Inject Lazy<UiEventLogger> mUiEventLogger; 142 @Inject Lazy<FeatureFlags> mFeatureFlagsLazy; 143 @Inject Lazy<NotificationSectionsManager> mNotificationSectionsManagerLazy; 144 @Inject Lazy<ScreenOffAnimationController> mScreenOffAnimationController; 145 @Inject Lazy<AmbientState> mAmbientStateLazy; 146 @Inject Lazy<GroupMembershipManager> mGroupMembershipManagerLazy; 147 @Inject Lazy<GroupExpansionManager> mGroupExpansionManagerLazy; 148 @Inject Lazy<SystemUIDialogManager> mSystemUIDialogManagerLazy; 149 @Inject Lazy<DialogTransitionAnimator> mDialogTransitionAnimatorLazy; 150 @Inject Lazy<UserTracker> mUserTrackerLazy; 151 @Inject Lazy<StatusBarWindowControllerStore> mStatusBarWindowControllerStoreLazy; 152 153 @Inject Dependency()154 public Dependency() { 155 } 156 157 /** 158 * Initialize Depenency. 159 */ start()160 protected void start() { 161 // TODO: Think about ways to push these creation rules out of Dependency to cut down 162 // on imports. 163 mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get); 164 mProviders.put(BG_LOOPER, mBgLooper::get); 165 mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get); 166 mProviders.put(BluetoothController.class, mBluetoothController::get); 167 mProviders.put(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor::get); 168 mProviders.put(DeviceProvisionedController.class, mDeviceProvisionedController::get); 169 mProviders.put(PluginManager.class, mPluginManager::get); 170 mProviders.put(AssistManager.class, mAssistManager::get); 171 mProviders.put(TunerService.class, mTunerService::get); 172 mProviders.put(DarkIconDispatcher.class, mDarkIconDispatcher::get); 173 mProviders.put(FragmentService.class, mFragmentService::get); 174 mProviders.put(VolumeDialogController.class, mVolumeDialogController::get); 175 mProviders.put(MetricsLogger.class, mMetricsLogger::get); 176 mProviders.put(UiOffloadThread.class, mUiOffloadThread::get); 177 mProviders.put(LightBarController.class, mLightBarController::get); 178 mProviders.put(LauncherProxyService.class, mLauncherProxyService::get); 179 mProviders.put(NavigationModeController.class, mNavBarModeController::get); 180 mProviders.put(NavigationBarController.class, mNavigationBarController::get); 181 mProviders.put(StatusBarStateController.class, mStatusBarStateController::get); 182 mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get); 183 mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); 184 mProviders.put(CommandQueue.class, mCommandQueue::get); 185 mProviders.put(UiEventLogger.class, mUiEventLogger::get); 186 mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get); 187 mProviders.put(NotificationSectionsManager.class, mNotificationSectionsManagerLazy::get); 188 mProviders.put(ScreenOffAnimationController.class, mScreenOffAnimationController::get); 189 mProviders.put(AmbientState.class, mAmbientStateLazy::get); 190 mProviders.put(GroupMembershipManager.class, mGroupMembershipManagerLazy::get); 191 mProviders.put(GroupExpansionManager.class, mGroupExpansionManagerLazy::get); 192 mProviders.put(SystemUIDialogManager.class, mSystemUIDialogManagerLazy::get); 193 mProviders.put(DialogTransitionAnimator.class, mDialogTransitionAnimatorLazy::get); 194 mProviders.put(UserTracker.class, mUserTrackerLazy::get); 195 mProviders.put( 196 StatusBarWindowControllerStore.class, mStatusBarWindowControllerStoreLazy::get); 197 198 Dependency.setInstance(this); 199 } 200 201 @VisibleForTesting setInstance(Dependency dependency)202 public static void setInstance(Dependency dependency) { 203 sDependency = dependency; 204 } 205 getDependency(Class<T> cls)206 protected final <T> T getDependency(Class<T> cls) { 207 return getDependencyInner(cls); 208 } 209 getDependency(DependencyKey<T> key)210 protected final <T> T getDependency(DependencyKey<T> key) { 211 return getDependencyInner(key); 212 } 213 getDependencyInner(Object key)214 private synchronized <T> T getDependencyInner(Object key) { 215 @SuppressWarnings("unchecked") 216 T obj = (T) mDependencies.get(key); 217 if (obj == null) { 218 obj = createDependency(key); 219 mDependencies.put(key, obj); 220 } 221 return obj; 222 } 223 224 @VisibleForTesting createDependency(Object cls)225 public <T> T createDependency(Object cls) { 226 Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>); 227 228 @SuppressWarnings("unchecked") 229 LazyDependencyCreator<T> provider = mProviders.get(cls); 230 if (provider == null) { 231 throw new IllegalArgumentException("Unsupported dependency " + cls 232 + ". " + mProviders.size() + " providers known."); 233 } 234 return provider.createDependency(); 235 } 236 237 private static Dependency sDependency; 238 239 /** 240 * Interface for a class that can create a dependency. Used to implement laziness 241 * @param <T> The type of the dependency being created 242 */ 243 private interface LazyDependencyCreator<T> { createDependency()244 T createDependency(); 245 } 246 destroyDependency(Class<T> cls, Consumer<T> destroy)247 private <T> void destroyDependency(Class<T> cls, Consumer<T> destroy) { 248 T dep = (T) mDependencies.remove(cls); 249 if (dep instanceof Dumpable) { 250 mDumpManager.unregisterDumpable(dep.getClass().getName()); 251 } 252 if (dep != null && destroy != null) { 253 destroy.accept(dep); 254 } 255 } 256 257 /** 258 * Used in separate process teardown to ensure the context isn't leaked. 259 * 260 * TODO: Remove once PreferenceFragment doesn't reference getActivity() 261 * anymore and these context hacks are no longer needed. 262 */ clearDependencies()263 public static void clearDependencies() { 264 sDependency = null; 265 } 266 267 /** 268 * Checks to see if a dependency is instantiated, if it is it removes it from 269 * the cache and calls the destroy callback. 270 */ destroy(Class<T> cls, Consumer<T> destroy)271 public static <T> void destroy(Class<T> cls, Consumer<T> destroy) { 272 sDependency.destroyDependency(cls, destroy); 273 } 274 275 /** 276 * @deprecated see docs/dagger.md 277 */ 278 @Deprecated get(Class<T> cls)279 public static <T> T get(Class<T> cls) { 280 return sDependency.getDependency(cls); 281 } 282 283 /** 284 * @deprecated see docs/dagger.md 285 */ 286 @Deprecated get(DependencyKey<T> cls)287 public static <T> T get(DependencyKey<T> cls) { 288 return sDependency.getDependency(cls); 289 } 290 291 public static final class DependencyKey<V> { 292 private final String mDisplayName; 293 DependencyKey(String displayName)294 public DependencyKey(String displayName) { 295 mDisplayName = displayName; 296 } 297 298 @Override toString()299 public String toString() { 300 return mDisplayName; 301 } 302 } 303 } 304