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