Loading packages/SystemUI/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1779,6 +1779,8 @@ <string name="tuner_full_importance_settings">Power notification controls</string> <string name="tuner_full_importance_settings_on">On</string> <string name="tuner_full_importance_settings_off">Off</string> <!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description --> <string name="rotation_lock_camera_rotation_on">On - Face-based</string> <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n<b>Level 5</b> \n- Show at the top of the notification list Loading packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +68 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,19 @@ package com.android.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.view.View; import android.widget.Switch; Loading @@ -38,18 +45,25 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; import com.android.systemui.util.settings.SecureSettings; import javax.inject.Inject; /** Quick settings tile: Rotation **/ public class RotationLockTile extends QSTileImpl<BooleanState> { public class RotationLockTile extends QSTileImpl<BooleanState> implements BatteryController.BatteryStateChangeCallback { private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate); private final RotationLockController mController; private final SensorPrivacyManager mPrivacyManager; private final BatteryController mBatteryController; private final SecureSetting mSetting; @Inject public RotationLockTile( Loading @@ -61,12 +75,38 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, RotationLockController rotationLockController RotationLockController rotationLockController, SensorPrivacyManager privacyManager, BatteryController batteryController, SecureSettings secureSettings ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = rotationLockController; mController.observe(this, mCallback); mPrivacyManager = privacyManager; mBatteryController = batteryController; mPrivacyManager .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshState()); int currentUser = host.getUserContext().getUserId(); mSetting = new SecureSetting( secureSettings, mHandler, Secure.CAMERA_AUTOROTATE, currentUser ) { @Override protected void handleValueChanged(int value, boolean observedChange) { // mHandler is the background handler so calling this is OK handleRefreshState(value); } }; mBatteryController.observe(getLifecycle(), this); } @Override public void onPowerSaveChanged(boolean isPowerSave) { refreshState(); } @Override Loading Loading @@ -95,14 +135,33 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { final boolean rotationLocked = mController.isRotationLocked(); final boolean powerSave = mBatteryController.isPowerSave(); final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled( SensorPrivacyManager.Sensors.CAMERA); final boolean cameraRotation = !powerSave && !cameraLocked && hasSufficientPermission(mContext) && mController.isCameraRotationEnabled(); state.value = !rotationLocked; state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label); state.icon = mIcon; state.contentDescription = getAccessibilityString(rotationLocked); if (!rotationLocked && cameraRotation) { state.secondaryLabel = mContext.getResources().getString( R.string.rotation_lock_camera_rotation_on); } else { state.secondaryLabel = ""; } state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; } @Override protected void handleUserSwitch(int newUserId) { mSetting.setUserId(newUserId); handleRefreshState(mSetting.getValue()); } public static boolean isCurrentOrientationLockPortrait(RotationLockController controller, Resources resources) { int lockOrientation = controller.getRotationLockOrientation(); Loading Loading @@ -140,4 +199,11 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { refreshState(rotationLocked); } }; private boolean hasSufficientPermission(Context context) { final PackageManager packageManager = context.getPackageManager(); final String rotationPackage = packageManager.getRotationResolverPackageName(); return rotationPackage != null && packageManager.checkPermission( Manifest.permission.CAMERA, rotationPackage) == PackageManager.PERMISSION_GRANTED; } } packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ public interface RotationLockController extends Listenable, int getRotationLockOrientation(); boolean isRotationLockAffordanceVisible(); boolean isRotationLocked(); boolean isCameraRotationEnabled(); void setRotationLocked(boolean locked); void setRotationLockedAtAngle(boolean locked, int rotation); Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java +16 −7 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.os.UserHandle; import android.provider.Settings.Secure; import androidx.annotation.NonNull; import com.android.internal.view.RotationPolicy; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.CopyOnWriteArrayList; Loading @@ -32,6 +34,7 @@ import javax.inject.Inject; @SysUISingleton public final class RotationLockControllerImpl implements RotationLockController { private final Context mContext; private final SecureSettings mSecureSettings; private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = new CopyOnWriteArrayList<RotationLockControllerCallback>(); Loading @@ -44,8 +47,9 @@ public final class RotationLockControllerImpl implements RotationLockController }; @Inject public RotationLockControllerImpl(Context context) { public RotationLockControllerImpl(Context context, SecureSettings secureSettings) { mContext = context; mSecureSettings = secureSettings; setListening(true); } Loading @@ -68,6 +72,11 @@ public final class RotationLockControllerImpl implements RotationLockController return RotationPolicy.isRotationLocked(mContext); } public boolean isCameraRotationEnabled() { return mSecureSettings.getIntForUser(Secure.CAMERA_AUTOROTATE, 0, UserHandle.USER_CURRENT) == 1; } public void setRotationLocked(boolean locked) { RotationPolicy.setRotationLock(mContext, locked); } Loading packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import android.Manifest; import android.content.pm.PackageManager; import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.text.TextUtils; import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.RotationLockControllerImpl; import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class RotationLockTileTest extends SysuiTestCase { private static final String PACKAGE_NAME = "package_name"; @Mock private PackageManager mPackageManager; @Mock private ActivityStarter mActivityStarter; @Mock private QSTileHost mHost; @Mock private MetricsLogger mMetricsLogger; @Mock private StatusBarStateController mStatusBarStateController; @Mock private QSLogger mQSLogger; @Mock private SensorPrivacyManager mPrivacyManager; @Mock private BatteryController mBatteryController; private SecureSettings mSecureSettings; private RotationLockController mController; private TestableLooper mTestableLooper; private RotationLockTile mLockTile; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); when(mHost.getUserContext()).thenReturn(mContext); mSecureSettings = new FakeSettings(); mController = new RotationLockControllerImpl(mContext, mSecureSettings); mLockTile = new RotationLockTile( mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, mQSLogger, mController, mPrivacyManager, mBatteryController, mSecureSettings ); mLockTile.initialize(); // We are not setting the mocks to listening, so we trigger a first refresh state to // set the initial state mLockTile.refreshState(); mTestableLooper.processAllMessages(); mContext.setMockPackageManager(mPackageManager); doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName(); doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( Manifest.permission.CAMERA, PACKAGE_NAME); when(mBatteryController.isPowerSave()).thenReturn(false); when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(false); enableAutoRotation(); enableCameraBasedRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); } @Test public void testSecondaryString_cameraRotateOn_returnsFaceBased() { assertEquals("On - Face-based", mLockTile.getState().secondaryLabel); } @Test public void testSecondaryString_rotateOff_isEmpty() { disableAutoRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_cameraRotateOff_isEmpty() { disableCameraBasedRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_powerSaveEnabled_isEmpty() { when(mBatteryController.isPowerSave()).thenReturn(true); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_cameraDisabled_isEmpty() { when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(true); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_noCameraPermission_isEmpty() { doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( Manifest.permission.CAMERA, PACKAGE_NAME); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } private void enableAutoRotation() { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1, UserHandle.USER_CURRENT); } private void disableAutoRotation() { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT); } private void enableCameraBasedRotation() { mSecureSettings.putIntForUser( CAMERA_AUTOROTATE, 1, UserHandle.USER_CURRENT); } private void disableCameraBasedRotation() { mSecureSettings.putIntForUser( CAMERA_AUTOROTATE, 0, UserHandle.USER_CURRENT); } } Loading
packages/SystemUI/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1779,6 +1779,8 @@ <string name="tuner_full_importance_settings">Power notification controls</string> <string name="tuner_full_importance_settings_on">On</string> <string name="tuner_full_importance_settings_off">Off</string> <!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description --> <string name="rotation_lock_camera_rotation_on">On - Face-based</string> <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n<b>Level 5</b> \n- Show at the top of the notification list Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +68 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,19 @@ package com.android.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.view.View; import android.widget.Switch; Loading @@ -38,18 +45,25 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; import com.android.systemui.util.settings.SecureSettings; import javax.inject.Inject; /** Quick settings tile: Rotation **/ public class RotationLockTile extends QSTileImpl<BooleanState> { public class RotationLockTile extends QSTileImpl<BooleanState> implements BatteryController.BatteryStateChangeCallback { private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate); private final RotationLockController mController; private final SensorPrivacyManager mPrivacyManager; private final BatteryController mBatteryController; private final SecureSetting mSetting; @Inject public RotationLockTile( Loading @@ -61,12 +75,38 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, RotationLockController rotationLockController RotationLockController rotationLockController, SensorPrivacyManager privacyManager, BatteryController batteryController, SecureSettings secureSettings ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = rotationLockController; mController.observe(this, mCallback); mPrivacyManager = privacyManager; mBatteryController = batteryController; mPrivacyManager .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshState()); int currentUser = host.getUserContext().getUserId(); mSetting = new SecureSetting( secureSettings, mHandler, Secure.CAMERA_AUTOROTATE, currentUser ) { @Override protected void handleValueChanged(int value, boolean observedChange) { // mHandler is the background handler so calling this is OK handleRefreshState(value); } }; mBatteryController.observe(getLifecycle(), this); } @Override public void onPowerSaveChanged(boolean isPowerSave) { refreshState(); } @Override Loading Loading @@ -95,14 +135,33 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { final boolean rotationLocked = mController.isRotationLocked(); final boolean powerSave = mBatteryController.isPowerSave(); final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled( SensorPrivacyManager.Sensors.CAMERA); final boolean cameraRotation = !powerSave && !cameraLocked && hasSufficientPermission(mContext) && mController.isCameraRotationEnabled(); state.value = !rotationLocked; state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label); state.icon = mIcon; state.contentDescription = getAccessibilityString(rotationLocked); if (!rotationLocked && cameraRotation) { state.secondaryLabel = mContext.getResources().getString( R.string.rotation_lock_camera_rotation_on); } else { state.secondaryLabel = ""; } state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; } @Override protected void handleUserSwitch(int newUserId) { mSetting.setUserId(newUserId); handleRefreshState(mSetting.getValue()); } public static boolean isCurrentOrientationLockPortrait(RotationLockController controller, Resources resources) { int lockOrientation = controller.getRotationLockOrientation(); Loading Loading @@ -140,4 +199,11 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { refreshState(rotationLocked); } }; private boolean hasSufficientPermission(Context context) { final PackageManager packageManager = context.getPackageManager(); final String rotationPackage = packageManager.getRotationResolverPackageName(); return rotationPackage != null && packageManager.checkPermission( Manifest.permission.CAMERA, rotationPackage) == PackageManager.PERMISSION_GRANTED; } }
packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ public interface RotationLockController extends Listenable, int getRotationLockOrientation(); boolean isRotationLockAffordanceVisible(); boolean isRotationLocked(); boolean isCameraRotationEnabled(); void setRotationLocked(boolean locked); void setRotationLockedAtAngle(boolean locked, int rotation); Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java +16 −7 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.os.UserHandle; import android.provider.Settings.Secure; import androidx.annotation.NonNull; import com.android.internal.view.RotationPolicy; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.CopyOnWriteArrayList; Loading @@ -32,6 +34,7 @@ import javax.inject.Inject; @SysUISingleton public final class RotationLockControllerImpl implements RotationLockController { private final Context mContext; private final SecureSettings mSecureSettings; private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = new CopyOnWriteArrayList<RotationLockControllerCallback>(); Loading @@ -44,8 +47,9 @@ public final class RotationLockControllerImpl implements RotationLockController }; @Inject public RotationLockControllerImpl(Context context) { public RotationLockControllerImpl(Context context, SecureSettings secureSettings) { mContext = context; mSecureSettings = secureSettings; setListening(true); } Loading @@ -68,6 +72,11 @@ public final class RotationLockControllerImpl implements RotationLockController return RotationPolicy.isRotationLocked(mContext); } public boolean isCameraRotationEnabled() { return mSecureSettings.getIntForUser(Secure.CAMERA_AUTOROTATE, 0, UserHandle.USER_CURRENT) == 1; } public void setRotationLocked(boolean locked) { RotationPolicy.setRotationLock(mContext, locked); } Loading
packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static android.provider.Settings.Secure.CAMERA_AUTOROTATE; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import android.Manifest; import android.content.pm.PackageManager; import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.text.TextUtils; import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.RotationLockControllerImpl; import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class RotationLockTileTest extends SysuiTestCase { private static final String PACKAGE_NAME = "package_name"; @Mock private PackageManager mPackageManager; @Mock private ActivityStarter mActivityStarter; @Mock private QSTileHost mHost; @Mock private MetricsLogger mMetricsLogger; @Mock private StatusBarStateController mStatusBarStateController; @Mock private QSLogger mQSLogger; @Mock private SensorPrivacyManager mPrivacyManager; @Mock private BatteryController mBatteryController; private SecureSettings mSecureSettings; private RotationLockController mController; private TestableLooper mTestableLooper; private RotationLockTile mLockTile; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); when(mHost.getUserContext()).thenReturn(mContext); mSecureSettings = new FakeSettings(); mController = new RotationLockControllerImpl(mContext, mSecureSettings); mLockTile = new RotationLockTile( mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, mQSLogger, mController, mPrivacyManager, mBatteryController, mSecureSettings ); mLockTile.initialize(); // We are not setting the mocks to listening, so we trigger a first refresh state to // set the initial state mLockTile.refreshState(); mTestableLooper.processAllMessages(); mContext.setMockPackageManager(mPackageManager); doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName(); doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( Manifest.permission.CAMERA, PACKAGE_NAME); when(mBatteryController.isPowerSave()).thenReturn(false); when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(false); enableAutoRotation(); enableCameraBasedRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); } @Test public void testSecondaryString_cameraRotateOn_returnsFaceBased() { assertEquals("On - Face-based", mLockTile.getState().secondaryLabel); } @Test public void testSecondaryString_rotateOff_isEmpty() { disableAutoRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_cameraRotateOff_isEmpty() { disableCameraBasedRotation(); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_powerSaveEnabled_isEmpty() { when(mBatteryController.isPowerSave()).thenReturn(true); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_cameraDisabled_isEmpty() { when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(true); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } @Test public void testSecondaryString_noCameraPermission_isEmpty() { doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( Manifest.permission.CAMERA, PACKAGE_NAME); mLockTile.refreshState(); mTestableLooper.processAllMessages(); assertTrue(TextUtils.isEmpty(mLockTile.getState().secondaryLabel)); } private void enableAutoRotation() { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1, UserHandle.USER_CURRENT); } private void disableAutoRotation() { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT); } private void enableCameraBasedRotation() { mSecureSettings.putIntForUser( CAMERA_AUTOROTATE, 1, UserHandle.USER_CURRENT); } private void disableCameraBasedRotation() { mSecureSettings.putIntForUser( CAMERA_AUTOROTATE, 0, UserHandle.USER_CURRENT); } }