diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bca028668942c..3488543701a61 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9056,6 +9056,16 @@ public final class Settings { @Readable public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component"; + /** + * The complications that are enabled to be shown over the screensaver by the user. Holds + * a comma separated list of + * {@link com.android.settingslib.dream.DreamBackend.ComplicationType}. + * + * @hide + */ + public static final String SCREENSAVER_ENABLED_COMPLICATIONS = + "screensaver_enabled_complications"; + /** * The default NFC payment component * @hide diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml index 45253bb7944af..b150e0169a962 100644 --- a/packages/SettingsLib/res/values/config.xml +++ b/packages/SettingsLib/res/values/config.xml @@ -28,4 +28,9 @@ false + + + + + \ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java index aed2ec10e9245..3c444f2b95b3b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java @@ -38,6 +38,8 @@ import android.util.AttributeSet; import android.util.Log; import android.util.Xml; +import com.android.settingslib.R; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -45,9 +47,12 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class DreamBackend { private static final String TAG = "DreamBackend"; @@ -78,19 +83,41 @@ public class DreamBackend { @Retention(RetentionPolicy.SOURCE) @IntDef({WHILE_CHARGING, WHILE_DOCKED, EITHER, NEVER}) - public @interface WhenToDream{} + public @interface WhenToDream {} public static final int WHILE_CHARGING = 0; public static final int WHILE_DOCKED = 1; public static final int EITHER = 2; public static final int NEVER = 3; + /** + * The type of dream complications which can be provided by a + * {@link com.android.systemui.dreams.ComplicationProvider}. + */ + @IntDef(prefix = {"COMPLICATION_TYPE_"}, value = { + COMPLICATION_TYPE_TIME, + COMPLICATION_TYPE_DATE, + COMPLICATION_TYPE_WEATHER, + COMPLICATION_TYPE_AIR_QUALITY, + COMPLICATION_TYPE_CAST_INFO + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ComplicationType {} + + public static final int COMPLICATION_TYPE_TIME = 1; + public static final int COMPLICATION_TYPE_DATE = 2; + public static final int COMPLICATION_TYPE_WEATHER = 3; + public static final int COMPLICATION_TYPE_AIR_QUALITY = 4; + public static final int COMPLICATION_TYPE_CAST_INFO = 5; + private final Context mContext; private final IDreamManager mDreamManager; private final DreamInfoComparator mComparator; private final boolean mDreamsEnabledByDefault; private final boolean mDreamsActivatedOnSleepByDefault; private final boolean mDreamsActivatedOnDockByDefault; + private final Set mSupportedComplications; + private final Set mDefaultEnabledComplications; private static DreamBackend sInstance; @@ -103,17 +130,31 @@ public class DreamBackend { public DreamBackend(Context context) { mContext = context.getApplicationContext(); + final Resources resources = mContext.getResources(); + mDreamManager = IDreamManager.Stub.asInterface( ServiceManager.getService(DreamService.DREAM_SERVICE)); mComparator = new DreamInfoComparator(getDefaultDream()); - mDreamsEnabledByDefault = mContext.getResources() - .getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault); - mDreamsActivatedOnSleepByDefault = mContext.getResources() - .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault); - mDreamsActivatedOnDockByDefault = mContext.getResources() - .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); - mDreamPreviewDefault = mContext.getResources().getDrawable( + mDreamsEnabledByDefault = resources.getBoolean( + com.android.internal.R.bool.config_dreamsEnabledByDefault); + mDreamsActivatedOnSleepByDefault = resources.getBoolean( + com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault); + mDreamsActivatedOnDockByDefault = resources.getBoolean( + com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); + mDreamPreviewDefault = resources.getDrawable( com.android.internal.R.drawable.default_dream_preview); + + mSupportedComplications = + Arrays.stream(resources.getIntArray(R.array.config_supportedDreamComplications)) + .boxed() + .collect(Collectors.toSet()); + + mDefaultEnabledComplications = Arrays.stream( + resources.getIntArray(R.array.config_dreamComplicationsEnabledByDefault)) + .boxed() + // A complication can only be enabled by default if it is also supported. + .filter(mSupportedComplications::contains) + .collect(Collectors.toSet()); } public List getDreamInfos() { @@ -242,7 +283,57 @@ public class DreamBackend { default: break; } + } + /** Gets all complications which have been enabled by the user. */ + public Set getEnabledComplications() { + final String enabledComplications = Settings.Secure.getString( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS); + + if (enabledComplications == null) { + return mDefaultEnabledComplications; + } + + return parseFromString(enabledComplications); + } + + /** Gets all dream complications which are supported on this device. **/ + public Set getSupportedComplications() { + return mSupportedComplications; + } + + /** + * Enables or disables a particular dream complication. + * + * @param complicationType The dream complication to be enabled/disabled. + * @param value If true, the complication is enabled. Otherwise it is disabled. + */ + public void setComplicationEnabled(@ComplicationType int complicationType, boolean value) { + if (!mSupportedComplications.contains(complicationType)) return; + + Set enabledComplications = getEnabledComplications(); + if (value) { + enabledComplications.add(complicationType); + } else { + enabledComplications.remove(complicationType); + } + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS, + convertToString(enabledComplications)); + } + + private static String convertToString(Set set) { + return set.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + } + + private static Set parseFromString(String string) { + return Arrays.stream(string.split(",")) + .map(Integer::parseInt) + .collect(Collectors.toSet()); } public boolean isEnabled() { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java new file mode 100644 index 0000000000000..53d465305a69e --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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.settingslib.dream; + + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; + +import com.android.settingslib.R; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSettings; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSettings.ShadowSecure.class}) +public final class DreamBackendTest { + private static final int[] SUPPORTED_DREAM_COMPLICATIONS = {1, 2, 3}; + private static final int[] DEFAULT_DREAM_COMPLICATIONS = {1, 3, 4}; + + @Mock + private Context mContext; + private DreamBackend mBackend; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getApplicationContext()).thenReturn(mContext); + + final Resources res = mock(Resources.class); + when(mContext.getResources()).thenReturn(res); + when(res.getIntArray(R.array.config_supportedDreamComplications)).thenReturn( + SUPPORTED_DREAM_COMPLICATIONS); + when(res.getIntArray(R.array.config_dreamComplicationsEnabledByDefault)).thenReturn( + DEFAULT_DREAM_COMPLICATIONS); + mBackend = new DreamBackend(mContext); + } + + @After + public void tearDown() { + ShadowSettings.ShadowSecure.reset(); + } + + @Test + public void testSupportedComplications() { + assertThat(mBackend.getSupportedComplications()).containsExactly(1, 2, 3); + } + + @Test + public void testGetEnabledDreamComplications_default() { + assertThat(mBackend.getEnabledComplications()).containsExactly(1, 3); + } + + @Test + public void testEnableComplication() { + mBackend.setComplicationEnabled(/* complicationType= */ 2, true); + assertThat(mBackend.getEnabledComplications()).containsExactly(1, 2, 3); + } + + @Test + public void testEnableComplication_notSupported() { + mBackend.setComplicationEnabled(/* complicationType= */ 5, true); + assertThat(mBackend.getEnabledComplications()).containsExactly(1, 3); + } + + @Test + public void testDisableComplication() { + mBackend.setComplicationEnabled(/* complicationType= */ 1, false); + assertThat(mBackend.getEnabledComplications()).containsExactly(3); + } +} +