Loading core/java/android/provider/Settings.java +1 −1 Original line number Diff line number Diff line Loading @@ -6103,7 +6103,7 @@ public final class Settings { * Indicates which clock face to show on lock screen and AOD while docked. * @hide */ private static final String DOCKED_CLOCK_FACE = "docked_clock_face"; public static final String DOCKED_CLOCK_FACE = "docked_clock_face"; /** * Set by the system to track if the user needs to see the call to action for Loading core/tests/coretests/src/android/provider/SettingsBackupTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -620,6 +620,7 @@ public class SettingsBackupTest { Settings.Secure.DISABLED_PRINT_SERVICES, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, Settings.Secure.DISPLAY_DENSITY_FORCED, Settings.Secure.DOCKED_CLOCK_FACE, Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P Loading packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +47 −70 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.keyguard.clock; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; Loading @@ -25,16 +26,18 @@ import android.os.Looper; import android.provider.Settings; import android.view.LayoutInflater; import androidx.annotation.VisibleForTesting; import com.android.keyguard.R; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManager.DockEventListener; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -45,7 +48,6 @@ import javax.inject.Singleton; @Singleton public final class ClockManager { private final LayoutInflater mLayoutInflater; private final ContentResolver mContentResolver; private final List<ClockInfo> mClockInfos = new ArrayList<>(); Loading @@ -62,7 +64,6 @@ public final class ClockManager { } } }; private final ExtensionController mExtensionController; /** * Used to select between plugin or default implementations of ClockPlugin interface. Loading @@ -72,13 +73,35 @@ public final class ClockManager { * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads. */ private final Consumer<ClockPlugin> mClockPluginConsumer = this::setClockPlugin; /** * Supplier of default ClockPlugin implementation. */ private final DefaultClockSupplier mDefaultClockSupplier; /** * Observe changes to dock state to know when to switch the clock face. */ private final DockEventListener mDockEventListener = new DockEventListener() { @Override public void onEvent(int event) { final boolean isDocked = (event == DockManager.STATE_DOCKED || event == DockManager.STATE_DOCKED_HIDE); mDefaultClockSupplier.setDocked(isDocked); if (mClockExtension != null) { mClockExtension.reload(); } } }; @Nullable private final DockManager mDockManager; private final List<ClockChangedListener> mListeners = new ArrayList<>(); @Inject public ClockManager(Context context, ExtensionController extensionController) { public ClockManager(Context context, ExtensionController extensionController, @Nullable DockManager dockManager) { mExtensionController = extensionController; mLayoutInflater = LayoutInflater.from(context); mDockManager = dockManager; mContentResolver = context.getContentResolver(); Resources res = context.getResources(); Loading Loading @@ -110,6 +133,9 @@ public final class ClockManager { .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.type_thumbnail)) .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.type_preview)) .build()); mDefaultClockSupplier = new DefaultClockSupplier(new SettingsWrapper(mContentResolver), LayoutInflater.from(context)); } /** Loading Loading @@ -154,41 +180,32 @@ public final class ClockManager { mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), false, mContentObserver); mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE), false, mContentObserver); if (mDockManager != null) { mDockManager.addListener(mDockEventListener); } mClockExtension = mExtensionController.newExtension(ClockPlugin.class) .withPlugin(ClockPlugin.class) .withCallback(mClockPluginConsumer) // Using withDefault even though this isn't the default as a workaround. // ExtensionBuilder doesn't provide the ability to supply a ClockPlugin // instance based off of the value of a setting. Since multiple "default" // can be provided, using a supplier that changes the settings value. // A null return will cause Extension#reload to look at the next "default" // supplier. .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, BubbleClockController.class.getName(), () -> BubbleClockController.build(mLayoutInflater))) .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, StretchAnalogClockController.class.getName(), () -> StretchAnalogClockController.build(mLayoutInflater))) .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, TypeClockController.class.getName(), () -> TypeClockController.build(mLayoutInflater))) .withDefault(mDefaultClockSupplier) .build(); } private void unregister() { mContentResolver.unregisterContentObserver(mContentObserver); if (mDockManager != null) { mDockManager.removeListener(mDockEventListener); } mClockExtension.destroy(); } @VisibleForTesting boolean isDocked() { return mDefaultClockSupplier.isDocked(); } /** * Listener for events that should cause the custom clock face to change. */ Loading @@ -200,44 +217,4 @@ public final class ClockManager { */ void onClockChanged(ClockPlugin clock); } /** * Supplier that only gets an instance when a settings value matches expected value. */ private static class SettingsGattedSupplier implements Supplier<ClockPlugin> { private final ContentResolver mContentResolver; private final String mKey; private final String mValue; private final Supplier<ClockPlugin> mSupplier; /** * Constructs a supplier that changes secure setting key against value. * * @param contentResolver Used to look up settings value. * @param key Settings key. * @param value If the setting matches this values that get supplies a ClockPlugin * instance. * @param supplier Supplier of ClockPlugin instance, only used if the setting * matches value. */ SettingsGattedSupplier(ContentResolver contentResolver, String key, String value, Supplier<ClockPlugin> supplier) { mContentResolver = contentResolver; mKey = key; mValue = value; mSupplier = supplier; } /** * Returns null if the settings value doesn't match the expected value. * * A null return causes Extension#reload to skip this supplier and move to the next. */ @Override public ClockPlugin get() { final String currentValue = Settings.Secure.getString(mContentResolver, mKey); return Objects.equals(currentValue, mValue) ? mSupplier.get() : null; } } } packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.keyguard.clock; import android.util.ArrayMap; import android.view.LayoutInflater; import com.android.systemui.plugins.ClockPlugin; import java.util.Map; import java.util.function.Supplier; /** * Supplier that only gets an instance when a settings value matches expected value. */ public class DefaultClockSupplier implements Supplier<ClockPlugin> { private final SettingsWrapper mSettingsWrapper; /** * Map from expected value stored in settings to supplier of custom clock face. */ private final Map<String, Supplier<ClockPlugin>> mClocks = new ArrayMap<>(); /** * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face * to show. */ private boolean mIsDocked; /** * Constructs a supplier that changes secure setting key against value. * * @param settingsWrapper Wrapper around settings used to look up the custom clock face. * @param layoutInflater Provided to clocks as dependency to inflate clock views. */ public DefaultClockSupplier(SettingsWrapper settingsWrapper, LayoutInflater layoutInflater) { mSettingsWrapper = settingsWrapper; mClocks.put(BubbleClockController.class.getName(), () -> BubbleClockController.build(layoutInflater)); mClocks.put(StretchAnalogClockController.class.getName(), () -> StretchAnalogClockController.build(layoutInflater)); mClocks.put(TypeClockController.class.getName(), () -> TypeClockController.build(layoutInflater)); } /** * Sets the dock state. * * @param isDocked True when docked, false otherwise. */ public void setDocked(boolean isDocked) { mIsDocked = isDocked; } boolean isDocked() { return mIsDocked; } /** * Get the custom clock face based on values in settings. * * @return Custom clock face, null if the settings value doesn't match a custom clock. */ @Override public ClockPlugin get() { ClockPlugin plugin = null; if (mIsDocked) { final String name = mSettingsWrapper.getDockedClockFace(); if (name != null) { Supplier<ClockPlugin> supplier = mClocks.get(name); if (supplier != null) { plugin = supplier.get(); if (plugin != null) { return plugin; } } } } final String name = mSettingsWrapper.getLockScreenCustomClockFace(); if (name != null) { Supplier<ClockPlugin> supplier = mClocks.get(name); if (supplier != null) { plugin = supplier.get(); } } return plugin; } } packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java 0 → 100644 +48 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.keyguard.clock; import android.content.ContentResolver; import android.provider.Settings; /** * Wrapper around Settings used for testing. */ public class SettingsWrapper { private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE; private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE; private ContentResolver mContentResolver; public SettingsWrapper(ContentResolver contentResolver) { mContentResolver = contentResolver; } /** * Gets the value stored in settings for the custom clock face. */ public String getLockScreenCustomClockFace() { return Settings.Secure.getString(mContentResolver, CUSTOM_CLOCK_FACE); } /** * Gets the value stored in settings for the clock face to use when docked. */ public String getDockedClockFace() { return Settings.Secure.getString(mContentResolver, DOCKED_CLOCK_FACE); } } Loading
core/java/android/provider/Settings.java +1 −1 Original line number Diff line number Diff line Loading @@ -6103,7 +6103,7 @@ public final class Settings { * Indicates which clock face to show on lock screen and AOD while docked. * @hide */ private static final String DOCKED_CLOCK_FACE = "docked_clock_face"; public static final String DOCKED_CLOCK_FACE = "docked_clock_face"; /** * Set by the system to track if the user needs to see the call to action for Loading
core/tests/coretests/src/android/provider/SettingsBackupTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -620,6 +620,7 @@ public class SettingsBackupTest { Settings.Secure.DISABLED_PRINT_SERVICES, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, Settings.Secure.DISPLAY_DENSITY_FORCED, Settings.Secure.DOCKED_CLOCK_FACE, Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P Loading
packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +47 −70 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.keyguard.clock; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; Loading @@ -25,16 +26,18 @@ import android.os.Looper; import android.provider.Settings; import android.view.LayoutInflater; import androidx.annotation.VisibleForTesting; import com.android.keyguard.R; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManager.DockEventListener; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -45,7 +48,6 @@ import javax.inject.Singleton; @Singleton public final class ClockManager { private final LayoutInflater mLayoutInflater; private final ContentResolver mContentResolver; private final List<ClockInfo> mClockInfos = new ArrayList<>(); Loading @@ -62,7 +64,6 @@ public final class ClockManager { } } }; private final ExtensionController mExtensionController; /** * Used to select between plugin or default implementations of ClockPlugin interface. Loading @@ -72,13 +73,35 @@ public final class ClockManager { * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads. */ private final Consumer<ClockPlugin> mClockPluginConsumer = this::setClockPlugin; /** * Supplier of default ClockPlugin implementation. */ private final DefaultClockSupplier mDefaultClockSupplier; /** * Observe changes to dock state to know when to switch the clock face. */ private final DockEventListener mDockEventListener = new DockEventListener() { @Override public void onEvent(int event) { final boolean isDocked = (event == DockManager.STATE_DOCKED || event == DockManager.STATE_DOCKED_HIDE); mDefaultClockSupplier.setDocked(isDocked); if (mClockExtension != null) { mClockExtension.reload(); } } }; @Nullable private final DockManager mDockManager; private final List<ClockChangedListener> mListeners = new ArrayList<>(); @Inject public ClockManager(Context context, ExtensionController extensionController) { public ClockManager(Context context, ExtensionController extensionController, @Nullable DockManager dockManager) { mExtensionController = extensionController; mLayoutInflater = LayoutInflater.from(context); mDockManager = dockManager; mContentResolver = context.getContentResolver(); Resources res = context.getResources(); Loading Loading @@ -110,6 +133,9 @@ public final class ClockManager { .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.type_thumbnail)) .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.type_preview)) .build()); mDefaultClockSupplier = new DefaultClockSupplier(new SettingsWrapper(mContentResolver), LayoutInflater.from(context)); } /** Loading Loading @@ -154,41 +180,32 @@ public final class ClockManager { mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), false, mContentObserver); mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE), false, mContentObserver); if (mDockManager != null) { mDockManager.addListener(mDockEventListener); } mClockExtension = mExtensionController.newExtension(ClockPlugin.class) .withPlugin(ClockPlugin.class) .withCallback(mClockPluginConsumer) // Using withDefault even though this isn't the default as a workaround. // ExtensionBuilder doesn't provide the ability to supply a ClockPlugin // instance based off of the value of a setting. Since multiple "default" // can be provided, using a supplier that changes the settings value. // A null return will cause Extension#reload to look at the next "default" // supplier. .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, BubbleClockController.class.getName(), () -> BubbleClockController.build(mLayoutInflater))) .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, StretchAnalogClockController.class.getName(), () -> StretchAnalogClockController.build(mLayoutInflater))) .withDefault( new SettingsGattedSupplier( mContentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, TypeClockController.class.getName(), () -> TypeClockController.build(mLayoutInflater))) .withDefault(mDefaultClockSupplier) .build(); } private void unregister() { mContentResolver.unregisterContentObserver(mContentObserver); if (mDockManager != null) { mDockManager.removeListener(mDockEventListener); } mClockExtension.destroy(); } @VisibleForTesting boolean isDocked() { return mDefaultClockSupplier.isDocked(); } /** * Listener for events that should cause the custom clock face to change. */ Loading @@ -200,44 +217,4 @@ public final class ClockManager { */ void onClockChanged(ClockPlugin clock); } /** * Supplier that only gets an instance when a settings value matches expected value. */ private static class SettingsGattedSupplier implements Supplier<ClockPlugin> { private final ContentResolver mContentResolver; private final String mKey; private final String mValue; private final Supplier<ClockPlugin> mSupplier; /** * Constructs a supplier that changes secure setting key against value. * * @param contentResolver Used to look up settings value. * @param key Settings key. * @param value If the setting matches this values that get supplies a ClockPlugin * instance. * @param supplier Supplier of ClockPlugin instance, only used if the setting * matches value. */ SettingsGattedSupplier(ContentResolver contentResolver, String key, String value, Supplier<ClockPlugin> supplier) { mContentResolver = contentResolver; mKey = key; mValue = value; mSupplier = supplier; } /** * Returns null if the settings value doesn't match the expected value. * * A null return causes Extension#reload to skip this supplier and move to the next. */ @Override public ClockPlugin get() { final String currentValue = Settings.Secure.getString(mContentResolver, mKey); return Objects.equals(currentValue, mValue) ? mSupplier.get() : null; } } }
packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.keyguard.clock; import android.util.ArrayMap; import android.view.LayoutInflater; import com.android.systemui.plugins.ClockPlugin; import java.util.Map; import java.util.function.Supplier; /** * Supplier that only gets an instance when a settings value matches expected value. */ public class DefaultClockSupplier implements Supplier<ClockPlugin> { private final SettingsWrapper mSettingsWrapper; /** * Map from expected value stored in settings to supplier of custom clock face. */ private final Map<String, Supplier<ClockPlugin>> mClocks = new ArrayMap<>(); /** * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face * to show. */ private boolean mIsDocked; /** * Constructs a supplier that changes secure setting key against value. * * @param settingsWrapper Wrapper around settings used to look up the custom clock face. * @param layoutInflater Provided to clocks as dependency to inflate clock views. */ public DefaultClockSupplier(SettingsWrapper settingsWrapper, LayoutInflater layoutInflater) { mSettingsWrapper = settingsWrapper; mClocks.put(BubbleClockController.class.getName(), () -> BubbleClockController.build(layoutInflater)); mClocks.put(StretchAnalogClockController.class.getName(), () -> StretchAnalogClockController.build(layoutInflater)); mClocks.put(TypeClockController.class.getName(), () -> TypeClockController.build(layoutInflater)); } /** * Sets the dock state. * * @param isDocked True when docked, false otherwise. */ public void setDocked(boolean isDocked) { mIsDocked = isDocked; } boolean isDocked() { return mIsDocked; } /** * Get the custom clock face based on values in settings. * * @return Custom clock face, null if the settings value doesn't match a custom clock. */ @Override public ClockPlugin get() { ClockPlugin plugin = null; if (mIsDocked) { final String name = mSettingsWrapper.getDockedClockFace(); if (name != null) { Supplier<ClockPlugin> supplier = mClocks.get(name); if (supplier != null) { plugin = supplier.get(); if (plugin != null) { return plugin; } } } } final String name = mSettingsWrapper.getLockScreenCustomClockFace(); if (name != null) { Supplier<ClockPlugin> supplier = mClocks.get(name); if (supplier != null) { plugin = supplier.get(); } } return plugin; } }
packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java 0 → 100644 +48 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.keyguard.clock; import android.content.ContentResolver; import android.provider.Settings; /** * Wrapper around Settings used for testing. */ public class SettingsWrapper { private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE; private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE; private ContentResolver mContentResolver; public SettingsWrapper(ContentResolver contentResolver) { mContentResolver = contentResolver; } /** * Gets the value stored in settings for the custom clock face. */ public String getLockScreenCustomClockFace() { return Settings.Secure.getString(mContentResolver, CUSTOM_CLOCK_FACE); } /** * Gets the value stored in settings for the clock face to use when docked. */ public String getDockedClockFace() { return Settings.Secure.getString(mContentResolver, DOCKED_CLOCK_FACE); } }