Loading src/com/android/settings/display/AlwaysOnDisplaySlice.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.settings.display; import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; import android.annotation.ColorInt; import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.hardware.display.AmbientDisplayConfiguration; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; import androidx.slice.Slice; import androidx.slice.builders.ListBuilder; import androidx.slice.builders.SliceAction; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.aware.AwareFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; /** * Custom {@link Slice} for Always on Display. * <p> * We make a custom slice instead of using {@link AmbientDisplayAlwaysOnPreferenceController} * because the controller will be unavailable if devices support aware sensor, and thus * can not convert to slice. * </p> * */ public class AlwaysOnDisplaySlice implements CustomSliceable { private static final int MY_USER = UserHandle.myUserId(); private final Context mContext; private final AmbientDisplayConfiguration mConfig; private final AwareFeatureProvider mFeatureProvider; public AlwaysOnDisplaySlice(Context context) { mContext = context; mConfig = new AmbientDisplayConfiguration(mContext); mFeatureProvider = FeatureFactory.getFactory(context).getAwareFeatureProvider(); } @Override public Slice getSlice() { if (!mConfig.alwaysOnAvailableForUser(MY_USER)) { return null; } final PendingIntent toggleAction = getBroadcastIntent(mContext); @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); final boolean isChecked = mConfig.alwaysOnEnabled(MY_USER); return new ListBuilder(mContext, CustomSliceRegistry.ALWAYS_ON_SLICE_URI, ListBuilder.INFINITY) .setAccentColor(color) .addRow(new ListBuilder.RowBuilder() .setTitle(mContext.getText(R.string.doze_always_on_title)) .setSubtitle(mContext.getText(R.string.doze_always_on_summary)) .setPrimaryAction( SliceAction.createToggle(toggleAction, null /* actionTitle */, isChecked))) .build(); } @Override public Uri getUri() { return CustomSliceRegistry.ALWAYS_ON_SLICE_URI; } @Override public void onNotifyChange(Intent intent) { final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); final ContentResolver resolver = mContext.getContentResolver(); final boolean isAwareSupported = mFeatureProvider.isSupported(mContext); final boolean isAwareEnabled = mFeatureProvider.isEnabled(mContext); Settings.Secure.putInt(resolver, DOZE_ALWAYS_ON, isChecked ? 1 : 0); Settings.Secure.putInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, (isAwareEnabled && isAwareSupported && isChecked) ? 1 : 0); } @Override public Intent getIntent() { return null; } } src/com/android/settings/slices/CustomSliceRegistry.java +12 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; import com.android.settings.display.AdaptiveSleepPreferenceController; import com.android.settings.display.AlwaysOnDisplaySlice; import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; Loading Loading @@ -303,6 +304,16 @@ public class CustomSliceRegistry { .appendPath(MediaOutputSliceConstants.KEY_REMOTE_MEDIA) .build(); /** * Backing Uri for the Always On Slice. */ public static final Uri ALWAYS_ON_SLICE_URI = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("always_on_display") .build(); @VisibleForTesting static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice; Loading @@ -325,6 +336,7 @@ public class CustomSliceRegistry { sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class); sUriToSlice.put(REMOTE_MEDIA_SLICE_URI, RemoteMediaSlice.class); sUriToSlice.put(MEDIA_OUTPUT_GROUP_SLICE_URI, MediaOutputGroupSlice.class); sUriToSlice.put(ALWAYS_ON_SLICE_URI, AlwaysOnDisplaySlice.class); } public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) { Loading tests/robotests/src/com/android/settings/display/AlwaysOnDisplaySliceTest.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.settings.display; import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.hardware.display.AmbientDisplayConfiguration; import android.net.Uri; import android.provider.Settings; import androidx.slice.Slice; import androidx.slice.SliceMetadata; import androidx.slice.SliceProvider; import androidx.slice.widget.SliceLiveData; import com.android.settings.R; import com.android.settings.aware.AwareFeatureProvider; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.testutils.FakeFeatureFactory; 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.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) public class AlwaysOnDisplaySliceTest { private Context mContext; private AlwaysOnDisplaySlice mSlice; private FakeFeatureFactory mFeatureFactory; private AwareFeatureProvider mFeatureProvider; @Mock private AmbientDisplayConfiguration mConfig; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mFeatureFactory = FakeFeatureFactory.setupForTest(); mFeatureProvider = mFeatureFactory.getAwareFeatureProvider(); // Set-up specs for SliceMetadata. SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); mSlice = new AlwaysOnDisplaySlice(mContext); ReflectionHelpers.setField(mSlice, "mConfig", mConfig); } @Test public void getUri_shouldReturnCorrectSliceUri() { final Uri uri = mSlice.getUri(); assertThat(uri).isEqualTo(CustomSliceRegistry.ALWAYS_ON_SLICE_URI); } @Test public void getSlice_alwaysOnNotSupported_returnNull() { when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); final Slice slice = mSlice.getSlice(); assertThat(slice).isNull(); } @Test public void getSlice_alwaysOnSupported_showTitleSubtitle() { when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(true); final Slice slice = mSlice.getSlice(); final SliceMetadata metadata = SliceMetadata.from(mContext, slice); assertThat(metadata.getTitle()).isEqualTo( mContext.getString(R.string.doze_always_on_title)); assertThat(metadata.getSubtitle()).isEqualTo( mContext.getString(R.string.doze_always_on_summary)); } @Test public void onNotifyChange_toggleOff_disableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(0); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareNotSupported_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); when(mFeatureProvider.isSupported(mContext)).thenReturn(false); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareDisabled_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); when(mFeatureProvider.isSupported(mContext)).thenReturn(true); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareSupported_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(true); when(mFeatureProvider.isSupported(mContext)).thenReturn(true); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(1); } } Loading
src/com/android/settings/display/AlwaysOnDisplaySlice.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.settings.display; import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; import android.annotation.ColorInt; import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.hardware.display.AmbientDisplayConfiguration; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; import androidx.slice.Slice; import androidx.slice.builders.ListBuilder; import androidx.slice.builders.SliceAction; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.aware.AwareFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; /** * Custom {@link Slice} for Always on Display. * <p> * We make a custom slice instead of using {@link AmbientDisplayAlwaysOnPreferenceController} * because the controller will be unavailable if devices support aware sensor, and thus * can not convert to slice. * </p> * */ public class AlwaysOnDisplaySlice implements CustomSliceable { private static final int MY_USER = UserHandle.myUserId(); private final Context mContext; private final AmbientDisplayConfiguration mConfig; private final AwareFeatureProvider mFeatureProvider; public AlwaysOnDisplaySlice(Context context) { mContext = context; mConfig = new AmbientDisplayConfiguration(mContext); mFeatureProvider = FeatureFactory.getFactory(context).getAwareFeatureProvider(); } @Override public Slice getSlice() { if (!mConfig.alwaysOnAvailableForUser(MY_USER)) { return null; } final PendingIntent toggleAction = getBroadcastIntent(mContext); @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); final boolean isChecked = mConfig.alwaysOnEnabled(MY_USER); return new ListBuilder(mContext, CustomSliceRegistry.ALWAYS_ON_SLICE_URI, ListBuilder.INFINITY) .setAccentColor(color) .addRow(new ListBuilder.RowBuilder() .setTitle(mContext.getText(R.string.doze_always_on_title)) .setSubtitle(mContext.getText(R.string.doze_always_on_summary)) .setPrimaryAction( SliceAction.createToggle(toggleAction, null /* actionTitle */, isChecked))) .build(); } @Override public Uri getUri() { return CustomSliceRegistry.ALWAYS_ON_SLICE_URI; } @Override public void onNotifyChange(Intent intent) { final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); final ContentResolver resolver = mContext.getContentResolver(); final boolean isAwareSupported = mFeatureProvider.isSupported(mContext); final boolean isAwareEnabled = mFeatureProvider.isEnabled(mContext); Settings.Secure.putInt(resolver, DOZE_ALWAYS_ON, isChecked ? 1 : 0); Settings.Secure.putInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, (isAwareEnabled && isAwareSupported && isChecked) ? 1 : 0); } @Override public Intent getIntent() { return null; } }
src/com/android/settings/slices/CustomSliceRegistry.java +12 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; import com.android.settings.display.AdaptiveSleepPreferenceController; import com.android.settings.display.AlwaysOnDisplaySlice; import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; Loading Loading @@ -303,6 +304,16 @@ public class CustomSliceRegistry { .appendPath(MediaOutputSliceConstants.KEY_REMOTE_MEDIA) .build(); /** * Backing Uri for the Always On Slice. */ public static final Uri ALWAYS_ON_SLICE_URI = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("always_on_display") .build(); @VisibleForTesting static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice; Loading @@ -325,6 +336,7 @@ public class CustomSliceRegistry { sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class); sUriToSlice.put(REMOTE_MEDIA_SLICE_URI, RemoteMediaSlice.class); sUriToSlice.put(MEDIA_OUTPUT_GROUP_SLICE_URI, MediaOutputGroupSlice.class); sUriToSlice.put(ALWAYS_ON_SLICE_URI, AlwaysOnDisplaySlice.class); } public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) { Loading
tests/robotests/src/com/android/settings/display/AlwaysOnDisplaySliceTest.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.settings.display; import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.hardware.display.AmbientDisplayConfiguration; import android.net.Uri; import android.provider.Settings; import androidx.slice.Slice; import androidx.slice.SliceMetadata; import androidx.slice.SliceProvider; import androidx.slice.widget.SliceLiveData; import com.android.settings.R; import com.android.settings.aware.AwareFeatureProvider; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.testutils.FakeFeatureFactory; 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.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) public class AlwaysOnDisplaySliceTest { private Context mContext; private AlwaysOnDisplaySlice mSlice; private FakeFeatureFactory mFeatureFactory; private AwareFeatureProvider mFeatureProvider; @Mock private AmbientDisplayConfiguration mConfig; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mFeatureFactory = FakeFeatureFactory.setupForTest(); mFeatureProvider = mFeatureFactory.getAwareFeatureProvider(); // Set-up specs for SliceMetadata. SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); mSlice = new AlwaysOnDisplaySlice(mContext); ReflectionHelpers.setField(mSlice, "mConfig", mConfig); } @Test public void getUri_shouldReturnCorrectSliceUri() { final Uri uri = mSlice.getUri(); assertThat(uri).isEqualTo(CustomSliceRegistry.ALWAYS_ON_SLICE_URI); } @Test public void getSlice_alwaysOnNotSupported_returnNull() { when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); final Slice slice = mSlice.getSlice(); assertThat(slice).isNull(); } @Test public void getSlice_alwaysOnSupported_showTitleSubtitle() { when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(true); final Slice slice = mSlice.getSlice(); final SliceMetadata metadata = SliceMetadata.from(mContext, slice); assertThat(metadata.getTitle()).isEqualTo( mContext.getString(R.string.doze_always_on_title)); assertThat(metadata.getSubtitle()).isEqualTo( mContext.getString(R.string.doze_always_on_summary)); } @Test public void onNotifyChange_toggleOff_disableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(0); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareNotSupported_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); when(mFeatureProvider.isSupported(mContext)).thenReturn(false); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareDisabled_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); when(mFeatureProvider.isSupported(mContext)).thenReturn(true); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); } @Test public void onNotifyChange_toggleOn_awareSupported_enableAoD() { final Intent intent = new Intent(); intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); when(mFeatureProvider.isEnabled(mContext)).thenReturn(true); when(mFeatureProvider.isSupported(mContext)).thenReturn(true); mSlice.onNotifyChange(intent); final ContentResolver resolver = mContext.getContentResolver(); assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(1); } }