diff --git a/AndroidManifest.xml b/AndroidManifest.xml index de4ae39e84d..87859abf552 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -104,7 +104,9 @@ - + + + Bluetooth will turn on + + + Unavailable because bedtime mode is on diff --git a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java index 6dee5d2675c..7749c8f19ab 100644 --- a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java +++ b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java @@ -16,12 +16,17 @@ package com.android.settings.display; import android.content.Context; +import android.content.pm.PackageManager; import android.hardware.display.AmbientDisplayConfiguration; +import android.os.PowerManager; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; +import androidx.preference.Preference; + +import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreferenceController { @@ -31,13 +36,9 @@ public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreference private static final int MY_USER = UserHandle.myUserId(); private static final String PROP_AWARE_AVAILABLE = "ro.vendor.aware_available"; + private static final String AOD_SUPPRESSED_TOKEN = "winddown"; private AmbientDisplayConfiguration mConfig; - private OnPreferenceChangedCallback mCallback; - - public interface OnPreferenceChangedCallback { - void onPreferenceChanged(); - } public AmbientDisplayAlwaysOnPreferenceController(Context context, String key) { super(context, key); @@ -50,6 +51,12 @@ public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreference AVAILABLE : UNSUPPORTED_ON_DEVICE; } + @Override + public void updateState(Preference preference) { + super.updateState(preference); + refreshSummary(preference); + } + @Override public boolean isSliceable() { return TextUtils.equals(getPreferenceKey(), "ambient_display_always_on"); @@ -70,24 +77,22 @@ public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreference int enabled = isChecked ? ON : OFF; Settings.Secure.putInt( mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, enabled); - if (mCallback != null) { - mCallback.onPreferenceChanged(); - } return true; } + @Override + public CharSequence getSummary() { + return mContext.getText( + isAodSuppressedByBedtime(mContext) ? R.string.aware_summary_when_bedtime_on + : R.string.doze_always_on_summary); + } + public AmbientDisplayAlwaysOnPreferenceController setConfig( AmbientDisplayConfiguration config) { mConfig = config; return this; } - public AmbientDisplayAlwaysOnPreferenceController setCallback( - OnPreferenceChangedCallback callback) { - mCallback = callback; - return this; - } - public static boolean isAvailable(AmbientDisplayConfiguration config) { return config.alwaysOnAvailableForUser(MY_USER); } @@ -98,4 +103,25 @@ public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreference } return mConfig; } + + /** + * Returns whether AOD is suppressed by Bedtime mode, a feature of Digital Wellbeing. + * + * We know that Bedtime mode suppresses AOD using {@link AOD_SUPPRESSED_TOKEN}. If the Digital + * Wellbeing app is suppressing AOD with {@link AOD_SUPPRESSED_TOKEN}, then we can infer that + * AOD is being suppressed by Bedtime mode. + */ + public static boolean isAodSuppressedByBedtime(Context context) { + int uid; + final PowerManager powerManager = context.getSystemService(PowerManager.class); + final PackageManager packageManager = context.getPackageManager(); + final String packageName = context.getString( + com.android.internal.R.string.config_defaultWellbeingPackage); + try { + uid = packageManager.getApplicationInfo(packageName, /* flags= */ 0).uid; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + return powerManager.isAmbientDisplaySuppressedForTokenByApp(AOD_SUPPRESSED_TOKEN, uid); + } } diff --git a/src/com/android/settings/security/LockscreenDashboardFragment.java b/src/com/android/settings/security/LockscreenDashboardFragment.java index 33529916379..39355f381a9 100644 --- a/src/com/android/settings/security/LockscreenDashboardFragment.java +++ b/src/com/android/settings/security/LockscreenDashboardFragment.java @@ -88,9 +88,7 @@ public class LockscreenDashboardFragment extends DashboardFragment @Override public void onAttach(Context context) { super.onAttach(context); - use(AmbientDisplayAlwaysOnPreferenceController.class) - .setConfig(getConfig(context)) - .setCallback(this::updatePreferenceStates); + use(AmbientDisplayAlwaysOnPreferenceController.class).setConfig(getConfig(context)); use(AmbientDisplayNotificationsPreferenceController.class).setConfig(getConfig(context)); use(DoubleTapScreenPreferenceController.class).setConfig(getConfig(context)); use(PickupGesturePreferenceController.class).setConfig(getConfig(context)); diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java index 1548b422cd8..405ea12abb3 100644 --- a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java @@ -19,13 +19,20 @@ package com.android.settings.display; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.hardware.display.AmbientDisplayConfiguration; +import android.os.PowerManager; import android.provider.Settings; +import com.android.internal.R; import com.android.settings.testutils.shadow.ShadowSecureSettings; import org.junit.Before; @@ -41,24 +48,41 @@ import org.robolectric.annotation.Config; @Config(shadows = ShadowSecureSettings.class) public class AmbientDisplayAlwaysOnPreferenceControllerTest { + private static final String TEST_PACKAGE = "com.android.test"; + @Mock private AmbientDisplayConfiguration mConfig; + @Mock + private PackageManager mPackageManager; + @Mock + private PowerManager mPowerManager; + @Mock + private ApplicationInfo mApplicationInfo; private Context mContext; private ContentResolver mContentResolver; private AmbientDisplayAlwaysOnPreferenceController mController; - private boolean mCallbackInvoked; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mContentResolver = mContext.getContentResolver(); mController = new AmbientDisplayAlwaysOnPreferenceController(mContext, "key"); mController.setConfig(mConfig); - mController.setCallback(() -> mCallbackInvoked = true); + + mApplicationInfo.uid = 1; + when(mContext.getString(R.string.config_defaultWellbeingPackage)).thenReturn(TEST_PACKAGE); + + when(mContext.getPackageManager()).thenReturn(mPackageManager); + doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo( + TEST_PACKAGE, /* flag= */0); + + doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); + when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt())) + .thenReturn(false); } @Test @@ -107,13 +131,6 @@ public class AmbientDisplayAlwaysOnPreferenceControllerTest { .isEqualTo(0); } - @Test - public void onPreferenceChange_callback() { - assertThat(mCallbackInvoked).isFalse(); - mController.setChecked(true); - assertThat(mCallbackInvoked).isTrue(); - } - @Test public void isSliceableCorrectKey_returnsTrue() { final AmbientDisplayAlwaysOnPreferenceController controller = @@ -133,4 +150,39 @@ public class AmbientDisplayAlwaysOnPreferenceControllerTest { public void isPublicSlice_returnTrue() { assertThat(mController.isPublicSlice()).isTrue(); } + + @Test + public void isAodSuppressedByBedtime_bedTimeModeOn_returnTrue() { + when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt())) + .thenReturn(true); + + assertThat(AmbientDisplayAlwaysOnPreferenceController + .isAodSuppressedByBedtime(mContext)).isTrue(); + } + + @Test + public void isAodSuppressedByBedtime_bedTimeModeOff_returnFalse() { + assertThat(AmbientDisplayAlwaysOnPreferenceController + .isAodSuppressedByBedtime(mContext)).isFalse(); + } + + @Test + public void isAodSuppressedByBedtime_notFoundWellbeingPackage_returnFalse() + throws PackageManager.NameNotFoundException { + when(mPackageManager.getApplicationInfo(TEST_PACKAGE, /* flag= */0)).thenThrow( + new PackageManager.NameNotFoundException()); + + assertThat(AmbientDisplayAlwaysOnPreferenceController + .isAodSuppressedByBedtime(mContext)).isFalse(); + } + + @Test + public void getSummary_bedTimeModeOn_shouldReturnUnavailableSummary() { + when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt())) + .thenReturn(true); + + final CharSequence summary = mController.getSummary(); + assertThat(summary).isEqualTo(mContext.getString( + com.android.settings.R.string.aware_summary_when_bedtime_on)); + } } diff --git a/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java index 8b5c5fea313..4146a4b07b4 100644 --- a/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java @@ -88,7 +88,6 @@ public class LockscreenDashboardFragmentTest { mTestFragment.onAttach(mContext); verify(controller).setConfig(any()); - verify(controller).setCallback(any()); } @Test