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
This commit is contained in:
Abel Tesfaye
2021-06-03 23:19:44 +00:00
parent c89b3afef5
commit 5131c691b5
2 changed files with 117 additions and 16 deletions

View File

@@ -16,15 +16,25 @@
package com.android.settings.display; package com.android.settings.display;
import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; 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.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.SensorPrivacyManager;
import android.os.PowerManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.view.RotationPolicy; import com.android.internal.view.RotationPolicy;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
@@ -41,8 +51,21 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
private RotationPolicy.RotationPolicyListener mRotationPolicyListener; private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
private Preference mPreference; 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) { public SmartAutoRotatePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
mPrivacyManager = SensorPrivacyManager.getInstance(context);
mPrivacyManager
.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshSummary(mPreference));
mPowerManager = context.getSystemService(PowerManager.class);
} }
@Override @Override
@@ -59,6 +82,8 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
@Override @Override
public void onStart() { public void onStart() {
mContext.registerReceiver(mReceiver,
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
if (mRotationPolicyListener == null) { if (mRotationPolicyListener == null) {
mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() { mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() {
@Override @Override
@@ -75,12 +100,27 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
@Override @Override
public void onStop() { public void onStop() {
mContext.unregisterReceiver(mReceiver);
if (mRotationPolicyListener != null) { if (mRotationPolicyListener != null) {
RotationPolicy.unregisterRotationPolicyListener(mContext, RotationPolicy.unregisterRotationPolicyListener(mContext,
mRotationPolicyListener); 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 @Override
public CharSequence getSummary() { public CharSequence getSummary() {
int activeStringId = R.string.auto_rotate_option_off; int activeStringId = R.string.auto_rotate_option_off;
@@ -89,7 +129,11 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
mContext.getContentResolver(), mContext.getContentResolver(),
CAMERA_AUTOROTATE, CAMERA_AUTOROTATE,
0, UserHandle.USER_CURRENT); 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; : R.string.auto_rotate_option_on;
} }
return mContext.getString(activeStringId); return mContext.getString(activeStringId);

View File

@@ -20,46 +20,65 @@ import static android.provider.Settings.Secure.CAMERA_AUTOROTATE;
import static com.google.common.truth.Truth.assertThat; 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.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.Manifest;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; 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.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory; 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.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowSensorPrivacyManager.class)
public class SmartAutoRotatePreferenceControllerTest { public class SmartAutoRotatePreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private static final String PACKAGE_NAME = "package_name";
private Context mContext;
@Mock @Mock
private PackageManager mPackageManager; private PackageManager mPackageManager;
@Mock
private Resources mResources;
private Context mContext;
private ContentResolver mContentResolver; private ContentResolver mContentResolver;
private SmartAutoRotatePreferenceController mController; private SmartAutoRotatePreferenceController mController;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = Mockito.spy(RuntimeEnvironment.application);
FakeFeatureFactory.setupForTest(); FakeFeatureFactory.setupForTest();
mContentResolver = RuntimeEnvironment.application.getContentResolver(); mContentResolver = RuntimeEnvironment.application.getContentResolver();
when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getContentResolver()).thenReturn(mContentResolver); 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)) when(mContext.getString(R.string.auto_rotate_option_off))
.thenReturn("Off"); .thenReturn("Off");
when(mContext.getString(R.string.auto_rotate_option_on)) when(mContext.getString(R.string.auto_rotate_option_on))
@@ -68,8 +87,14 @@ public class SmartAutoRotatePreferenceControllerTest {
.thenReturn("On - Face-based"); .thenReturn("On - Face-based");
disableCameraBasedRotation(); 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 @Test
@@ -82,33 +107,37 @@ public class SmartAutoRotatePreferenceControllerTest {
} }
@Test @Test
public void updatePreference_settingsIsOff_shouldTurnOffToggle() { public void getSummary_settingsIsOff_returnsOff() {
disableAutoRotation(); disableAutoRotation();
assertThat(mController.getSummary()).isEqualTo("Off"); assertThat(mController.getSummary()).isEqualTo("Off");
} }
@Test @Test
public void updatePreference_settingsIsOn_shouldTurnOnToggle() { public void getSummary_settingsIsOn_returnsOn() {
enableAutoRotation(); enableAutoRotation();
assertThat(mController.getSummary()).isEqualTo("On"); assertThat(mController.getSummary()).isEqualTo("On");
} }
@Test @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(); enableCameraBasedRotation();
enableAutoRotation(); enableAutoRotation();
assertThat(mController.getSummary()).isEqualTo("On - Face-based"); assertThat(mController.getSummary()).isEqualTo("On - Face-based");
disableAutoRotation();
assertThat(mController.getSummary()).isEqualTo("Off");
} }
@Test @Test
public void updatePreference_settingsIsOff_noSmartAuto_shouldTurnOffToggle() { public void getSummary_noSmartAuto_returnsOff() {
disableAutoRotation(); disableAutoRotation();
Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.putStringForUser(mContentResolver,
CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT); CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT);
@@ -118,7 +147,7 @@ public class SmartAutoRotatePreferenceControllerTest {
} }
@Test @Test
public void updatePreference_settingsIsOn_noSmartAuto_shouldTurnOnToggle() { public void getSummary_noSmartAuto_returnsOn() {
enableAutoRotation(); enableAutoRotation();
Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.putStringForUser(mContentResolver,
CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT); CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT);
@@ -126,6 +155,34 @@ public class SmartAutoRotatePreferenceControllerTest {
assertThat(mController.getSummary()).isEqualTo("On"); 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 @Test
public void testGetAvailabilityStatus() { public void testGetAvailabilityStatus() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(BasePreferenceController assertThat(mController.getAvailabilityStatus()).isEqualTo(BasePreferenceController
@@ -158,14 +215,14 @@ public class SmartAutoRotatePreferenceControllerTest {
private void enableAutoRotationPreference() { private void enableAutoRotationPreference() {
when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true); 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.putInt(mContentResolver,
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0); Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0);
} }
private void disableAutoRotationPreference() { private void disableAutoRotationPreference() {
when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true); 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.putInt(mContentResolver,
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 1); Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 1);
} }