Loading packages/SystemUI/src/com/android/systemui/Dependency.java +5 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionControllerImpl; import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.FlashlightControllerImpl; import com.android.systemui.statusbar.policy.HotspotController; Loading Loading @@ -233,6 +235,9 @@ public class Dependency extends SystemUI { mProviders.put(FragmentService.class, () -> new FragmentService(mContext)); mProviders.put(ExtensionController.class, () -> new ExtensionControllerImpl()); // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } Loading packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -133,14 +133,7 @@ public class PluginManager extends BroadcastReceiver { public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls, boolean allowMultiple) { ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); if (info == null) { throw new RuntimeException(cls + " doesn't provide an interface"); } if (TextUtils.isEmpty(info.action())) { throw new RuntimeException(cls + " doesn't provide an action"); } addPluginListener(info.action(), listener, cls, allowMultiple); addPluginListener(getAction(cls), listener, cls, allowMultiple); } public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener, Loading Loading @@ -285,6 +278,17 @@ public class PluginManager extends BroadcastReceiver { return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader); } public static <P> String getAction(Class<P> cls) { ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); if (info == null) { throw new RuntimeException(cls + " doesn't provide an interface"); } if (TextUtils.isEmpty(info.action())) { throw new RuntimeException(cls + " doesn't provide an action"); } return info.action(); } private class AllPluginClassLoader extends ClassLoader { public AllPluginClassLoader(ClassLoader classLoader) { super(classLoader); Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +29 −63 Original line number Diff line number Diff line Loading @@ -19,9 +19,10 @@ package com.android.systemui.statusbar.phone; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK; import static com.android.systemui.tuner.LockscreenFragment.getIntentButton; import android.app.ActivityManager; import android.app.ActivityOptions; Loading Loading @@ -79,9 +80,12 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.tuner.LockscreenFragment; import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; Loading @@ -91,8 +95,7 @@ import com.android.systemui.tuner.TunerService.Tunable; */ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener, UnlockMethodCache.OnUnlockMethodChangedListener, AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener, Tunable { AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener { final static String TAG = "StatusBar/KeyguardBottomAreaView"; Loading Loading @@ -159,12 +162,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private Drawable mLeftAssistIcon; private IntentButton mRightButton = new DefaultRightButton(); private IntentButton mRightDefault = mRightButton; private IntentButton mRightPlugin; private Extension<IntentButton> mRightExtension; private String mRightButtonStr; private IntentButton mLeftButton = new DefaultLeftButton(); private IntentButton mLeftDefault = mLeftButton; private IntentButton mLeftPlugin; private Extension<IntentButton> mLeftExtension; private String mLeftButtonStr; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); private boolean mDozing; Loading Loading @@ -261,21 +262,28 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL protected void onAttachedToWindow() { super.onAttachedToWindow(); mAccessibilityController.addStateChangedCallback(this); Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN, mRightListener, IntentButtonProvider.class, false /* Only allow one */); Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN, mLeftListener, IntentButtonProvider.class, false /* Only allow one */); Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON, LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON); mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN, p -> p.getIntentButton()) .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON)) .withDefault(() -> new DefaultRightButton()) .withCallback(button -> setRightButton(button)) .build(); mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN, p -> p.getIntentButton()) .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON)) .withDefault(() -> new DefaultLeftButton()) .withCallback(button -> setLeftButton(button)) .build(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mAccessibilityController.removeStateChangedCallback(this); Dependency.get(PluginManager.class).removePluginListener(mRightListener); Dependency.get(PluginManager.class).removePluginListener(mLeftListener); Dependency.get(TunerService.class).removeTunable(this); mRightExtension.destroy(); mLeftExtension.destroy(); } private void initAccessibility() { Loading Loading @@ -790,62 +798,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL inflateCameraPreview(); } @Override public void onTuningChanged(String key, String newValue) { if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) { mLeftButtonStr = newValue; mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null; mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault); updateLeftAffordance(); } else { mRightButtonStr = newValue; mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault); updateRightAffordanceIcon(); updateCameraVisibility(); inflateCameraPreview(); } } private void setRightButton(IntentButton button) { mRightPlugin = button; mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault); mRightButton = button; updateRightAffordanceIcon(); updateCameraVisibility(); inflateCameraPreview(); } private void setLeftButton(IntentButton button) { mLeftPlugin = button; mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault); mLeftButton = button; if (!(mLeftButton instanceof DefaultLeftButton)) { mLeftIsVoiceAssist = false; updateLeftAffordance(); } private final PluginListener<IntentButtonProvider> mRightListener = new PluginListener<IntentButtonProvider>() { @Override public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) { setRightButton(plugin.getIntentButton()); } @Override public void onPluginDisconnected(IntentButtonProvider plugin) { setRightButton(null); } }; private final PluginListener<IntentButtonProvider> mLeftListener = new PluginListener<IntentButtonProvider>() { @Override public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) { setLeftButton(plugin.getIntentButton()); } @Override public void onPluginDisconnected(IntentButtonProvider plugin) { setLeftButton(null); updateLeftAffordance(); } }; public void setDozing(boolean dozing, boolean animate) { mDozing = dozing; Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.android.systemui.statusbar.policy; import com.android.systemui.Dependency; import com.android.systemui.plugins.Plugin; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; /** * Utility class used to select between a plugin, tuner settings, and a default implementation * of an interface. */ public interface ExtensionController { <T> ExtensionBuilder<T> newExtension(Class<T> cls); interface Extension<T> { T get(); void destroy(); } interface ExtensionBuilder<T> { ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory); <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls); <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action); <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter); ExtensionBuilder<T> withDefault(Supplier<T> def); ExtensionBuilder<T> withCallback(Consumer<T> callback); Extension build(); } public interface PluginConverter<T, P> { T getInterfaceFromPlugin(P plugin); } public interface TunerFactory<T> { String[] keys(); T create(Map<String, String> settings); } } packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java 0 → 100644 +236 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.android.systemui.statusbar.policy; import com.android.systemui.Dependency; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import android.content.Context; import android.util.ArrayMap; import java.util.ArrayList; import java.util.Collections; import java.util.function.Consumer; import java.util.function.Supplier; public class ExtensionControllerImpl implements ExtensionController { @Override public <T> ExtensionBuilder<T> newExtension(Class<T> cls) { return new ExtensionBuilder<>(); } private interface Producer<T> { T get(); void destroy(); } private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> { private ExtensionImpl<T> mExtension = new ExtensionImpl<>(); @Override public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) { mExtension.addTunerFactory(factory, factory.keys()); return this; } @Override public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) { return withPlugin(cls, PluginManager.getAction(cls)); } @Override public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls, String action) { return withPlugin(cls, action, null); } @Override public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter) { mExtension.addPlugin(action, cls, converter); return this; } @Override public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) { mExtension.addDefault(def); return this; } @Override public ExtensionController.ExtensionBuilder<T> withCallback( Consumer<T> callback) { mExtension.mCallbacks.add(callback); return this; } @Override public ExtensionController.Extension build() { // Manually sort, plugins first, tuners second, defaults last. Collections.sort(mExtension.mProducers, (o1, o2) -> { if (o1 instanceof ExtensionImpl.PluginItem) { if (o2 instanceof ExtensionImpl.PluginItem) { return 0; } else { return -1; } } if (o1 instanceof ExtensionImpl.TunerItem) { if (o2 instanceof ExtensionImpl.PluginItem) { return 1; } else if (o2 instanceof ExtensionImpl.TunerItem) { return 0; } else { return -1; } } return 0; }); mExtension.notifyChanged(); return mExtension; } } private class ExtensionImpl<T> implements ExtensionController.Extension<T> { private final ArrayList<Producer<T>> mProducers = new ArrayList<>(); private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>(); private T mItem; @Override public T get() { return mItem; } @Override public void destroy() { for (int i = 0; i < mProducers.size(); i++) { mProducers.get(i).destroy(); } } private void notifyChanged() { for (int i = 0; i < mProducers.size(); i++) { final T item = mProducers.get(i).get(); if (item != null) { mItem = item; break; } } for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).accept(mItem); } } public void addDefault(Supplier<T> def) { mProducers.add(new Default(def)); } public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) { mProducers.add(new PluginItem(action, cls, converter)); } public void addTunerFactory(TunerFactory<T> factory, String[] keys) { mProducers.add(new TunerItem(factory, factory.keys())); } private class PluginItem<P extends Plugin> implements Producer<T>, PluginListener<P> { private final PluginConverter<T, P> mConverter; private T mItem; public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) { mConverter = converter; Dependency.get(PluginManager.class).addPluginListener(action, this, cls); } @Override public void onPluginConnected(P plugin, Context pluginContext) { if (mConverter != null) { mItem = mConverter.getInterfaceFromPlugin(plugin); } else { mItem = (T) plugin; } notifyChanged(); } @Override public void onPluginDisconnected(P plugin) { mItem = null; notifyChanged(); } @Override public T get() { return mItem; } @Override public void destroy() { Dependency.get(PluginManager.class).removePluginListener(this); } } private class TunerItem<T> implements Producer<T>, Tunable { private final TunerFactory<T> mFactory; private final ArrayMap<String, String> mSettings = new ArrayMap<>(); private T mItem; public TunerItem(TunerFactory<T> factory, String... setting) { mFactory = factory; Dependency.get(TunerService.class).addTunable(this, setting); } @Override public T get() { return mItem; } @Override public void destroy() { Dependency.get(TunerService.class).removeTunable(this); } @Override public void onTuningChanged(String key, String newValue) { mSettings.put(key, newValue); mItem = mFactory.create(mSettings); notifyChanged(); } } private class Default<T> implements Producer<T> { private final Supplier<T> mSupplier; public Default(Supplier<T> supplier) { mSupplier = supplier; } @Override public T get() { return mSupplier.get(); } @Override public void destroy() { } } } } Loading
packages/SystemUI/src/com/android/systemui/Dependency.java +5 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionControllerImpl; import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.FlashlightControllerImpl; import com.android.systemui.statusbar.policy.HotspotController; Loading Loading @@ -233,6 +235,9 @@ public class Dependency extends SystemUI { mProviders.put(FragmentService.class, () -> new FragmentService(mContext)); mProviders.put(ExtensionController.class, () -> new ExtensionControllerImpl()); // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } Loading
packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -133,14 +133,7 @@ public class PluginManager extends BroadcastReceiver { public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls, boolean allowMultiple) { ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); if (info == null) { throw new RuntimeException(cls + " doesn't provide an interface"); } if (TextUtils.isEmpty(info.action())) { throw new RuntimeException(cls + " doesn't provide an action"); } addPluginListener(info.action(), listener, cls, allowMultiple); addPluginListener(getAction(cls), listener, cls, allowMultiple); } public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener, Loading Loading @@ -285,6 +278,17 @@ public class PluginManager extends BroadcastReceiver { return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader); } public static <P> String getAction(Class<P> cls) { ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); if (info == null) { throw new RuntimeException(cls + " doesn't provide an interface"); } if (TextUtils.isEmpty(info.action())) { throw new RuntimeException(cls + " doesn't provide an action"); } return info.action(); } private class AllPluginClassLoader extends ClassLoader { public AllPluginClassLoader(ClassLoader classLoader) { super(classLoader); Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +29 −63 Original line number Diff line number Diff line Loading @@ -19,9 +19,10 @@ package com.android.systemui.statusbar.phone; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK; import static com.android.systemui.tuner.LockscreenFragment.getIntentButton; import android.app.ActivityManager; import android.app.ActivityOptions; Loading Loading @@ -79,9 +80,12 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.tuner.LockscreenFragment; import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; Loading @@ -91,8 +95,7 @@ import com.android.systemui.tuner.TunerService.Tunable; */ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener, UnlockMethodCache.OnUnlockMethodChangedListener, AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener, Tunable { AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener { final static String TAG = "StatusBar/KeyguardBottomAreaView"; Loading Loading @@ -159,12 +162,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private Drawable mLeftAssistIcon; private IntentButton mRightButton = new DefaultRightButton(); private IntentButton mRightDefault = mRightButton; private IntentButton mRightPlugin; private Extension<IntentButton> mRightExtension; private String mRightButtonStr; private IntentButton mLeftButton = new DefaultLeftButton(); private IntentButton mLeftDefault = mLeftButton; private IntentButton mLeftPlugin; private Extension<IntentButton> mLeftExtension; private String mLeftButtonStr; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); private boolean mDozing; Loading Loading @@ -261,21 +262,28 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL protected void onAttachedToWindow() { super.onAttachedToWindow(); mAccessibilityController.addStateChangedCallback(this); Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN, mRightListener, IntentButtonProvider.class, false /* Only allow one */); Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN, mLeftListener, IntentButtonProvider.class, false /* Only allow one */); Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON, LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON); mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN, p -> p.getIntentButton()) .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON)) .withDefault(() -> new DefaultRightButton()) .withCallback(button -> setRightButton(button)) .build(); mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN, p -> p.getIntentButton()) .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON)) .withDefault(() -> new DefaultLeftButton()) .withCallback(button -> setLeftButton(button)) .build(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mAccessibilityController.removeStateChangedCallback(this); Dependency.get(PluginManager.class).removePluginListener(mRightListener); Dependency.get(PluginManager.class).removePluginListener(mLeftListener); Dependency.get(TunerService.class).removeTunable(this); mRightExtension.destroy(); mLeftExtension.destroy(); } private void initAccessibility() { Loading Loading @@ -790,62 +798,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL inflateCameraPreview(); } @Override public void onTuningChanged(String key, String newValue) { if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) { mLeftButtonStr = newValue; mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null; mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault); updateLeftAffordance(); } else { mRightButtonStr = newValue; mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault); updateRightAffordanceIcon(); updateCameraVisibility(); inflateCameraPreview(); } } private void setRightButton(IntentButton button) { mRightPlugin = button; mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault); mRightButton = button; updateRightAffordanceIcon(); updateCameraVisibility(); inflateCameraPreview(); } private void setLeftButton(IntentButton button) { mLeftPlugin = button; mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault); mLeftButton = button; if (!(mLeftButton instanceof DefaultLeftButton)) { mLeftIsVoiceAssist = false; updateLeftAffordance(); } private final PluginListener<IntentButtonProvider> mRightListener = new PluginListener<IntentButtonProvider>() { @Override public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) { setRightButton(plugin.getIntentButton()); } @Override public void onPluginDisconnected(IntentButtonProvider plugin) { setRightButton(null); } }; private final PluginListener<IntentButtonProvider> mLeftListener = new PluginListener<IntentButtonProvider>() { @Override public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) { setLeftButton(plugin.getIntentButton()); } @Override public void onPluginDisconnected(IntentButtonProvider plugin) { setLeftButton(null); updateLeftAffordance(); } }; public void setDozing(boolean dozing, boolean animate) { mDozing = dozing; Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.android.systemui.statusbar.policy; import com.android.systemui.Dependency; import com.android.systemui.plugins.Plugin; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; /** * Utility class used to select between a plugin, tuner settings, and a default implementation * of an interface. */ public interface ExtensionController { <T> ExtensionBuilder<T> newExtension(Class<T> cls); interface Extension<T> { T get(); void destroy(); } interface ExtensionBuilder<T> { ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory); <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls); <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action); <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter); ExtensionBuilder<T> withDefault(Supplier<T> def); ExtensionBuilder<T> withCallback(Consumer<T> callback); Extension build(); } public interface PluginConverter<T, P> { T getInterfaceFromPlugin(P plugin); } public interface TunerFactory<T> { String[] keys(); T create(Map<String, String> settings); } }
packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java 0 → 100644 +236 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.android.systemui.statusbar.policy; import com.android.systemui.Dependency; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import android.content.Context; import android.util.ArrayMap; import java.util.ArrayList; import java.util.Collections; import java.util.function.Consumer; import java.util.function.Supplier; public class ExtensionControllerImpl implements ExtensionController { @Override public <T> ExtensionBuilder<T> newExtension(Class<T> cls) { return new ExtensionBuilder<>(); } private interface Producer<T> { T get(); void destroy(); } private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> { private ExtensionImpl<T> mExtension = new ExtensionImpl<>(); @Override public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) { mExtension.addTunerFactory(factory, factory.keys()); return this; } @Override public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) { return withPlugin(cls, PluginManager.getAction(cls)); } @Override public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls, String action) { return withPlugin(cls, action, null); } @Override public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter) { mExtension.addPlugin(action, cls, converter); return this; } @Override public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) { mExtension.addDefault(def); return this; } @Override public ExtensionController.ExtensionBuilder<T> withCallback( Consumer<T> callback) { mExtension.mCallbacks.add(callback); return this; } @Override public ExtensionController.Extension build() { // Manually sort, plugins first, tuners second, defaults last. Collections.sort(mExtension.mProducers, (o1, o2) -> { if (o1 instanceof ExtensionImpl.PluginItem) { if (o2 instanceof ExtensionImpl.PluginItem) { return 0; } else { return -1; } } if (o1 instanceof ExtensionImpl.TunerItem) { if (o2 instanceof ExtensionImpl.PluginItem) { return 1; } else if (o2 instanceof ExtensionImpl.TunerItem) { return 0; } else { return -1; } } return 0; }); mExtension.notifyChanged(); return mExtension; } } private class ExtensionImpl<T> implements ExtensionController.Extension<T> { private final ArrayList<Producer<T>> mProducers = new ArrayList<>(); private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>(); private T mItem; @Override public T get() { return mItem; } @Override public void destroy() { for (int i = 0; i < mProducers.size(); i++) { mProducers.get(i).destroy(); } } private void notifyChanged() { for (int i = 0; i < mProducers.size(); i++) { final T item = mProducers.get(i).get(); if (item != null) { mItem = item; break; } } for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).accept(mItem); } } public void addDefault(Supplier<T> def) { mProducers.add(new Default(def)); } public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) { mProducers.add(new PluginItem(action, cls, converter)); } public void addTunerFactory(TunerFactory<T> factory, String[] keys) { mProducers.add(new TunerItem(factory, factory.keys())); } private class PluginItem<P extends Plugin> implements Producer<T>, PluginListener<P> { private final PluginConverter<T, P> mConverter; private T mItem; public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) { mConverter = converter; Dependency.get(PluginManager.class).addPluginListener(action, this, cls); } @Override public void onPluginConnected(P plugin, Context pluginContext) { if (mConverter != null) { mItem = mConverter.getInterfaceFromPlugin(plugin); } else { mItem = (T) plugin; } notifyChanged(); } @Override public void onPluginDisconnected(P plugin) { mItem = null; notifyChanged(); } @Override public T get() { return mItem; } @Override public void destroy() { Dependency.get(PluginManager.class).removePluginListener(this); } } private class TunerItem<T> implements Producer<T>, Tunable { private final TunerFactory<T> mFactory; private final ArrayMap<String, String> mSettings = new ArrayMap<>(); private T mItem; public TunerItem(TunerFactory<T> factory, String... setting) { mFactory = factory; Dependency.get(TunerService.class).addTunable(this, setting); } @Override public T get() { return mItem; } @Override public void destroy() { Dependency.get(TunerService.class).removeTunable(this); } @Override public void onTuningChanged(String key, String newValue) { mSettings.put(key, newValue); mItem = mFactory.create(mSettings); notifyChanged(); } } private class Default<T> implements Producer<T> { private final Supplier<T> mSupplier; public Default(Supplier<T> supplier) { mSupplier = supplier; } @Override public T get() { return mSupplier.get(); } @Override public void destroy() { } } } }