Persist user rotations of external displays.
It also introduces a command line tool to rotate external displays for
testing purposes.
Instead of changing signatures of freezeRotation(), thawRotation() and
isRotationFrozen(), introduce 3 new methods to IWindowManager interface.
The old methods are being used pervasively.
Also resolved some style issues in DisplaySettings class.
Bug: 113252523
Bug: 111361251
Test: Rotation locks via settings still work. User rotation mode and
user rotation values for external devices are persisted as expected in
storage. DisplaySettingsTests passes.
Change-Id: I1746bea98a588f0bbd30c9f0617a7a23dc6e4209
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 3e559d9..0c3a295 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -226,27 +226,52 @@
int getPreferredOptionsPanelGravity(int displayId);
/**
- * Lock the device orientation to the specified rotation, or to the
- * current rotation if -1. Sensor input will be ignored until
- * thawRotation() is called.
- * @hide
+ * Equivalent to calling {@link #freezeDisplayRotation(int, int)} with {@link
+ * android.view.Display#DEFAULT_DISPLAY} and given rotation.
*/
void freezeRotation(int rotation);
/**
- * Release the orientation lock imposed by freezeRotation().
- * @hide
+ * Equivalent to calling {@link #thawDisplayRotation(int)} with {@link
+ * android.view.Display#DEFAULT_DISPLAY}.
*/
void thawRotation();
/**
- * Gets whether the rotation is frozen.
- *
- * @return Whether the rotation is frozen.
+ * Equivelant to call {@link #isDisplayRotationFrozen(int)} with {@link
+ * android.view.Display#DEFAULT_DISPLAY}.
*/
boolean isRotationFrozen();
/**
+ * Lock the display orientation to the specified rotation, or to the current
+ * rotation if -1. Sensor input will be ignored until thawRotation() is called.
+ *
+ * @param displayId the ID of display which rotation should be frozen.
+ * @param rotation one of {@link android.view.Surface#ROTATION_0},
+ * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
+ * {@link android.view.Surface#ROTATION_270} or -1 to freeze it to current rotation.
+ * @hide
+ */
+ void freezeDisplayRotation(int displayId, int rotation);
+
+ /**
+ * Release the orientation lock imposed by freezeRotation() on the display.
+ *
+ * @param displayId the ID of display which rotation should be thawed.
+ * @hide
+ */
+ void thawDisplayRotation(int displayId);
+
+ /**
+ * Gets whether the rotation is frozen on the display.
+ *
+ * @param displayId the ID of display which frozen is needed.
+ * @return Whether the rotation is frozen.
+ */
+ boolean isDisplayRotationFrozen(int displayId);
+
+ /**
* Screenshot the current wallpaper layer, including the whole screen.
*/
Bitmap screenshotWallpaper();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 06ee935..7489267 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6860,37 +6860,6 @@
}
@Override
- public int getUserRotationMode() {
- return Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
- WindowManagerPolicy.USER_ROTATION_FREE :
- WindowManagerPolicy.USER_ROTATION_LOCKED;
- }
-
- // User rotation: to be used when all else fails in assigning an orientation to the device
- @Override
- public void setUserRotationMode(int mode, int rot) {
- ContentResolver res = mContext.getContentResolver();
-
- // mUserRotationMode and mUserRotation will be assigned by the content observer
- if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
- Settings.System.putIntForUser(res,
- Settings.System.USER_ROTATION,
- rot,
- UserHandle.USER_CURRENT);
- Settings.System.putIntForUser(res,
- Settings.System.ACCELEROMETER_ROTATION,
- 0,
- UserHandle.USER_CURRENT);
- } else {
- Settings.System.putIntForUser(res,
- Settings.System.ACCELEROMETER_ROTATION,
- 1,
- UserHandle.USER_CURRENT);
- }
- }
-
- @Override
public void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
if (safeMode) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 27ab3ef..37b769b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -82,7 +82,6 @@
import android.view.IWindowManager;
import android.view.InputEventReceiver;
import android.view.KeyEvent;
-import android.view.Surface;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants;
@@ -1483,26 +1482,6 @@
public void keepScreenOnStoppedLw();
/**
- * Gets the current user rotation mode.
- *
- * @return The rotation mode.
- *
- * @see #USER_ROTATION_LOCKED
- * @see #USER_ROTATION_FREE
- */
- @UserRotationMode
- public int getUserRotationMode();
-
- /**
- * Inform the policy that the user has chosen a preferred orientation ("rotation lock").
- *
- * @param mode One of {@link #USER_ROTATION_LOCKED} or {@link #USER_ROTATION_FREE}.
- * @param rotation One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
- * {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
- */
- public void setUserRotationMode(@UserRotationMode int mode, @Surface.Rotation int rotation);
-
- /**
* Called when a new system UI visibility is being reported, allowing
* the policy to adjust what is actually reported.
* @param visibility The raw visibility reported by the status bar.
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index bd82553..847cff9 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -55,6 +55,7 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
private final WindowManagerService mService;
+ private final DisplayContent mDisplayContent;
private final DisplayPolicy mDisplayPolicy;
private final Context mContext;
private final Object mLock;
@@ -106,6 +107,7 @@
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
DisplayPolicy displayPolicy, Context context, Object lock) {
mService = service;
+ mDisplayContent = displayContent;
mDisplayPolicy = displayPolicy;
mContext = context;
mLock = lock;
@@ -225,6 +227,70 @@
}
}
+ void restoreUserRotation(int userRotationMode, int userRotation) {
+ if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
+ && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
+ Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
+ + " for " + mDisplayContent);
+ userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
+ }
+ if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) {
+ Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation
+ + " for " + mDisplayContent);
+ userRotation = Surface.ROTATION_0;
+ }
+ mUserRotationMode = userRotationMode;
+ mUserRotation = userRotation;
+ }
+
+ private void setUserRotation(int userRotationMode, int userRotation) {
+ if (isDefaultDisplay) {
+ // 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;
+ Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
+ accelerometerRotation, UserHandle.USER_CURRENT);
+ Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
+ UserHandle.USER_CURRENT);
+ return;
+ }
+
+ boolean changed = false;
+ if (mUserRotationMode != userRotationMode) {
+ mUserRotationMode = userRotationMode;
+ changed = true;
+ }
+ if (mUserRotation != userRotation) {
+ mUserRotation = userRotation;
+ changed = true;
+ }
+ mService.mDisplaySettings.setUserRotation(mDisplayContent, userRotationMode, userRotation);
+ if (changed) {
+ mService.updateRotation(true /* alwaysSendConfiguration */,
+ false /* forceRelayout */);
+ mService.mDisplaySettings.writeSettingsLocked();
+ }
+ }
+
+ void freezeRotation(int rotation) {
+ rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
+ setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
+ }
+
+ void thawRotation() {
+ setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
+ }
+
+ boolean isRotationFrozen() {
+ if (!isDefaultDisplay) {
+ return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
+ }
+
+ return Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
+ }
+
/** @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true. */
boolean isDefaultOrientationForced() {
return mForceDefaultOrientation;
@@ -381,9 +447,6 @@
* @param orientation An orientation constant, such as
* {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
* @param lastRotation The most recently used rotation.
- * @param defaultDisplay Flag indicating whether the rotation is computed for the default
- * display. Currently for all non-default displays sensors, docking mode,
- * rotation lock and other factors are ignored.
* @return The surface rotation to use.
*/
int rotationForOrientation(int orientation, int lastRotation) {
@@ -418,8 +481,8 @@
final int preferredRotation;
if (!isDefaultDisplay) {
// For secondary displays we ignore things like displays sensors, docking mode and
- // rotation lock, and always prefer a default rotation.
- preferredRotation = Surface.ROTATION_0;
+ // rotation lock, and always prefer user rotation.
+ preferredRotation = mUserRotation;
} else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
// Ignore sensor when lid switch is open and rotation is forced.
preferredRotation = mLidOpenRotation;
diff --git a/services/core/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
index bbb690f..28dc008 100644
--- a/services/core/java/com/android/server/wm/DisplaySettings.java
+++ b/services/core/java/com/android/server/wm/DisplaySettings.java
@@ -20,20 +20,23 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.WindowConfiguration;
-import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Environment;
-import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.policy.WindowManagerPolicy;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -43,10 +46,6 @@
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
/**
* Current persistent settings about a display
*/
@@ -58,15 +57,25 @@
private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
private static class Entry {
- private final String name;
- private int overscanLeft;
- private int overscanTop;
- private int overscanRight;
- private int overscanBottom;
- private int windowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ private final String mName;
+ private int mOverscanLeft;
+ private int mOverscanTop;
+ private int mOverscanRight;
+ private int mOverscanBottom;
+ private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
+ private int mUserRotation = Surface.ROTATION_0;
private Entry(String _name) {
- name = _name;
+ mName = _name;
+ }
+
+ private boolean isEmpty() {
+ return mOverscanLeft == 0 && mOverscanTop == 0 && mOverscanRight == 0
+ && mOverscanBottom == 0
+ && mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
+ && mUserRotation == Surface.ROTATION_0;
}
}
@@ -90,13 +99,30 @@
return entry;
}
+ private Entry getOrCreateEntry(String uniqueId, String name) {
+ Entry entry = getEntry(uniqueId, name);
+ if (entry == null) {
+ entry = new Entry(uniqueId);
+ mEntries.put(uniqueId, entry);
+ }
+ return entry;
+ }
+
+ private void removeEntryIfEmpty(String uniqueId, String name) {
+ final Entry entry = getEntry(uniqueId, name);
+ if (entry.isEmpty()) {
+ mEntries.remove(uniqueId);
+ mEntries.remove(name);
+ }
+ }
+
private void getOverscanLocked(String name, String uniqueId, Rect outRect) {
final Entry entry = getEntry(name, uniqueId);
if (entry != null) {
- outRect.left = entry.overscanLeft;
- outRect.top = entry.overscanTop;
- outRect.right = entry.overscanRight;
- outRect.bottom = entry.overscanBottom;
+ outRect.left = entry.mOverscanLeft;
+ outRect.top = entry.mOverscanTop;
+ outRect.right = entry.mOverscanRight;
+ outRect.bottom = entry.mOverscanBottom;
} else {
outRect.set(0, 0, 0, 0);
}
@@ -104,28 +130,22 @@
void setOverscanLocked(String uniqueId, String name, int left, int top, int right,
int bottom) {
- if (left == 0 && top == 0 && right == 0 && bottom == 0) {
- // Right now all we are storing is overscan; if there is no overscan,
- // we have no need for the entry.
- mEntries.remove(uniqueId);
- // Legacy name might have been in used, so we need to clear it.
- mEntries.remove(name);
+ Entry entry = mEntries.get(uniqueId);
+ if (left == 0 && top == 0 && right == 0 && bottom == 0 && entry == null) {
+ // All default value, no action needed.
return;
}
- Entry entry = mEntries.get(uniqueId);
- if (entry == null) {
- entry = new Entry(uniqueId);
- mEntries.put(uniqueId, entry);
- }
- entry.overscanLeft = left;
- entry.overscanTop = top;
- entry.overscanRight = right;
- entry.overscanBottom = bottom;
+ entry = getOrCreateEntry(uniqueId, name);
+ entry.mOverscanLeft = left;
+ entry.mOverscanTop = top;
+ entry.mOverscanRight = right;
+ entry.mOverscanBottom = bottom;
+ removeEntryIfEmpty(uniqueId, name);
}
private int getWindowingModeLocked(String name, String uniqueId, int displayId) {
final Entry entry = getEntry(name, uniqueId);
- int windowingMode = entry != null ? entry.windowingMode
+ int windowingMode = entry != null ? entry.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
// This display used to be in freeform, but we don't support freeform anymore, so fall
// back to fullscreen.
@@ -148,6 +168,36 @@
return windowingMode;
}
+ void setUserRotation(DisplayContent dc, int rotationMode, int rotation) {
+ final DisplayInfo displayInfo = dc.getDisplayInfo();
+
+ final String uniqueId = displayInfo.uniqueId;
+ final String name = displayInfo.name;
+ Entry entry = getEntry(displayInfo.name, uniqueId);
+ if (rotationMode == WindowManagerPolicy.USER_ROTATION_FREE
+ && rotation == Surface.ROTATION_0 && entry == null) {
+ // All default values. No action needed.
+ return;
+ }
+
+ entry = getOrCreateEntry(uniqueId, name);
+ entry.mUserRotationMode = rotationMode;
+ entry.mUserRotation = rotation;
+ removeEntryIfEmpty(uniqueId, name);
+ }
+
+ private void restoreUserRotation(DisplayContent dc) {
+ final DisplayInfo info = dc.getDisplayInfo();
+
+ final Entry entry = getEntry(info.name, info.uniqueId);
+ final int userRotationMode = entry != null ? entry.mUserRotationMode
+ : WindowManagerPolicy.USER_ROTATION_FREE;
+ final int userRotation = entry != null ? entry.mUserRotation
+ : Surface.ROTATION_0;
+
+ dc.getDisplayRotation().restoreUserRotation(userRotationMode, userRotation);
+ }
+
void applySettingsToDisplayLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
@@ -161,6 +211,8 @@
displayInfo.overscanTop = rect.top;
displayInfo.overscanRight = rect.right;
displayInfo.overscanBottom = rect.bottom;
+
+ restoreUserRotation(dc);
}
void readSettingsLocked() {
@@ -244,12 +296,16 @@
String name = parser.getAttributeValue(null, "name");
if (name != null) {
Entry entry = new Entry(name);
- entry.overscanLeft = getIntAttribute(parser, "overscanLeft");
- entry.overscanTop = getIntAttribute(parser, "overscanTop");
- entry.overscanRight = getIntAttribute(parser, "overscanRight");
- entry.overscanBottom = getIntAttribute(parser, "overscanBottom");
- entry.windowingMode = getIntAttribute(parser, "windowingMode",
+ entry.mOverscanLeft = getIntAttribute(parser, "overscanLeft");
+ entry.mOverscanTop = getIntAttribute(parser, "overscanTop");
+ entry.mOverscanRight = getIntAttribute(parser, "overscanRight");
+ entry.mOverscanBottom = getIntAttribute(parser, "overscanBottom");
+ entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
WindowConfiguration.WINDOWING_MODE_UNDEFINED);
+ entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
+ WindowManagerPolicy.USER_ROTATION_FREE);
+ entry.mUserRotation = getIntAttribute(parser, "userRotation",
+ Surface.ROTATION_0);
mEntries.put(name, entry);
}
XmlUtils.skipCurrentTag(parser);
@@ -272,21 +328,28 @@
for (Entry entry : mEntries.values()) {
out.startTag(null, "display");
- out.attribute(null, "name", entry.name);
- if (entry.overscanLeft != 0) {
- out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft));
+ out.attribute(null, "name", entry.mName);
+ if (entry.mOverscanLeft != 0) {
+ out.attribute(null, "overscanLeft", Integer.toString(entry.mOverscanLeft));
}
- if (entry.overscanTop != 0) {
- out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop));
+ if (entry.mOverscanTop != 0) {
+ out.attribute(null, "overscanTop", Integer.toString(entry.mOverscanTop));
}
- if (entry.overscanRight != 0) {
- out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight));
+ if (entry.mOverscanRight != 0) {
+ out.attribute(null, "overscanRight", Integer.toString(entry.mOverscanRight));
}
- if (entry.overscanBottom != 0) {
- out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom));
+ if (entry.mOverscanBottom != 0) {
+ out.attribute(null, "overscanBottom", Integer.toString(entry.mOverscanBottom));
}
- if (entry.windowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- out.attribute(null, "windowingMode", Integer.toString(entry.windowingMode));
+ if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
+ }
+ if (entry.mUserRotationMode != WindowManagerPolicy.USER_ROTATION_FREE) {
+ out.attribute(null, "userRotationMode",
+ Integer.toString(entry.mUserRotationMode));
+ }
+ if (entry.mUserRotation != Surface.ROTATION_0) {
+ out.attribute(null, "userRotation", Integer.toString(entry.mUserRotation));
}
out.endTag(null, "display");
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8b1b327..e0916fb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3672,14 +3672,19 @@
}
}
+ @Override
+ public void freezeRotation(int rotation) {
+ freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation);
+ }
+
/**
* Freeze rotation changes. (Enable "rotation lock".)
* Persists across reboots.
- * @param rotation The desired rotation to freeze to, or -1 to use the
- * current rotation.
+ * @param displayId The ID of the display to freeze.
+ * @param rotation The desired rotation to freeze to, or -1 to use the current rotation.
*/
@Override
- public void freezeRotation(int rotation) {
+ public void freezeDisplayRotation(int displayId, int rotation) {
// TODO(multi-display): Track which display is rotated.
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"freezeRotation()")) {
@@ -3690,14 +3695,16 @@
+ "rotation constant.");
}
- final int defaultDisplayRotation = getDefaultDisplayRotation();
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: mRotation="
- + defaultDisplayRotation);
-
long origId = Binder.clearCallingIdentity();
try {
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
- rotation == -1 ? defaultDisplayRotation : rotation);
+ synchronized (mWindowMap) {
+ final DisplayContent display = mRoot.getDisplayContent(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Trying to freeze rotation for a missing display.");
+ return;
+ }
+ display.getDisplayRotation().freezeRotation(rotation);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -3705,12 +3712,17 @@
updateRotationUnchecked(false, false);
}
+ @Override
+ public void thawRotation() {
+ thawDisplayRotation(Display.DEFAULT_DISPLAY);
+ }
+
/**
* Thaw rotation changes. (Disable "rotation lock".)
* Persists across reboots.
*/
@Override
- public void thawRotation() {
+ public void thawDisplayRotation(int displayId) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"thawRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
@@ -3721,8 +3733,14 @@
long origId = Binder.clearCallingIdentity();
try {
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
- 777); // rot not used
+ synchronized (mWindowMap) {
+ final DisplayContent display = mRoot.getDisplayContent(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Trying to thaw rotation for a missing display.");
+ return;
+ }
+ display.getDisplayRotation().thawRotation();
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -3730,6 +3748,23 @@
updateRotationUnchecked(false, false);
}
+ @Override
+ public boolean isRotationFrozen() {
+ return isDisplayRotationFrozen(Display.DEFAULT_DISPLAY);
+ }
+
+ @Override
+ public boolean isDisplayRotationFrozen(int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent display = mRoot.getDisplayContent(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Trying to thaw rotation for a missing display.");
+ return false;
+ }
+ return display.getDisplayRotation().isRotationFrozen();
+ }
+ }
+
/**
* Recalculate the current rotation.
*
@@ -3799,11 +3834,6 @@
}
@Override
- public boolean isRotationFrozen() {
- return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED;
- }
-
- @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 831418b..bf2d0df 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -26,6 +26,7 @@
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.IWindowManager;
+import android.view.Surface;
import java.io.PrintWriter;
import java.util.regex.Matcher;
@@ -73,6 +74,8 @@
// trace files can be written.
return mInternal.mWindowTracing.onShellCommand(this,
getNextArgRequired());
+ case "set-user-rotation":
+ return runSetDisplayUserRotation(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -262,6 +265,36 @@
return Integer.parseInt(s);
}
+ private int runSetDisplayUserRotation(PrintWriter pw) {
+ final String lockMode = getNextArgRequired();
+
+ int displayId = Display.DEFAULT_DISPLAY;
+ String arg = getNextArg();
+ if ("-d".equals(arg)) {
+ displayId = Integer.parseInt(getNextArgRequired());
+ arg = getNextArg();
+ }
+
+ if ("free".equals(lockMode)) {
+ mInternal.thawDisplayRotation(displayId);
+ return 0;
+ }
+
+ if (!lockMode.equals("lock")) {
+ getErrPrintWriter().println("Error: lock mode needs to be either free or lock.");
+ return -1;
+ }
+
+ try {
+ final int rotation = arg != null ? Integer.parseInt(arg) : Surface.ROTATION_0;
+ mInternal.freezeDisplayRotation(displayId, rotation);
+ return 0;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println("Error: " + e.getMessage());
+ return -1;
+ }
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -279,6 +312,8 @@
pw.println(" Set display scaling mode.");
pw.println(" dismiss-keyguard");
pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
+ pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]");
+ pw.println(" Set user rotation mode and user rotation.");
if (!IS_USER) {
pw.println(" tracing (start | stop)");
pw.println(" Start or stop window tracing.");
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
index 07eafa5..a028d5ee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
@@ -18,23 +18,34 @@
package com.android.server.wm;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import android.app.WindowConfiguration;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.policy.WindowManagerPolicy;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+/**
+ * Tests for the {@link DisplaySettings} class.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.wm.DisplaySettingsTests
+ */
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -155,6 +166,71 @@
assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
}
+ @Test
+ public void testDefaultToFreeUserRotation() {
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
+ assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, rotation.getUserRotationMode());
+ assertFalse(rotation.isRotationFrozen());
+ }
+
+ @Test
+ public void testDefaultTo0DegRotation() {
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ assertEquals(Surface.ROTATION_0, mSecondaryDisplay.getDisplayRotation().getUserRotation());
+ }
+
+ @Test
+ public void testPersistUserRotationModeInSameInstance() {
+ mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
+ Surface.ROTATION_90);
+
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
+ assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
+ assertTrue(rotation.isRotationFrozen());
+ }
+
+ @Test
+ public void testPersistUserRotationInSameInstance() {
+ mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
+ Surface.ROTATION_90);
+
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ assertEquals(Surface.ROTATION_90, mSecondaryDisplay.getDisplayRotation().getUserRotation());
+ }
+
+ @Test
+ public void testPersistUserRotationModeAcrossInstances() {
+ mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
+ Surface.ROTATION_270);
+ mTarget.writeSettingsLocked();
+
+ DisplaySettings target = new DisplaySettings(sWm, mTestFolder);
+ target.readSettingsLocked();
+
+ target.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
+ assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
+ assertTrue(rotation.isRotationFrozen());
+ }
+
+ @Test
+ public void testPersistUserRotationAcrossInstances() {
+ mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
+ Surface.ROTATION_270);
+
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
+ assertEquals(Surface.ROTATION_270,
+ mSecondaryDisplay.getDisplayRotation().getUserRotation());
+ }
+
private static void assertOverscan(DisplayContent display, int left, int top, int right,
int bottom) {
final DisplayInfo info = display.getDisplayInfo();
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 474e5b7..5159551 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -432,17 +432,6 @@
}
@Override
- public int getUserRotationMode() {
- return 0;
- }
-
- @Override
- public void setUserRotationMode(int mode,
- int rotation) {
-
- }
-
- @Override
public int adjustSystemUiVisibilityLw(int visibility) {
return 0;
}