Loading core/java/com/android/internal/view/RotationPolicy.java +10 −2 Original line number Diff line number Diff line Loading @@ -172,11 +172,19 @@ public final class RotationPolicy { setRotationLock(enabled, NATURAL_ROTATION, caller); } private static boolean areAllRotationsAllowed(Context context) { /** * If true, the screen can be rotated via the accelerometer in all 4 rotations as the default * behavior. */ public static boolean areAllRotationsAllowed(Context context) { return context.getResources().getBoolean(R.bool.config_allowAllRotations); } private static boolean useCurrentRotationOnRotationLockChange(Context context) { /** * If false and config_allowAllRotations is false, the screen will rotate to the natural * orientation of the device when the auto-rotate policy is toggled. */ public static boolean useCurrentRotationOnRotationLockChange(Context context) { return context.getResources().getBoolean( R.bool.config_useCurrentRotationOnRotationLockChange); } Loading packages/SettingsLib/DeviceStateRotationLock/src/com/android/settingslib/devicestate/DeviceStateAutoRotateSettingManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ public interface DeviceStateAutoRotateSettingManager extends Dumpable { void unregisterListener(@NonNull DeviceStateAutoRotateSettingListener settingListener); /** * Write {@code deviceState}'s setting value as {@code autoRotate}, for * Write {@code deviceState}'s setting value as {@code rotationLock}, for * {@link DEVICE_STATE_ROTATION_LOCK} setting. */ void updateSetting(int deviceState, boolean autoRotate); void updateSetting(int deviceState, boolean rotationLock); /** * Get {@link DEVICE_STATE_ROTATION_LOCK} setting value for {@code deviceState}. Returns null if Loading packages/SettingsLib/DeviceStateRotationLock/src/com/android/settingslib/devicestate/DeviceStateAutoRotateSettingManagerImpl.java +3 −3 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.view.RotationPolicy; import com.android.window.flags.Flags; import java.io.PrintWriter; Loading Loading @@ -172,9 +173,8 @@ public class DeviceStateAutoRotateSettingManagerImpl implements } @Override public void updateSetting(int deviceState, boolean autoRotate) { // TODO: b/350946537 - Create IPC to update the setting, and call it here. throw new UnsupportedOperationException("API updateSetting is not implemented yet"); public void updateSetting(int deviceState, boolean rotationLock) { RotationPolicy.requestDeviceStateAutoRotateSettingChange(deviceState, !rotationLock); } @Override Loading services/core/java/com/android/server/wm/DeviceStateAutoRotateSettingController.java +115 −49 Original line number Diff line number Diff line Loading @@ -22,6 +22,12 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCK import static android.provider.Settings.System.ACCELEROMETER_ROTATION; import static android.provider.Settings.System.getUriFor; import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION; import static com.android.internal.view.RotationPolicy.areAllRotationsAllowed; import static com.android.internal.view.RotationPolicy.useCurrentRotationOnRotationLockChange; import static com.android.server.wm.DisplayRotation.NO_UPDATE_USER_ROTATION; import static com.android.server.wm.DisplayRotation.USE_CURRENT_ROTATION; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; Loading @@ -30,7 +36,6 @@ import android.database.ContentObserver; import android.hardware.devicestate.DeviceState; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.provider.Settings; Loading @@ -38,6 +43,8 @@ import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.PersistedSettingUpdate; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.UpdateAccelerometerRotationSetting; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.UpdateDeviceState; Loading Loading @@ -83,18 +90,22 @@ public class DeviceStateAutoRotateSettingController { private final ContentResolver mContentResolver; private final DeviceStateController mDeviceStateController; private final List<Event> mPendingEvents = new ArrayList<>(); private final WindowManagerService mWm; private final Context mContext; private int mDeviceState = INVALID_DEVICE_STATE; private boolean mAccelerometerSetting; private SparseIntArray mDeviceStateAutoRotateSetting; public DeviceStateAutoRotateSettingController( Context context, Looper looper, Handler handler, DeviceStateController deviceStateController, DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager) { DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager, WindowManagerService wmService) { mDeviceStateAutoRotateSettingManager = deviceStateAutoRotateSettingManager; mHandler = handler; mContentResolver = context.getContentResolver(); mWm = wmService; mContext = mWm.mContext; mHandler = getHandler(); mContentResolver = mContext.getContentResolver(); mDeviceStateController = deviceStateController; mDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); if (mDeviceStateAutoRotateSetting == null) { Loading @@ -102,7 +113,7 @@ public class DeviceStateAutoRotateSettingController { mDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); } mAccelerometerSetting = getAccelerometerRotationSetting(); mEventHandler = new Handler(looper) { mEventHandler = new Handler(mHandler.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { final Event event = (Event) msg.obj; Loading Loading @@ -133,11 +144,16 @@ public class DeviceStateAutoRotateSettingController { } private void handleEvent(@NonNull Event event) { final boolean inMemoryStateUpdated = updateInMemoryState(event); final boolean persistedAccelerometerRotationSetting = getAccelerometerRotationSetting(); final SparseIntArray persistedDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); if (inMemoryStateUpdated) { writeInMemoryStateIntoPersistedSetting(); } updateInMemoryState(event, persistedAccelerometerRotationSetting, persistedDeviceStateAutoRotateSetting); writeInMemoryStateIntoPersistedSetting(persistedAccelerometerRotationSetting, persistedDeviceStateAutoRotateSetting); writeUserRotationSettingIfNeeded(event, persistedAccelerometerRotationSetting); } /** Request to change {@link DEVICE_STATE_ROTATION_LOCK} persisted setting. */ Loading @@ -145,9 +161,12 @@ public class DeviceStateAutoRotateSettingController { postUpdate(new UpdateDeviceStateAutoRotateSetting(deviceState, autoRotate)); } /** Request to change {@link ACCELEROMETER_ROTATION} persisted setting. */ public void requestAccelerometerRotationSettingChange(boolean autoRotate) { postUpdate(new UpdateAccelerometerRotationSetting(autoRotate)); /** * Request to change {@link ACCELEROMETER_ROTATION} persisted setting. If needed, we might also * write into {@link USER_ROTATION} with {@param userRotation}. */ public void requestAccelerometerRotationSettingChange(boolean autoRotate, int userRotation) { postUpdate(new UpdateAccelerometerRotationSetting(autoRotate, userRotation)); } private void registerDeviceStateAutoRotateSettingObserver() { Loading Loading @@ -179,28 +198,27 @@ public class DeviceStateAutoRotateSettingController { Message.obtain(mEventHandler, MSG_UPDATE_STATE, event).sendToTarget(); } private boolean updateInMemoryState(Event event) { private void updateInMemoryState(Event event, boolean persistedAccelerometerRotationSetting, SparseIntArray persistedDeviceStateAutoRotateSetting) { // Compare persisted setting value with in-memory state before making any changes to // in-memory state. This is to detect if persisted setting was changed directly, which is // not expected. final boolean newAccelerometerRotationSetting = getAccelerometerRotationSetting(); SparseIntArray newDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); // Map would be null if string value of DEVICE_STATE_ROTATION_LOCK is corrupted. final boolean isDeviceStateAutoRotateSettingCorrupted = newDeviceStateAutoRotateSetting == null; persistedDeviceStateAutoRotateSetting == null; if (isDeviceStateAutoRotateSettingCorrupted) { // If string value of DEVICE_STATE_ROTATION_LOCK is corrupted, rewrite it with default // value while also respecting current ACCELEROMETER_ROTATION setting value. newDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); newDeviceStateAutoRotateSetting.put(mDeviceState, persistedDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); persistedDeviceStateAutoRotateSetting.put(mDeviceState, mAccelerometerSetting ? DEVICE_STATE_ROTATION_LOCK_UNLOCKED : DEVICE_STATE_ROTATION_LOCK_LOCKED); } final boolean wasAccelerometerRotationSettingChanged = (newAccelerometerRotationSetting != mAccelerometerSetting); (persistedAccelerometerRotationSetting != mAccelerometerSetting); final boolean wasDevicesStateAutoRotateSettingChanged = !equals( mDeviceStateAutoRotateSetting, newDeviceStateAutoRotateSetting); mDeviceStateAutoRotateSetting, persistedDeviceStateAutoRotateSetting); if (wasAccelerometerRotationSettingChanged || wasDevicesStateAutoRotateSettingChanged) { // System apps should only request changes via DeviceStateAutoRotateSettingManager's Loading @@ -209,14 +227,15 @@ public class DeviceStateAutoRotateSettingController { if (wasAccelerometerRotationSettingChanged) { errorMessage.append("ACCELEROMETER_ROTATION setting changed from ").append( mAccelerometerSetting).append(" to ").append( newAccelerometerRotationSetting).append(" via Settings API.\n"); persistedAccelerometerRotationSetting).append(" via Settings API.\n"); } if (wasDevicesStateAutoRotateSettingChanged) { errorMessage.append( "DEVICE_STATE_ROTATION_LOCK setting directly changed from ").append( mDeviceStateAutoRotateSetting).append(" to ").append( newDeviceStateAutoRotateSetting).append("\nExpectation is for system-apps " + "to only use defined apis to change auto-rotate persisted settings.\n"); persistedDeviceStateAutoRotateSetting).append( "\nExpectation is for system-apps to only use defined apis to change " + "auto-rotate persisted settings.\n"); } Slog.e(TAG, errorMessage + "Using Settings API to write auto-rotate persisted setting, could result " Loading @@ -235,24 +254,18 @@ public class DeviceStateAutoRotateSettingController { // prioritize ACCELEROMETER_ROTATION because it has a direct impact on the user visible // behavior. if (wasDevicesStateAutoRotateSettingChanged) { // Clone the newDeviceStateAutoRotateSetting to avoid modifying it when updating // Clone the persistedDeviceStateAutoRotateSetting to avoid modifying it when updating // mDeviceStateAutoRotateSetting in future mDeviceStateAutoRotateSetting = newDeviceStateAutoRotateSetting.clone(); mDeviceStateAutoRotateSetting = persistedDeviceStateAutoRotateSetting.clone(); mAccelerometerSetting = mDeviceStateAutoRotateSetting.get(mDeviceState) == DEVICE_STATE_ROTATION_LOCK_UNLOCKED; } if (wasAccelerometerRotationSettingChanged) { mAccelerometerSetting = newAccelerometerRotationSetting; mAccelerometerSetting = persistedAccelerometerRotationSetting; mDeviceStateAutoRotateSetting.put(mDeviceState, mAccelerometerSetting ? DEVICE_STATE_ROTATION_LOCK_UNLOCKED : DEVICE_STATE_ROTATION_LOCK_LOCKED); } // Return true if the in-memory state was updated and write needs to be made in persisted // settings. return (mAccelerometerSetting != newAccelerometerRotationSetting || !equals(mDeviceStateAutoRotateSetting, newDeviceStateAutoRotateSetting) || isDeviceStateAutoRotateSettingCorrupted); } private void updateInMemoryStateFromEvent(Event event) { Loading Loading @@ -282,6 +295,64 @@ public class DeviceStateAutoRotateSettingController { } } private void writeInMemoryStateIntoPersistedSetting( boolean persistedAccelerometerRotationSetting, SparseIntArray persistedDeviceStateAutoRotateSetting) { if (mAccelerometerSetting != persistedAccelerometerRotationSetting) { Settings.System.putIntForUser(mContentResolver, ACCELEROMETER_ROTATION, mAccelerometerSetting ? ACCELEROMETER_ROTATION_ON : ACCELEROMETER_ROTATION_OFF, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "ACCELEROMETER_ROTATION=" + mAccelerometerSetting); } } if (!equals(mDeviceStateAutoRotateSetting, persistedDeviceStateAutoRotateSetting)) { final String serializedDeviceStateAutoRotateSetting = convertIntArrayToSerializedSetting(mDeviceStateAutoRotateSetting); Settings.Secure.putStringForUser(mContentResolver, DEVICE_STATE_ROTATION_LOCK, serializedDeviceStateAutoRotateSetting, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "DEVICE_STATE_ROTATION_LOCK=" + serializedDeviceStateAutoRotateSetting); } } } private void writeUserRotationSettingIfNeeded(Event event, boolean persistedAccelerometerRotationSetting) { if (!(event instanceof UpdateAccelerometerRotationSetting) && (mAccelerometerSetting == persistedAccelerometerRotationSetting)) { return; } final int userRotation; if (event instanceof UpdateAccelerometerRotationSetting) { // If the event is `UpdateAccelerometerRotationSetting`, it means that the // userRotation was provided, so we should set it. userRotation = ((UpdateAccelerometerRotationSetting) event).mUserRotation; } else { // If the event is not `UpdateAccelerometerRotationSetting`, it means that the // userRotation was not explicitly provided. if (mAccelerometerSetting) { userRotation = NO_UPDATE_USER_ROTATION; } else { userRotation = areAllRotationsAllowed(mContext) || useCurrentRotationOnRotationLockChange(mContext) ? USE_CURRENT_ROTATION : NATURAL_ROTATION; } } synchronized (mWm.mRoot.mService.mGlobalLock) { mWm.mRoot.getDefaultDisplay().getDisplayRotation().setUserRotationSetting( mAccelerometerSetting ? WindowManagerPolicy.USER_ROTATION_FREE : WindowManagerPolicy.USER_ROTATION_LOCKED, userRotation, "DSAutoRotateCtrl"); } } private boolean getAccelerometerRotationSetting() { return Settings.System.getIntForUser(mContentResolver, ACCELEROMETER_ROTATION, /* def= */ -1, UserHandle.USER_CURRENT) == ACCELEROMETER_ROTATION_ON; Loading @@ -297,20 +368,9 @@ public class DeviceStateAutoRotateSettingController { return mDeviceStateAutoRotateSettingManager.getDefaultRotationLockSetting(); } private void writeInMemoryStateIntoPersistedSetting() { Settings.System.putIntForUser(mContentResolver, ACCELEROMETER_ROTATION, mAccelerometerSetting ? ACCELEROMETER_ROTATION_ON : ACCELEROMETER_ROTATION_OFF, UserHandle.USER_CURRENT); final String serializedDeviceStateAutoRotateSetting = convertIntArrayToSerializedSetting(mDeviceStateAutoRotateSetting); Settings.Secure.putStringForUser(mContentResolver, DEVICE_STATE_ROTATION_LOCK, serializedDeviceStateAutoRotateSetting, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "ACCELEROMETER_ROTATION=" + mAccelerometerSetting + "\nDEVICE_STATE_ROTATION_LOCK=" + serializedDeviceStateAutoRotateSetting); } @VisibleForTesting Handler getHandler() { return mWm.mH; } private static String convertIntArrayToSerializedSetting( Loading Loading @@ -339,15 +399,21 @@ public class DeviceStateAutoRotateSettingController { /** * Event sent when there is a request to update the current auto-rotate setting. * This occurs when actions like `freezeRotation` or `thawRotation` are triggered. * It also contains the user rotation that should be set, if userRotation is -1 then * {@link Settings.System#USER_ROTATION} setting will not be updated. */ static final class UpdateAccelerometerRotationSetting extends Event { final boolean mAutoRotate; final int mUserRotation; /** * @param autoRotate The desired auto-rotate state to write into ACCELEROMETER_ROTATION. * @param autoRotate The desired auto-rotate state to write into * ACCELEROMETER_ROTATION. * @param userRotation The desired user rotation to write into USER_ROTATION. */ UpdateAccelerometerRotationSetting(boolean autoRotate) { UpdateAccelerometerRotationSetting(boolean autoRotate, int userRotation) { mAutoRotate = autoRotate; mUserRotation = userRotation; } } Loading services/core/java/com/android/server/wm/DisplayRotation.java +58 −14 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ import java.util.Set; * Non-public methods are assumed to run inside WM lock. */ public class DisplayRotation { public static final int USE_CURRENT_ROTATION = -1; public static final int NO_UPDATE_USER_ROTATION = -2; private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; // Delay in milliseconds when updating config due to folding events. This prevents Loading Loading @@ -752,20 +754,29 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation, String caller) { mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; if (useDefaultSettingsProvider()) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); final int accelerometerRotation = userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1; if (mService.mRoot.mDeviceStateAutoRotateSettingController != null) { // This call will trigger a setting update asynchronously. DisplayRotation will be // notified of this update via the registered settings listener. That means, // subsequent calls may not be able to read the updated value upon querying // ACCELEROMETER_ROTATION. In future, while processing this request, // setUserRotationSetting may be called. mService.mRoot.mDeviceStateAutoRotateSettingController .requestAccelerometerRotationSettingChange(accelerometerRotation == 1, userRotation); } else { Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION, accelerometerRotation, UserHandle.USER_CURRENT); Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation, UserHandle.USER_CURRENT); setUserRotationSetting(userRotationMode, userRotation, caller); } return; } mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; boolean changed = false; if (mUserRotationMode != userRotationMode) { mUserRotationMode = userRotationMode; Loading @@ -790,8 +801,41 @@ public class DisplayRotation { } } /** * Sets the user rotation and updates the {@link RotationLockHistory}. * * @param userRotationMode The user rotation mode (e.g., * {@link WindowManagerPolicy#USER_ROTATION_FREE}, * {@link WindowManagerPolicy#USER_ROTATION_LOCKED}). * @param userRotation The desired user rotation (e.g., {@link Surface#ROTATION_0}, * {@link Surface#ROTATION_90}, etc.). If this value is set to * {@link USE_CURRENT_ROTATION}, the * {@link Settings.System#USER_ROTATION} setting will be set to * {@link #mRotation}. If this value is set to * {@link NO_UPDATE_USER_ROTATION}, the * {@link Settings.System#USER_ROTATION} setting will be set to * {@link #mUserRotation}. * @param caller The caller of this method, used for logging in * {@link RotationLockHistory}. */ void setUserRotationSetting(int userRotationMode, int userRotation, String caller) { if (userRotation == USE_CURRENT_ROTATION) { userRotation = mRotation; } else if (userRotation == NO_UPDATE_USER_ROTATION) { userRotation = mUserRotation; } Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.USER_ROTATION, userRotation, UserHandle.USER_CURRENT); mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; } void requestDeviceStateAutoRotateSettingChange(int deviceState, boolean autoRotate) { // TODO(b/350946537) Redirect request to DeviceStateAutoRotateSettingController if (mService.mRoot.mDeviceStateAutoRotateSettingController != null) { mService.mRoot.mDeviceStateAutoRotateSettingController .requestDeviceStateAutoRotateSettingChange(deviceState, autoRotate); } } void freezeRotation(int rotation, String caller) { Loading @@ -799,7 +843,7 @@ public class DisplayRotation { rotation = RotationUtils.reverseRotationDirectionAroundZAxis(rotation); } rotation = (rotation == -1) ? mRotation : rotation; rotation = (rotation == USE_CURRENT_ROTATION) ? mRotation : rotation; setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation, caller); } Loading Loading @@ -1661,7 +1705,8 @@ public class DisplayRotation { */ @Nullable static DeviceStateAutoRotateSettingController createDeviceStateAutoRotateDependencies( Context context, DeviceStateController deviceStateController, Handler handler) { Context context, DeviceStateController deviceStateController, WindowManagerService wmService) { if (!isFoldable(context) || !isAutoRotateSupported(context)) return null; if (!Flags.enableDeviceStateAutoRotateSettingLogging() && !Flags.enableDeviceStateAutoRotateSettingRefactor()) { Loading @@ -1675,17 +1720,16 @@ public class DisplayRotation { if (Flags.enableDeviceStateAutoRotateSettingLogging()) { new DeviceStateAutoRotateSettingIssueLogger(SystemClock::elapsedRealtime, secureSettings, deviceStateController, handler); secureSettings, deviceStateController, wmService.mH); } if (Flags.enableDeviceStateAutoRotateSettingRefactor()) { final DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager = new DeviceStateAutoRotateSettingManagerImpl( context, BackgroundThread.getExecutor(), secureSettings, handler, context, BackgroundThread.getExecutor(), secureSettings, wmService.mH, new PostureDeviceStateConverter(context, new DeviceStateManager())); deviceStateAutoRotateSettingController = new DeviceStateAutoRotateSettingController( context, handler.getLooper(), handler, deviceStateController, deviceStateAutoRotateSettingManager); deviceStateController, deviceStateAutoRotateSettingManager, wmService); } return deviceStateAutoRotateSettingController; Loading Loading
core/java/com/android/internal/view/RotationPolicy.java +10 −2 Original line number Diff line number Diff line Loading @@ -172,11 +172,19 @@ public final class RotationPolicy { setRotationLock(enabled, NATURAL_ROTATION, caller); } private static boolean areAllRotationsAllowed(Context context) { /** * If true, the screen can be rotated via the accelerometer in all 4 rotations as the default * behavior. */ public static boolean areAllRotationsAllowed(Context context) { return context.getResources().getBoolean(R.bool.config_allowAllRotations); } private static boolean useCurrentRotationOnRotationLockChange(Context context) { /** * If false and config_allowAllRotations is false, the screen will rotate to the natural * orientation of the device when the auto-rotate policy is toggled. */ public static boolean useCurrentRotationOnRotationLockChange(Context context) { return context.getResources().getBoolean( R.bool.config_useCurrentRotationOnRotationLockChange); } Loading
packages/SettingsLib/DeviceStateRotationLock/src/com/android/settingslib/devicestate/DeviceStateAutoRotateSettingManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ public interface DeviceStateAutoRotateSettingManager extends Dumpable { void unregisterListener(@NonNull DeviceStateAutoRotateSettingListener settingListener); /** * Write {@code deviceState}'s setting value as {@code autoRotate}, for * Write {@code deviceState}'s setting value as {@code rotationLock}, for * {@link DEVICE_STATE_ROTATION_LOCK} setting. */ void updateSetting(int deviceState, boolean autoRotate); void updateSetting(int deviceState, boolean rotationLock); /** * Get {@link DEVICE_STATE_ROTATION_LOCK} setting value for {@code deviceState}. Returns null if Loading
packages/SettingsLib/DeviceStateRotationLock/src/com/android/settingslib/devicestate/DeviceStateAutoRotateSettingManagerImpl.java +3 −3 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.util.Log; import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.view.RotationPolicy; import com.android.window.flags.Flags; import java.io.PrintWriter; Loading Loading @@ -172,9 +173,8 @@ public class DeviceStateAutoRotateSettingManagerImpl implements } @Override public void updateSetting(int deviceState, boolean autoRotate) { // TODO: b/350946537 - Create IPC to update the setting, and call it here. throw new UnsupportedOperationException("API updateSetting is not implemented yet"); public void updateSetting(int deviceState, boolean rotationLock) { RotationPolicy.requestDeviceStateAutoRotateSettingChange(deviceState, !rotationLock); } @Override Loading
services/core/java/com/android/server/wm/DeviceStateAutoRotateSettingController.java +115 −49 Original line number Diff line number Diff line Loading @@ -22,6 +22,12 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCK import static android.provider.Settings.System.ACCELEROMETER_ROTATION; import static android.provider.Settings.System.getUriFor; import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION; import static com.android.internal.view.RotationPolicy.areAllRotationsAllowed; import static com.android.internal.view.RotationPolicy.useCurrentRotationOnRotationLockChange; import static com.android.server.wm.DisplayRotation.NO_UPDATE_USER_ROTATION; import static com.android.server.wm.DisplayRotation.USE_CURRENT_ROTATION; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; Loading @@ -30,7 +36,6 @@ import android.database.ContentObserver; import android.hardware.devicestate.DeviceState; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.provider.Settings; Loading @@ -38,6 +43,8 @@ import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.PersistedSettingUpdate; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.UpdateAccelerometerRotationSetting; import com.android.server.wm.DeviceStateAutoRotateSettingController.Event.UpdateDeviceState; Loading Loading @@ -83,18 +90,22 @@ public class DeviceStateAutoRotateSettingController { private final ContentResolver mContentResolver; private final DeviceStateController mDeviceStateController; private final List<Event> mPendingEvents = new ArrayList<>(); private final WindowManagerService mWm; private final Context mContext; private int mDeviceState = INVALID_DEVICE_STATE; private boolean mAccelerometerSetting; private SparseIntArray mDeviceStateAutoRotateSetting; public DeviceStateAutoRotateSettingController( Context context, Looper looper, Handler handler, DeviceStateController deviceStateController, DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager) { DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager, WindowManagerService wmService) { mDeviceStateAutoRotateSettingManager = deviceStateAutoRotateSettingManager; mHandler = handler; mContentResolver = context.getContentResolver(); mWm = wmService; mContext = mWm.mContext; mHandler = getHandler(); mContentResolver = mContext.getContentResolver(); mDeviceStateController = deviceStateController; mDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); if (mDeviceStateAutoRotateSetting == null) { Loading @@ -102,7 +113,7 @@ public class DeviceStateAutoRotateSettingController { mDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); } mAccelerometerSetting = getAccelerometerRotationSetting(); mEventHandler = new Handler(looper) { mEventHandler = new Handler(mHandler.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { final Event event = (Event) msg.obj; Loading Loading @@ -133,11 +144,16 @@ public class DeviceStateAutoRotateSettingController { } private void handleEvent(@NonNull Event event) { final boolean inMemoryStateUpdated = updateInMemoryState(event); final boolean persistedAccelerometerRotationSetting = getAccelerometerRotationSetting(); final SparseIntArray persistedDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); if (inMemoryStateUpdated) { writeInMemoryStateIntoPersistedSetting(); } updateInMemoryState(event, persistedAccelerometerRotationSetting, persistedDeviceStateAutoRotateSetting); writeInMemoryStateIntoPersistedSetting(persistedAccelerometerRotationSetting, persistedDeviceStateAutoRotateSetting); writeUserRotationSettingIfNeeded(event, persistedAccelerometerRotationSetting); } /** Request to change {@link DEVICE_STATE_ROTATION_LOCK} persisted setting. */ Loading @@ -145,9 +161,12 @@ public class DeviceStateAutoRotateSettingController { postUpdate(new UpdateDeviceStateAutoRotateSetting(deviceState, autoRotate)); } /** Request to change {@link ACCELEROMETER_ROTATION} persisted setting. */ public void requestAccelerometerRotationSettingChange(boolean autoRotate) { postUpdate(new UpdateAccelerometerRotationSetting(autoRotate)); /** * Request to change {@link ACCELEROMETER_ROTATION} persisted setting. If needed, we might also * write into {@link USER_ROTATION} with {@param userRotation}. */ public void requestAccelerometerRotationSettingChange(boolean autoRotate, int userRotation) { postUpdate(new UpdateAccelerometerRotationSetting(autoRotate, userRotation)); } private void registerDeviceStateAutoRotateSettingObserver() { Loading Loading @@ -179,28 +198,27 @@ public class DeviceStateAutoRotateSettingController { Message.obtain(mEventHandler, MSG_UPDATE_STATE, event).sendToTarget(); } private boolean updateInMemoryState(Event event) { private void updateInMemoryState(Event event, boolean persistedAccelerometerRotationSetting, SparseIntArray persistedDeviceStateAutoRotateSetting) { // Compare persisted setting value with in-memory state before making any changes to // in-memory state. This is to detect if persisted setting was changed directly, which is // not expected. final boolean newAccelerometerRotationSetting = getAccelerometerRotationSetting(); SparseIntArray newDeviceStateAutoRotateSetting = getDeviceStateAutoRotateSetting(); // Map would be null if string value of DEVICE_STATE_ROTATION_LOCK is corrupted. final boolean isDeviceStateAutoRotateSettingCorrupted = newDeviceStateAutoRotateSetting == null; persistedDeviceStateAutoRotateSetting == null; if (isDeviceStateAutoRotateSettingCorrupted) { // If string value of DEVICE_STATE_ROTATION_LOCK is corrupted, rewrite it with default // value while also respecting current ACCELEROMETER_ROTATION setting value. newDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); newDeviceStateAutoRotateSetting.put(mDeviceState, persistedDeviceStateAutoRotateSetting = getDefaultDeviceStateAutoRotateSetting(); persistedDeviceStateAutoRotateSetting.put(mDeviceState, mAccelerometerSetting ? DEVICE_STATE_ROTATION_LOCK_UNLOCKED : DEVICE_STATE_ROTATION_LOCK_LOCKED); } final boolean wasAccelerometerRotationSettingChanged = (newAccelerometerRotationSetting != mAccelerometerSetting); (persistedAccelerometerRotationSetting != mAccelerometerSetting); final boolean wasDevicesStateAutoRotateSettingChanged = !equals( mDeviceStateAutoRotateSetting, newDeviceStateAutoRotateSetting); mDeviceStateAutoRotateSetting, persistedDeviceStateAutoRotateSetting); if (wasAccelerometerRotationSettingChanged || wasDevicesStateAutoRotateSettingChanged) { // System apps should only request changes via DeviceStateAutoRotateSettingManager's Loading @@ -209,14 +227,15 @@ public class DeviceStateAutoRotateSettingController { if (wasAccelerometerRotationSettingChanged) { errorMessage.append("ACCELEROMETER_ROTATION setting changed from ").append( mAccelerometerSetting).append(" to ").append( newAccelerometerRotationSetting).append(" via Settings API.\n"); persistedAccelerometerRotationSetting).append(" via Settings API.\n"); } if (wasDevicesStateAutoRotateSettingChanged) { errorMessage.append( "DEVICE_STATE_ROTATION_LOCK setting directly changed from ").append( mDeviceStateAutoRotateSetting).append(" to ").append( newDeviceStateAutoRotateSetting).append("\nExpectation is for system-apps " + "to only use defined apis to change auto-rotate persisted settings.\n"); persistedDeviceStateAutoRotateSetting).append( "\nExpectation is for system-apps to only use defined apis to change " + "auto-rotate persisted settings.\n"); } Slog.e(TAG, errorMessage + "Using Settings API to write auto-rotate persisted setting, could result " Loading @@ -235,24 +254,18 @@ public class DeviceStateAutoRotateSettingController { // prioritize ACCELEROMETER_ROTATION because it has a direct impact on the user visible // behavior. if (wasDevicesStateAutoRotateSettingChanged) { // Clone the newDeviceStateAutoRotateSetting to avoid modifying it when updating // Clone the persistedDeviceStateAutoRotateSetting to avoid modifying it when updating // mDeviceStateAutoRotateSetting in future mDeviceStateAutoRotateSetting = newDeviceStateAutoRotateSetting.clone(); mDeviceStateAutoRotateSetting = persistedDeviceStateAutoRotateSetting.clone(); mAccelerometerSetting = mDeviceStateAutoRotateSetting.get(mDeviceState) == DEVICE_STATE_ROTATION_LOCK_UNLOCKED; } if (wasAccelerometerRotationSettingChanged) { mAccelerometerSetting = newAccelerometerRotationSetting; mAccelerometerSetting = persistedAccelerometerRotationSetting; mDeviceStateAutoRotateSetting.put(mDeviceState, mAccelerometerSetting ? DEVICE_STATE_ROTATION_LOCK_UNLOCKED : DEVICE_STATE_ROTATION_LOCK_LOCKED); } // Return true if the in-memory state was updated and write needs to be made in persisted // settings. return (mAccelerometerSetting != newAccelerometerRotationSetting || !equals(mDeviceStateAutoRotateSetting, newDeviceStateAutoRotateSetting) || isDeviceStateAutoRotateSettingCorrupted); } private void updateInMemoryStateFromEvent(Event event) { Loading Loading @@ -282,6 +295,64 @@ public class DeviceStateAutoRotateSettingController { } } private void writeInMemoryStateIntoPersistedSetting( boolean persistedAccelerometerRotationSetting, SparseIntArray persistedDeviceStateAutoRotateSetting) { if (mAccelerometerSetting != persistedAccelerometerRotationSetting) { Settings.System.putIntForUser(mContentResolver, ACCELEROMETER_ROTATION, mAccelerometerSetting ? ACCELEROMETER_ROTATION_ON : ACCELEROMETER_ROTATION_OFF, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "ACCELEROMETER_ROTATION=" + mAccelerometerSetting); } } if (!equals(mDeviceStateAutoRotateSetting, persistedDeviceStateAutoRotateSetting)) { final String serializedDeviceStateAutoRotateSetting = convertIntArrayToSerializedSetting(mDeviceStateAutoRotateSetting); Settings.Secure.putStringForUser(mContentResolver, DEVICE_STATE_ROTATION_LOCK, serializedDeviceStateAutoRotateSetting, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "DEVICE_STATE_ROTATION_LOCK=" + serializedDeviceStateAutoRotateSetting); } } } private void writeUserRotationSettingIfNeeded(Event event, boolean persistedAccelerometerRotationSetting) { if (!(event instanceof UpdateAccelerometerRotationSetting) && (mAccelerometerSetting == persistedAccelerometerRotationSetting)) { return; } final int userRotation; if (event instanceof UpdateAccelerometerRotationSetting) { // If the event is `UpdateAccelerometerRotationSetting`, it means that the // userRotation was provided, so we should set it. userRotation = ((UpdateAccelerometerRotationSetting) event).mUserRotation; } else { // If the event is not `UpdateAccelerometerRotationSetting`, it means that the // userRotation was not explicitly provided. if (mAccelerometerSetting) { userRotation = NO_UPDATE_USER_ROTATION; } else { userRotation = areAllRotationsAllowed(mContext) || useCurrentRotationOnRotationLockChange(mContext) ? USE_CURRENT_ROTATION : NATURAL_ROTATION; } } synchronized (mWm.mRoot.mService.mGlobalLock) { mWm.mRoot.getDefaultDisplay().getDisplayRotation().setUserRotationSetting( mAccelerometerSetting ? WindowManagerPolicy.USER_ROTATION_FREE : WindowManagerPolicy.USER_ROTATION_LOCKED, userRotation, "DSAutoRotateCtrl"); } } private boolean getAccelerometerRotationSetting() { return Settings.System.getIntForUser(mContentResolver, ACCELEROMETER_ROTATION, /* def= */ -1, UserHandle.USER_CURRENT) == ACCELEROMETER_ROTATION_ON; Loading @@ -297,20 +368,9 @@ public class DeviceStateAutoRotateSettingController { return mDeviceStateAutoRotateSettingManager.getDefaultRotationLockSetting(); } private void writeInMemoryStateIntoPersistedSetting() { Settings.System.putIntForUser(mContentResolver, ACCELEROMETER_ROTATION, mAccelerometerSetting ? ACCELEROMETER_ROTATION_ON : ACCELEROMETER_ROTATION_OFF, UserHandle.USER_CURRENT); final String serializedDeviceStateAutoRotateSetting = convertIntArrayToSerializedSetting(mDeviceStateAutoRotateSetting); Settings.Secure.putStringForUser(mContentResolver, DEVICE_STATE_ROTATION_LOCK, serializedDeviceStateAutoRotateSetting, UserHandle.USER_CURRENT); if (DEBUG) { Slog.d(TAG, "Wrote into persisted setting:\n" + "ACCELEROMETER_ROTATION=" + mAccelerometerSetting + "\nDEVICE_STATE_ROTATION_LOCK=" + serializedDeviceStateAutoRotateSetting); } @VisibleForTesting Handler getHandler() { return mWm.mH; } private static String convertIntArrayToSerializedSetting( Loading Loading @@ -339,15 +399,21 @@ public class DeviceStateAutoRotateSettingController { /** * Event sent when there is a request to update the current auto-rotate setting. * This occurs when actions like `freezeRotation` or `thawRotation` are triggered. * It also contains the user rotation that should be set, if userRotation is -1 then * {@link Settings.System#USER_ROTATION} setting will not be updated. */ static final class UpdateAccelerometerRotationSetting extends Event { final boolean mAutoRotate; final int mUserRotation; /** * @param autoRotate The desired auto-rotate state to write into ACCELEROMETER_ROTATION. * @param autoRotate The desired auto-rotate state to write into * ACCELEROMETER_ROTATION. * @param userRotation The desired user rotation to write into USER_ROTATION. */ UpdateAccelerometerRotationSetting(boolean autoRotate) { UpdateAccelerometerRotationSetting(boolean autoRotate, int userRotation) { mAutoRotate = autoRotate; mUserRotation = userRotation; } } Loading
services/core/java/com/android/server/wm/DisplayRotation.java +58 −14 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ import java.util.Set; * Non-public methods are assumed to run inside WM lock. */ public class DisplayRotation { public static final int USE_CURRENT_ROTATION = -1; public static final int NO_UPDATE_USER_ROTATION = -2; private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; // Delay in milliseconds when updating config due to folding events. This prevents Loading Loading @@ -752,20 +754,29 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation, String caller) { mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; if (useDefaultSettingsProvider()) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); final int accelerometerRotation = userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1; if (mService.mRoot.mDeviceStateAutoRotateSettingController != null) { // This call will trigger a setting update asynchronously. DisplayRotation will be // notified of this update via the registered settings listener. That means, // subsequent calls may not be able to read the updated value upon querying // ACCELEROMETER_ROTATION. In future, while processing this request, // setUserRotationSetting may be called. mService.mRoot.mDeviceStateAutoRotateSettingController .requestAccelerometerRotationSettingChange(accelerometerRotation == 1, userRotation); } else { Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION, accelerometerRotation, UserHandle.USER_CURRENT); Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation, UserHandle.USER_CURRENT); setUserRotationSetting(userRotationMode, userRotation, caller); } return; } mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; boolean changed = false; if (mUserRotationMode != userRotationMode) { mUserRotationMode = userRotationMode; Loading @@ -790,8 +801,41 @@ public class DisplayRotation { } } /** * Sets the user rotation and updates the {@link RotationLockHistory}. * * @param userRotationMode The user rotation mode (e.g., * {@link WindowManagerPolicy#USER_ROTATION_FREE}, * {@link WindowManagerPolicy#USER_ROTATION_LOCKED}). * @param userRotation The desired user rotation (e.g., {@link Surface#ROTATION_0}, * {@link Surface#ROTATION_90}, etc.). If this value is set to * {@link USE_CURRENT_ROTATION}, the * {@link Settings.System#USER_ROTATION} setting will be set to * {@link #mRotation}. If this value is set to * {@link NO_UPDATE_USER_ROTATION}, the * {@link Settings.System#USER_ROTATION} setting will be set to * {@link #mUserRotation}. * @param caller The caller of this method, used for logging in * {@link RotationLockHistory}. */ void setUserRotationSetting(int userRotationMode, int userRotation, String caller) { if (userRotation == USE_CURRENT_ROTATION) { userRotation = mRotation; } else if (userRotation == NO_UPDATE_USER_ROTATION) { userRotation = mUserRotation; } Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.USER_ROTATION, userRotation, UserHandle.USER_CURRENT); mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; } void requestDeviceStateAutoRotateSettingChange(int deviceState, boolean autoRotate) { // TODO(b/350946537) Redirect request to DeviceStateAutoRotateSettingController if (mService.mRoot.mDeviceStateAutoRotateSettingController != null) { mService.mRoot.mDeviceStateAutoRotateSettingController .requestDeviceStateAutoRotateSettingChange(deviceState, autoRotate); } } void freezeRotation(int rotation, String caller) { Loading @@ -799,7 +843,7 @@ public class DisplayRotation { rotation = RotationUtils.reverseRotationDirectionAroundZAxis(rotation); } rotation = (rotation == -1) ? mRotation : rotation; rotation = (rotation == USE_CURRENT_ROTATION) ? mRotation : rotation; setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation, caller); } Loading Loading @@ -1661,7 +1705,8 @@ public class DisplayRotation { */ @Nullable static DeviceStateAutoRotateSettingController createDeviceStateAutoRotateDependencies( Context context, DeviceStateController deviceStateController, Handler handler) { Context context, DeviceStateController deviceStateController, WindowManagerService wmService) { if (!isFoldable(context) || !isAutoRotateSupported(context)) return null; if (!Flags.enableDeviceStateAutoRotateSettingLogging() && !Flags.enableDeviceStateAutoRotateSettingRefactor()) { Loading @@ -1675,17 +1720,16 @@ public class DisplayRotation { if (Flags.enableDeviceStateAutoRotateSettingLogging()) { new DeviceStateAutoRotateSettingIssueLogger(SystemClock::elapsedRealtime, secureSettings, deviceStateController, handler); secureSettings, deviceStateController, wmService.mH); } if (Flags.enableDeviceStateAutoRotateSettingRefactor()) { final DeviceStateAutoRotateSettingManager deviceStateAutoRotateSettingManager = new DeviceStateAutoRotateSettingManagerImpl( context, BackgroundThread.getExecutor(), secureSettings, handler, context, BackgroundThread.getExecutor(), secureSettings, wmService.mH, new PostureDeviceStateConverter(context, new DeviceStateManager())); deviceStateAutoRotateSettingController = new DeviceStateAutoRotateSettingController( context, handler.getLooper(), handler, deviceStateController, deviceStateAutoRotateSettingManager); deviceStateController, deviceStateAutoRotateSettingManager, wmService); } return deviceStateAutoRotateSettingController; Loading