From 5131c691b54f8880cf48bf1ba7c9abfd660f7b11 Mon Sep 17 00:00:00 2001 From: Abel Tesfaye Date: Thu, 3 Jun 2021 23:19:44 +0000 Subject: [PATCH] Check in auto rotate settings summary for rotation resolver service Fixes issue where summary text would not properly describe the state of camera based auto rotation when permission is missing or when another state is blocking the feature Bug: 190095500 Test: locally with flame & make RunSettingsRoboTests -j$(nproc) ROBOTEST_FILTER=SmartAutoRotatePreferenceControllerTest Change-Id: I7609ca87658e08831f3bc37c839f00f63946ddec --- .../SmartAutoRotatePreferenceController.java | 46 +++++++++- ...artAutoRotatePreferenceControllerTest.java | 87 +++++++++++++++---- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/com/android/settings/display/SmartAutoRotatePreferenceController.java b/src/com/android/settings/display/SmartAutoRotatePreferenceController.java index 8c25a05ca31..f8d5f96786e 100644 --- a/src/com/android/settings/display/SmartAutoRotatePreferenceController.java +++ b/src/com/android/settings/display/SmartAutoRotatePreferenceController.java @@ -16,15 +16,25 @@ package com.android.settings.display; +import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; +import static com.android.settings.display.SmartAutoRotateController.hasSufficientPermission; +import static com.android.settings.display.SmartAutoRotateController.isRotationResolverServiceAvailable; + +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.SensorPrivacyManager; +import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.view.RotationPolicy; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -41,8 +51,21 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle private RotationPolicy.RotationPolicyListener mRotationPolicyListener; private Preference mPreference; + private final SensorPrivacyManager mPrivacyManager; + private final PowerManager mPowerManager; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + refreshSummary(mPreference); + } + }; + public SmartAutoRotatePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); + mPrivacyManager = SensorPrivacyManager.getInstance(context); + mPrivacyManager + .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshSummary(mPreference)); + mPowerManager = context.getSystemService(PowerManager.class); } @Override @@ -59,6 +82,8 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle @Override public void onStart() { + mContext.registerReceiver(mReceiver, + new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); if (mRotationPolicyListener == null) { mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() { @Override @@ -75,12 +100,27 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle @Override public void onStop() { + mContext.unregisterReceiver(mReceiver); if (mRotationPolicyListener != null) { RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); } } + /** + * Need this because all controller tests use Roboelectric. No easy way to mock this service, + * so we mock the call we need + */ + @VisibleForTesting + boolean isCameraLocked() { + return mPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA); + } + + @VisibleForTesting + boolean isPowerSaveMode() { + return mPowerManager.isPowerSaveMode(); + } + @Override public CharSequence getSummary() { int activeStringId = R.string.auto_rotate_option_off; @@ -89,7 +129,11 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle mContext.getContentResolver(), CAMERA_AUTOROTATE, 0, UserHandle.USER_CURRENT); - activeStringId = cameraRotate == 1 ? R.string.auto_rotate_option_face_based + activeStringId = cameraRotate == 1 && isRotationResolverServiceAvailable(mContext) + && hasSufficientPermission(mContext) + && !isCameraLocked() + && !isPowerSaveMode() + ? R.string.auto_rotate_option_face_based : R.string.auto_rotate_option_on; } return mContext.getString(activeStringId); diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java index cc3b20da896..068de3472b5 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java @@ -20,46 +20,65 @@ import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; +import android.Manifest; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.os.UserHandle; import android.provider.Settings; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.ResolveInfoBuilder; +import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowSensorPrivacyManager.class) public class SmartAutoRotatePreferenceControllerTest { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; + private static final String PACKAGE_NAME = "package_name"; @Mock private PackageManager mPackageManager; + @Mock + private Resources mResources; + private Context mContext; private ContentResolver mContentResolver; private SmartAutoRotatePreferenceController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mContext = Mockito.spy(RuntimeEnvironment.application); FakeFeatureFactory.setupForTest(); mContentResolver = RuntimeEnvironment.application.getContentResolver(); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getResources()).thenReturn(mResources); when(mContext.getContentResolver()).thenReturn(mContentResolver); + + doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName(); + doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( + Manifest.permission.CAMERA, PACKAGE_NAME); when(mContext.getString(R.string.auto_rotate_option_off)) .thenReturn("Off"); when(mContext.getString(R.string.auto_rotate_option_on)) @@ -68,8 +87,14 @@ public class SmartAutoRotatePreferenceControllerTest { .thenReturn("On - Face-based"); disableCameraBasedRotation(); + final ResolveInfo resolveInfo = new ResolveInfoBuilder(PACKAGE_NAME).build(); + resolveInfo.serviceInfo = new ServiceInfo(); + when(mPackageManager.resolveService(any(), anyInt())).thenReturn(resolveInfo); - mController = new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate"); + mController = Mockito.spy( + new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate")); + when(mController.isCameraLocked()).thenReturn(false); + when(mController.isPowerSaveMode()).thenReturn(false); } @Test @@ -82,33 +107,37 @@ public class SmartAutoRotatePreferenceControllerTest { } @Test - public void updatePreference_settingsIsOff_shouldTurnOffToggle() { + public void getSummary_settingsIsOff_returnsOff() { disableAutoRotation(); assertThat(mController.getSummary()).isEqualTo("Off"); } @Test - public void updatePreference_settingsIsOn_shouldTurnOnToggle() { + public void getSummary_settingsIsOn_returnsOn() { enableAutoRotation(); assertThat(mController.getSummary()).isEqualTo("On"); } @Test - public void updatePreference_settingsIsCameraBased_shouldTurnOnToggle() { + public void getSummary_autoRotateOffSmartAutoRotateOn_returnsOff() { + enableCameraBasedRotation(); + disableAutoRotation(); + + assertThat(mController.getSummary()).isEqualTo("Off"); + } + + @Test + public void updatePreference_smartAutoRotateOn_returnsFaceBased() { enableCameraBasedRotation(); enableAutoRotation(); assertThat(mController.getSummary()).isEqualTo("On - Face-based"); - - disableAutoRotation(); - - assertThat(mController.getSummary()).isEqualTo("Off"); } @Test - public void updatePreference_settingsIsOff_noSmartAuto_shouldTurnOffToggle() { + public void getSummary_noSmartAuto_returnsOff() { disableAutoRotation(); Settings.Secure.putStringForUser(mContentResolver, CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT); @@ -118,7 +147,7 @@ public class SmartAutoRotatePreferenceControllerTest { } @Test - public void updatePreference_settingsIsOn_noSmartAuto_shouldTurnOnToggle() { + public void getSummary_noSmartAuto_returnsOn() { enableAutoRotation(); Settings.Secure.putStringForUser(mContentResolver, CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT); @@ -126,6 +155,34 @@ public class SmartAutoRotatePreferenceControllerTest { assertThat(mController.getSummary()).isEqualTo("On"); } + @Test + public void getSummary_noCameraPermission_returnsOn() { + enableAutoRotation(); + enableCameraBasedRotation(); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + Manifest.permission.CAMERA, PACKAGE_NAME); + + assertThat(mController.getSummary()).isEqualTo("On"); + } + + @Test + public void getSummary_cameraDisabled_returnsOn() { + enableAutoRotation(); + enableCameraBasedRotation(); + when(mController.isCameraLocked()).thenReturn(true); + + assertThat(mController.getSummary()).isEqualTo("On"); + } + + @Test + public void getSummary_powerSaveEnabled_returnsOn() { + enableAutoRotation(); + enableCameraBasedRotation(); + when(mController.isPowerSaveMode()).thenReturn(true); + + assertThat(mController.getSummary()).isEqualTo("On"); + } + @Test public void testGetAvailabilityStatus() { assertThat(mController.getAvailabilityStatus()).isEqualTo(BasePreferenceController @@ -158,14 +215,14 @@ public class SmartAutoRotatePreferenceControllerTest { private void enableAutoRotationPreference() { when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true); - when(mContext.getResources().getBoolean(anyInt())).thenReturn(true); + when(mResources.getBoolean(anyInt())).thenReturn(true); Settings.System.putInt(mContentResolver, Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0); } private void disableAutoRotationPreference() { when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true); - when(mContext.getResources().getBoolean(anyInt())).thenReturn(true); + when(mResources.getBoolean(anyInt())).thenReturn(true); Settings.System.putInt(mContentResolver, Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 1); }