Loading packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -1273,6 +1273,10 @@ <!-- [CHAR LIMIT=NONE] Importance Tuner setting title --> <string name="tuner_full_importance_settings">Power notification controls</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 +80 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static com.android.systemui.statusbar.policy.RotationLockControllerImpl.hasSufficientPermission; import android.content.Intent; 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 +44,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.SettingObserver; 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 SettingObserver mSetting; @Inject public RotationLockTile( Loading @@ -61,12 +74,41 @@ 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; int currentUser = host.getUserContext().getUserId(); mSetting = new SettingObserver( 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(null); } }; mBatteryController.observe(getLifecycle(), this); } @Override protected void handleInitialize() { mPrivacyManager.addSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener); } @Override public void onPowerSaveChanged(boolean isPowerSave) { refreshState(); } @Override Loading Loading @@ -95,14 +137,46 @@ 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(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.stateDescription = state.secondaryLabel; state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; } @Override protected void handleDestroy() { super.handleDestroy(); mSetting.setListening(false); mPrivacyManager.removeSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener); } @Override public void handleSetListening(boolean listening) { super.handleSetListening(listening); mSetting.setListening(listening); } @Override protected void handleUserSwitch(int newUserId) { mSetting.setUserId(newUserId); handleRefreshState(null); } public static boolean isCurrentOrientationLockPortrait(RotationLockController controller, Resources resources) { int lockOrientation = controller.getRotationLockOrientation(); Loading Loading @@ -140,4 +214,8 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { refreshState(rotationLocked); } }; private final SensorPrivacyManager.OnSensorPrivacyChangedListener mSensorPrivacyChangedListener = (sensor, enabled) -> refreshState(); } 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 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.systemui.statusbar.policy; import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; import androidx.annotation.NonNull; Loading @@ -34,6 +37,7 @@ import javax.inject.Named; /** Platform implementation of the rotation lock controller. **/ @SysUISingleton public final class RotationLockControllerImpl implements RotationLockController { private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = new CopyOnWriteArrayList<>(); Loading Loading @@ -86,6 +90,10 @@ public final class RotationLockControllerImpl implements RotationLockController return mRotationPolicy.isRotationLocked(); } public boolean isCameraRotationEnabled() { return mRotationPolicy.isCameraRotationEnabled(); } public void setRotationLocked(boolean locked) { mRotationPolicy.setRotationLock(locked); } Loading Loading @@ -121,4 +129,11 @@ public final class RotationLockControllerImpl implements RotationLockController callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(), mRotationPolicy.isRotationLockToggleVisible()); } public static 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/util/wrapper/RotationPolicyWrapper.kt +11 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.systemui.util.wrapper import android.content.Context import android.provider.Settings.Secure.CAMERA_AUTOROTATE import com.android.internal.view.RotationPolicy import com.android.internal.view.RotationPolicy.RotationPolicyListener import com.android.systemui.util.settings.SecureSettings import javax.inject.Inject /** Loading @@ -30,11 +32,15 @@ interface RotationPolicyWrapper { fun getRotationLockOrientation(): Int fun isRotationLockToggleVisible(): Boolean fun isRotationLocked(): Boolean fun isCameraRotationEnabled(): Boolean fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int) fun unregisterRotationPolicyListener(listener: RotationPolicyListener) } class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) : class RotationPolicyWrapperImpl @Inject constructor( private val context: Context, private val secureSettings: SecureSettings ) : RotationPolicyWrapper { override fun setRotationLock(enabled: Boolean) { Loading @@ -54,6 +60,9 @@ class RotationPolicyWrapperImpl @Inject constructor(private val context: Context override fun isRotationLocked(): Boolean = RotationPolicy.isRotationLocked(context) override fun isCameraRotationEnabled(): Boolean = secureSettings.getInt(CAMERA_AUTOROTATE, 0) == 1 override fun registerRotationPolicyListener( listener: RotationPolicyListener, userHandle: Int Loading Loading
packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -1273,6 +1273,10 @@ <!-- [CHAR LIMIT=NONE] Importance Tuner setting title --> <string name="tuner_full_importance_settings">Power notification controls</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 +80 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static com.android.systemui.statusbar.policy.RotationLockControllerImpl.hasSufficientPermission; import android.content.Intent; 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 +44,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.SettingObserver; 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 SettingObserver mSetting; @Inject public RotationLockTile( Loading @@ -61,12 +74,41 @@ 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; int currentUser = host.getUserContext().getUserId(); mSetting = new SettingObserver( 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(null); } }; mBatteryController.observe(getLifecycle(), this); } @Override protected void handleInitialize() { mPrivacyManager.addSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener); } @Override public void onPowerSaveChanged(boolean isPowerSave) { refreshState(); } @Override Loading Loading @@ -95,14 +137,46 @@ 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(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.stateDescription = state.secondaryLabel; state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; } @Override protected void handleDestroy() { super.handleDestroy(); mSetting.setListening(false); mPrivacyManager.removeSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener); } @Override public void handleSetListening(boolean listening) { super.handleSetListening(listening); mSetting.setListening(listening); } @Override protected void handleUserSwitch(int newUserId) { mSetting.setUserId(newUserId); handleRefreshState(null); } public static boolean isCurrentOrientationLockPortrait(RotationLockController controller, Resources resources) { int lockOrientation = controller.getRotationLockOrientation(); Loading Loading @@ -140,4 +214,8 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { refreshState(rotationLocked); } }; private final SensorPrivacyManager.OnSensorPrivacyChangedListener mSensorPrivacyChangedListener = (sensor, enabled) -> refreshState(); }
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 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.systemui.statusbar.policy; import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; import androidx.annotation.NonNull; Loading @@ -34,6 +37,7 @@ import javax.inject.Named; /** Platform implementation of the rotation lock controller. **/ @SysUISingleton public final class RotationLockControllerImpl implements RotationLockController { private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = new CopyOnWriteArrayList<>(); Loading Loading @@ -86,6 +90,10 @@ public final class RotationLockControllerImpl implements RotationLockController return mRotationPolicy.isRotationLocked(); } public boolean isCameraRotationEnabled() { return mRotationPolicy.isCameraRotationEnabled(); } public void setRotationLocked(boolean locked) { mRotationPolicy.setRotationLock(locked); } Loading Loading @@ -121,4 +129,11 @@ public final class RotationLockControllerImpl implements RotationLockController callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(), mRotationPolicy.isRotationLockToggleVisible()); } public static 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/util/wrapper/RotationPolicyWrapper.kt +11 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.systemui.util.wrapper import android.content.Context import android.provider.Settings.Secure.CAMERA_AUTOROTATE import com.android.internal.view.RotationPolicy import com.android.internal.view.RotationPolicy.RotationPolicyListener import com.android.systemui.util.settings.SecureSettings import javax.inject.Inject /** Loading @@ -30,11 +32,15 @@ interface RotationPolicyWrapper { fun getRotationLockOrientation(): Int fun isRotationLockToggleVisible(): Boolean fun isRotationLocked(): Boolean fun isCameraRotationEnabled(): Boolean fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int) fun unregisterRotationPolicyListener(listener: RotationPolicyListener) } class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) : class RotationPolicyWrapperImpl @Inject constructor( private val context: Context, private val secureSettings: SecureSettings ) : RotationPolicyWrapper { override fun setRotationLock(enabled: Boolean) { Loading @@ -54,6 +60,9 @@ class RotationPolicyWrapperImpl @Inject constructor(private val context: Context override fun isRotationLocked(): Boolean = RotationPolicy.isRotationLocked(context) override fun isCameraRotationEnabled(): Boolean = secureSettings.getInt(CAMERA_AUTOROTATE, 0) == 1 override fun registerRotationPolicyListener( listener: RotationPolicyListener, userHandle: Int Loading