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.statusbar.policy;
16 
17 import android.content.Context;
18 import android.content.res.Configuration;
19 import android.os.Handler;
20 import android.util.ArrayMap;
21 
22 import com.android.systemui.dagger.SysUISingleton;
23 import com.android.systemui.plugins.Plugin;
24 import com.android.systemui.plugins.PluginListener;
25 import com.android.systemui.plugins.PluginManager;
26 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
27 import com.android.systemui.tuner.TunerService;
28 import com.android.systemui.tuner.TunerService.Tunable;
29 import com.android.systemui.util.leak.LeakDetector;
30 
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Comparator;
34 import java.util.function.Consumer;
35 import java.util.function.Supplier;
36 
37 import javax.inject.Inject;
38 
39 /**
40  */
41 @SysUISingleton
42 public class ExtensionControllerImpl implements ExtensionController {
43 
44     public static final int SORT_ORDER_PLUGIN  = 0;
45     public static final int SORT_ORDER_TUNER   = 1;
46     public static final int SORT_ORDER_FEATURE = 2;
47     public static final int SORT_ORDER_UI_MODE = 3;
48     public static final int SORT_ORDER_DEFAULT = 4;
49 
50     private final Context mDefaultContext;
51     private final LeakDetector mLeakDetector;
52     private final PluginManager mPluginManager;
53     private final TunerService mTunerService;
54     private final ConfigurationController mConfigurationController;
55 
56     /**
57      */
58     @Inject
ExtensionControllerImpl( Context context, LeakDetector leakDetector, PluginManager pluginManager, TunerService tunerService, ConfigurationController configurationController)59     public ExtensionControllerImpl(
60             Context context,
61             LeakDetector leakDetector,
62             PluginManager pluginManager,
63             TunerService tunerService,
64             ConfigurationController configurationController) {
65         mDefaultContext = context;
66         mLeakDetector = leakDetector;
67         mPluginManager = pluginManager;
68         mTunerService = tunerService;
69         mConfigurationController = configurationController;
70     }
71 
72     @Override
newExtension(Class<T> cls)73     public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
74         return new ExtensionBuilder<>();
75     }
76 
77     private interface Producer<T> {
get()78         T get();
79 
destroy()80         void destroy();
81     }
82 
83     private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> {
84 
85         private ExtensionImpl<T> mExtension = new ExtensionImpl<>();
86 
87         @Override
withTunerFactory(TunerFactory<T> factory)88         public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
89             mExtension.addTunerFactory(factory, factory.keys());
90             return this;
91         }
92 
93         @Override
withPlugin(Class<P> cls)94         public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) {
95             return withPlugin(cls, PluginManager.Helper.getAction(cls));
96         }
97 
98         @Override
withPlugin(Class<P> cls, String action)99         public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
100                 String action) {
101             return withPlugin(cls, action, null);
102         }
103 
104         @Override
withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter)105         public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
106                 String action, PluginConverter<T, P> converter) {
107             mExtension.addPlugin(action, cls, converter);
108             return this;
109         }
110 
111         @Override
withDefault(Supplier<T> def)112         public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) {
113             mExtension.addDefault(def);
114             return this;
115         }
116 
117         @Override
withUiMode(int uiMode, Supplier<T> supplier)118         public ExtensionController.ExtensionBuilder<T> withUiMode(int uiMode,
119                 Supplier<T> supplier) {
120             mExtension.addUiMode(uiMode, supplier);
121             return this;
122         }
123 
124         @Override
withFeature(String feature, Supplier<T> supplier)125         public ExtensionController.ExtensionBuilder<T> withFeature(String feature,
126                 Supplier<T> supplier) {
127             mExtension.addFeature(feature, supplier);
128             return this;
129         }
130 
131         @Override
withCallback( Consumer<T> callback)132         public ExtensionController.ExtensionBuilder<T> withCallback(
133                 Consumer<T> callback) {
134             mExtension.mCallbacks.add(callback);
135             return this;
136         }
137 
138         @Override
build()139         public ExtensionController.Extension<T> build() {
140             // Sort items in ascending order
141             Collections.sort(mExtension.mProducers, Comparator.comparingInt(Item::sortOrder));
142             mExtension.notifyChanged();
143             return mExtension;
144         }
145     }
146 
147     private class ExtensionImpl<T> implements ExtensionController.Extension<T> {
148         private final ArrayList<Item<T>> mProducers = new ArrayList<>();
149         private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>();
150         private T mItem;
151         private Context mPluginContext;
152 
addCallback(Consumer<T> callback)153         public void addCallback(Consumer<T> callback) {
154             mCallbacks.add(callback);
155         }
156 
157         @Override
get()158         public T get() {
159             return mItem;
160         }
161 
162         @Override
getContext()163         public Context getContext() {
164             return mPluginContext != null ? mPluginContext : mDefaultContext;
165         }
166 
167         @Override
destroy()168         public void destroy() {
169             for (int i = 0; i < mProducers.size(); i++) {
170                 mProducers.get(i).destroy();
171             }
172         }
173 
174         @Override
reload()175         public T reload() {
176             notifyChanged();
177             return get();
178         }
179 
180         @Override
clearItem(boolean isDestroyed)181         public void clearItem(boolean isDestroyed) {
182             if (isDestroyed && mItem != null) {
183                 mLeakDetector.trackGarbage(mItem);
184             }
185             mItem = null;
186         }
187 
notifyChanged()188         private void notifyChanged() {
189             if (mItem != null) {
190                 mLeakDetector.trackGarbage(mItem);
191             }
192             mItem = null;
193             for (int i = 0; i < mProducers.size(); i++) {
194                 final T item = mProducers.get(i).get();
195                 if (item != null) {
196                     mItem = item;
197                     break;
198                 }
199             }
200             for (int i = 0; i < mCallbacks.size(); i++) {
201                 mCallbacks.get(i).accept(mItem);
202             }
203         }
204 
addDefault(Supplier<T> def)205         public void addDefault(Supplier<T> def) {
206             mProducers.add(new Default(def));
207         }
208 
addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter)209         public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) {
210             mProducers.add(new PluginItem(action, cls, converter));
211         }
212 
addTunerFactory(TunerFactory<T> factory, String[] keys)213         public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
214             mProducers.add(new TunerItem(factory, keys));
215         }
216 
addUiMode(int uiMode, Supplier<T> mode)217         public void addUiMode(int uiMode, Supplier<T> mode) {
218             mProducers.add(new UiModeItem(uiMode, mode));
219         }
220 
addFeature(String feature, Supplier<T> mode)221         public void addFeature(String feature, Supplier<T> mode) {
222             mProducers.add(new FeatureItem<>(feature, mode));
223         }
224 
225         private class PluginItem<P extends Plugin> implements Item<T>, PluginListener<P> {
226             private final PluginConverter<T, P> mConverter;
227             private T mItem;
228 
PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter)229             public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) {
230                 mConverter = converter;
231                 mPluginManager.addPluginListener(action, this, cls);
232             }
233 
234             @Override
onPluginConnected(P plugin, Context pluginContext)235             public void onPluginConnected(P plugin, Context pluginContext) {
236                 mPluginContext = pluginContext;
237                 if (mConverter != null) {
238                     mItem = mConverter.getInterfaceFromPlugin(plugin);
239                 } else {
240                     mItem = (T) plugin;
241                 }
242                 notifyChanged();
243             }
244 
245             @Override
onPluginDisconnected(P plugin)246             public void onPluginDisconnected(P plugin) {
247                 mPluginContext = null;
248                 mItem = null;
249                 notifyChanged();
250             }
251 
252             @Override
get()253             public T get() {
254                 return mItem;
255             }
256 
257             @Override
destroy()258             public void destroy() {
259                 mPluginManager.removePluginListener(this);
260             }
261 
262             @Override
sortOrder()263             public int sortOrder() {
264                 return SORT_ORDER_PLUGIN;
265             }
266         }
267 
268         private class TunerItem<T> implements Item<T>, Tunable {
269             private final TunerFactory<T> mFactory;
270             private final ArrayMap<String, String> mSettings = new ArrayMap<>();
271             private T mItem;
272 
TunerItem(TunerFactory<T> factory, String... setting)273             public TunerItem(TunerFactory<T> factory, String... setting) {
274                 mFactory = factory;
275                 mTunerService.addTunable(this, setting);
276             }
277 
278             @Override
get()279             public T get() {
280                 return mItem;
281             }
282 
283             @Override
destroy()284             public void destroy() {
285                 mTunerService.removeTunable(this);
286             }
287 
288             @Override
onTuningChanged(String key, String newValue)289             public void onTuningChanged(String key, String newValue) {
290                 mSettings.put(key, newValue);
291                 mItem = mFactory.create(mSettings);
292                 notifyChanged();
293             }
294 
295             @Override
sortOrder()296             public int sortOrder() {
297                 return SORT_ORDER_TUNER;
298             }
299         }
300 
301         private class UiModeItem<T> implements Item<T>, ConfigurationListener {
302 
303             private final int mDesiredUiMode;
304             private final Supplier<T> mSupplier;
305             private int mUiMode;
306             private Handler mHandler = new Handler();
307 
UiModeItem(int uiMode, Supplier<T> supplier)308             public UiModeItem(int uiMode, Supplier<T> supplier) {
309                 mDesiredUiMode = uiMode;
310                 mSupplier = supplier;
311                 mUiMode = mDefaultContext.getResources().getConfiguration().uiMode
312                         & Configuration.UI_MODE_TYPE_MASK;
313                 mConfigurationController.addCallback(this);
314             }
315 
316             @Override
onConfigChanged(Configuration newConfig)317             public void onConfigChanged(Configuration newConfig) {
318                 int newMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
319                 if (newMode != mUiMode) {
320                     mUiMode = newMode;
321                     // Post to make sure we don't have concurrent modifications.
322                     mHandler.post(ExtensionImpl.this::notifyChanged);
323                 }
324             }
325 
326             @Override
get()327             public T get() {
328                 return (mUiMode == mDesiredUiMode) ? mSupplier.get() : null;
329             }
330 
331             @Override
destroy()332             public void destroy() {
333                 mConfigurationController.removeCallback(this);
334             }
335 
336             @Override
sortOrder()337             public int sortOrder() {
338                 return SORT_ORDER_UI_MODE;
339             }
340         }
341 
342         private class FeatureItem<T> implements Item<T> {
343             private final String mFeature;
344             private final Supplier<T> mSupplier;
345 
FeatureItem(String feature, Supplier<T> supplier)346             public FeatureItem(String feature, Supplier<T> supplier) {
347                 mSupplier = supplier;
348                 mFeature = feature;
349             }
350 
351             @Override
get()352             public T get() {
353                 return mDefaultContext.getPackageManager().hasSystemFeature(mFeature)
354                         ? mSupplier.get() : null;
355             }
356 
357             @Override
destroy()358             public void destroy() {
359 
360             }
361 
362             @Override
sortOrder()363             public int sortOrder() {
364                 return SORT_ORDER_FEATURE;
365             }
366         }
367 
368         private class Default<T> implements Item<T> {
369             private final Supplier<T> mSupplier;
370 
Default(Supplier<T> supplier)371             public Default(Supplier<T> supplier) {
372                 mSupplier = supplier;
373             }
374 
375             @Override
get()376             public T get() {
377                 return mSupplier.get();
378             }
379 
380             @Override
destroy()381             public void destroy() {
382 
383             }
384 
385             @Override
sortOrder()386             public int sortOrder() {
387                 return SORT_ORDER_DEFAULT;
388             }
389         }
390     }
391 
392     private interface Item<T> extends Producer<T> {
sortOrder()393         int sortOrder();
394     }
395 }
396