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