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