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