• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.Context;
18 import android.content.res.Configuration;
19 import android.os.Handler;
20 import android.os.HandlerThread;
21 import android.os.Looper;
22 import android.os.Process;
23 import android.util.ArrayMap;
24 
25 import com.android.internal.annotations.VisibleForTesting;
26 import com.android.internal.app.NightDisplayController;
27 import com.android.internal.logging.MetricsLogger;
28 import com.android.internal.util.Preconditions;
29 import com.android.settingslib.bluetooth.LocalBluetoothManager;
30 import com.android.systemui.assist.AssistManager;
31 import com.android.systemui.fragments.FragmentService;
32 import com.android.systemui.plugins.ActivityStarter;
33 import com.android.systemui.plugins.PluginDependencyProvider;
34 import com.android.systemui.plugins.PluginManager;
35 import com.android.systemui.plugins.PluginManagerImpl;
36 import com.android.systemui.plugins.VolumeDialogController;
37 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
38 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
39 import com.android.systemui.statusbar.phone.ManagedProfileController;
40 import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
41 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
42 import com.android.systemui.statusbar.phone.StatusBarIconController;
43 import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
44 import com.android.systemui.statusbar.policy.AccessibilityController;
45 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
46 import com.android.systemui.statusbar.policy.BatteryController;
47 import com.android.systemui.statusbar.policy.BatteryControllerImpl;
48 import com.android.systemui.statusbar.policy.BluetoothController;
49 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
50 import com.android.systemui.statusbar.policy.CastController;
51 import com.android.systemui.statusbar.policy.CastControllerImpl;
52 import com.android.systemui.statusbar.policy.ConfigurationController;
53 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
54 import com.android.systemui.statusbar.policy.DataSaverController;
55 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
56 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
57 import com.android.systemui.statusbar.policy.ExtensionController;
58 import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
59 import com.android.systemui.statusbar.policy.FlashlightController;
60 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
61 import com.android.systemui.statusbar.policy.HotspotController;
62 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
63 import com.android.systemui.statusbar.policy.KeyguardMonitor;
64 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
65 import com.android.systemui.statusbar.policy.LocationController;
66 import com.android.systemui.statusbar.policy.LocationControllerImpl;
67 import com.android.systemui.statusbar.policy.NetworkController;
68 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
69 import com.android.systemui.statusbar.policy.NextAlarmController;
70 import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
71 import com.android.systemui.statusbar.policy.RotationLockController;
72 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
73 import com.android.systemui.statusbar.policy.SecurityController;
74 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
75 import com.android.systemui.statusbar.policy.UserInfoController;
76 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
77 import com.android.systemui.statusbar.policy.UserSwitcherController;
78 import com.android.systemui.statusbar.policy.ZenModeController;
79 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
80 import com.android.systemui.tuner.TunerService;
81 import com.android.systemui.tuner.TunerServiceImpl;
82 import com.android.systemui.util.leak.GarbageMonitor;
83 import com.android.systemui.util.leak.LeakDetector;
84 import com.android.systemui.util.leak.LeakReporter;
85 import com.android.systemui.volume.VolumeDialogControllerImpl;
86 
87 import java.io.FileDescriptor;
88 import java.io.PrintWriter;
89 import java.util.HashMap;
90 import 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  */
107 public 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
start()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
dump(FileDescriptor fd, PrintWriter pw, String[] args)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
onConfigurationChanged(Configuration newConfig)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 
getDependency(Class<T> cls)291     protected final <T> T getDependency(Class<T> cls) {
292         return getDependencyInner(cls);
293     }
294 
getDependency(DependencyKey<T> key)295     protected final <T> T getDependency(DependencyKey<T> key) {
296         return getDependencyInner(key);
297     }
298 
getDependencyInner(Object key)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
createDependency(Object cls)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> {
createDependency()324         T createDependency();
325     }
326 
destroyDependency(Class<T> cls, Consumer<T> destroy)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      */
initDependencies(Context context)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      */
clearDependencies()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      */
destroy(Class<T> cls, Consumer<T> destroy)359     public static <T> void destroy(Class<T> cls, Consumer<T> destroy) {
360         sDependency.destroyDependency(cls, destroy);
361     }
362 
get(Class<T> cls)363     public static <T> T get(Class<T> cls) {
364         return sDependency.getDependency(cls);
365     }
366 
get(DependencyKey<T> cls)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 
DependencyKey(String displayName)374         public DependencyKey(String displayName) {
375             mDisplayName = displayName;
376         }
377 
378         @Override
toString()379         public String toString() {
380             return mDisplayName;
381         }
382     }
383 }
384