ExtensionControllerImpl.java revision 0b80c4e518110ba385a1b83d1e29325f164dc90d
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 private void notifyChanged() { 144 mItem = null; 145 for (int i = 0; i < mProducers.size(); i++) { 146 final T item = mProducers.get(i).get(); 147 if (item != null) { 148 mItem = item; 149 break; 150 } 151 } 152 for (int i = 0; i < mCallbacks.size(); i++) { 153 mCallbacks.get(i).accept(mItem); 154 } 155 } 156 157 public void addDefault(Supplier<T> def) { 158 mProducers.add(new Default(def)); 159 } 160 161 public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) { 162 mProducers.add(new PluginItem(action, cls, converter)); 163 } 164 165 public void addTunerFactory(TunerFactory<T> factory, String[] keys) { 166 mProducers.add(new TunerItem(factory, factory.keys())); 167 } 168 169 public void addUiMode(int uiMode, Supplier<T> mode) { 170 mProducers.add(new UiModeItem(uiMode, mode)); 171 } 172 173 private class PluginItem<P extends Plugin> implements Item<T>, PluginListener<P> { 174 private final PluginConverter<T, P> mConverter; 175 private T mItem; 176 177 public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) { 178 mConverter = converter; 179 Dependency.get(PluginManager.class).addPluginListener(action, this, cls); 180 } 181 182 @Override 183 public void onPluginConnected(P plugin, Context pluginContext) { 184 mPluginContext = pluginContext; 185 if (mConverter != null) { 186 mItem = mConverter.getInterfaceFromPlugin(plugin); 187 } else { 188 mItem = (T) plugin; 189 } 190 notifyChanged(); 191 } 192 193 @Override 194 public void onPluginDisconnected(P plugin) { 195 mPluginContext = null; 196 mItem = null; 197 notifyChanged(); 198 } 199 200 @Override 201 public T get() { 202 return mItem; 203 } 204 205 @Override 206 public void destroy() { 207 Dependency.get(PluginManager.class).removePluginListener(this); 208 } 209 210 @Override 211 public int sortOrder() { 212 return SORT_ORDER_PLUGIN; 213 } 214 } 215 216 private class TunerItem<T> implements Item<T>, Tunable { 217 private final TunerFactory<T> mFactory; 218 private final ArrayMap<String, String> mSettings = new ArrayMap<>(); 219 private T mItem; 220 221 public TunerItem(TunerFactory<T> factory, String... setting) { 222 mFactory = factory; 223 Dependency.get(TunerService.class).addTunable(this, setting); 224 } 225 226 @Override 227 public T get() { 228 return mItem; 229 } 230 231 @Override 232 public void destroy() { 233 Dependency.get(TunerService.class).removeTunable(this); 234 } 235 236 @Override 237 public void onTuningChanged(String key, String newValue) { 238 mSettings.put(key, newValue); 239 mItem = mFactory.create(mSettings); 240 notifyChanged(); 241 } 242 243 @Override 244 public int sortOrder() { 245 return SORT_ORDER_TUNER; 246 } 247 } 248 249 private class UiModeItem<T> implements Item<T>, ConfigurationListener { 250 251 private final int mDesiredUiMode; 252 private final Supplier<T> mSupplier; 253 private int mUiMode; 254 private Handler mHandler = new Handler(); 255 256 public UiModeItem(int uiMode, Supplier<T> supplier) { 257 mDesiredUiMode = uiMode; 258 mSupplier = supplier; 259 mUiMode = mDefaultContext.getResources().getConfiguration().uiMode; 260 Dependency.get(ConfigurationController.class).addCallback(this); 261 } 262 263 @Override 264 public void onConfigChanged(Configuration newConfig) { 265 int newMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK; 266 if (newMode != mUiMode) { 267 mUiMode = newMode; 268 // Post to make sure we don't have concurrent modifications. 269 mHandler.post(ExtensionImpl.this::notifyChanged); 270 } 271 } 272 273 @Override 274 public T get() { 275 return (mUiMode == mDesiredUiMode) ? mSupplier.get() : null; 276 } 277 278 @Override 279 public void destroy() { 280 Dependency.get(ConfigurationController.class).removeCallback(this); 281 } 282 283 @Override 284 public int sortOrder() { 285 return SORT_ORDER_UI_MODE; 286 } 287 } 288 289 private class Default<T> implements Item<T> { 290 private final Supplier<T> mSupplier; 291 292 public Default(Supplier<T> supplier) { 293 mSupplier = supplier; 294 } 295 296 @Override 297 public T get() { 298 return mSupplier.get(); 299 } 300 301 @Override 302 public void destroy() { 303 304 } 305 306 @Override 307 public int sortOrder() { 308 return SORT_ORDER_DEFAULT; 309 } 310 } 311 } 312 313 private interface Item<T> extends Producer<T> { 314 int sortOrder(); 315 } 316} 317