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