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);
+ }
+}
+