Merge changes I2a8688e7,I6d831706 into tm-qpr-dev
* changes: Per-app controls for using landscape display orientation Add orientation per-app controls.
This commit is contained in:
committed by
Android (Google) Code Review
commit
558219eca0
@@ -1187,6 +1187,79 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
@Overridable
|
||||
public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L;
|
||||
|
||||
// Compat framework that per-app overrides rely on only supports booleans. That's why we have
|
||||
// multiple OVERRIDE_*_ORIENTATION_* change ids below instead of just one override with
|
||||
// the integer value.
|
||||
|
||||
/**
|
||||
* Enables {@link #SCREEN_ORIENTATION_PORTRAIT}. Unless OVERRIDE_ANY_ORIENTATION
|
||||
* is enabled, this override is used only when no other fixed orientation was specified by the
|
||||
* activity.
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L;
|
||||
|
||||
/**
|
||||
* Enables {@link #SCREEN_ORIENTATION_NOSENSOR}. Unless OVERRIDE_ANY_ORIENTATION
|
||||
* is enabled, this override is used only when no other fixed orientation was specified by the
|
||||
* activity.
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR = 265451093L;
|
||||
|
||||
/**
|
||||
* Enables {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE}. Unless OVERRIDE_ANY_ORIENTATION
|
||||
* is enabled, this override is used only when activity specify landscape orientation.
|
||||
* This can help apps that assume that landscape display orientation corresponds to {@link
|
||||
* android.view.Surface#ROTATION_90}, while on some devices it can be {@link
|
||||
* android.view.Surface#ROTATION_270}.
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE = 266124927L;
|
||||
|
||||
/**
|
||||
* When enabled, allows OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE,
|
||||
* OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR and OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
|
||||
* to override any orientation requested by the activity.
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_ANY_ORIENTATION = 265464455L;
|
||||
|
||||
/**
|
||||
* This override fixes display orientation to landscape natural orientation when a task is
|
||||
* fullscreen. While display rotation is fixed to landscape, the orientation requested by the
|
||||
* activity will be still respected by bounds resolution logic. For instance, if an activity
|
||||
* requests portrait orientation and this override is set, then activity will appear in the
|
||||
* letterbox mode for fixed orientation with the display rotated to the lanscape natural
|
||||
* orientation.
|
||||
*
|
||||
* <p>This override is applicable only when natural orientation of the device is
|
||||
* landscape and display ignores orientation requestes.
|
||||
*
|
||||
* <p>Main use case for this override are camera-using activities that are portrait-only and
|
||||
* assume alignment with natural device orientation. Such activities can automatically be
|
||||
* rotated with com.android.server.wm.DisplayRotationCompatPolicy but not all of them can
|
||||
* handle dynamic rotation and thus can benefit from this override.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L;
|
||||
|
||||
/**
|
||||
* Compares activity window layout min width/height with require space for multi window to
|
||||
* determine if it can be put into multi window mode.
|
||||
@@ -1405,8 +1478,19 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public boolean isFixedOrientation() {
|
||||
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|
||||
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
|
||||
return isFixedOrientation(screenOrientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed activity's orientation is fixed.
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isFixedOrientation(@ScreenOrientation int orientation) {
|
||||
return orientation == SCREEN_ORIENTATION_LOCKED
|
||||
// Orientation is fixed to natural display orientation
|
||||
|| orientation == SCREEN_ORIENTATION_NOSENSOR
|
||||
|| isFixedOrientationLandscape(orientation)
|
||||
|| isFixedOrientationPortrait(orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -989,6 +989,77 @@ public interface WindowManager extends ViewManager {
|
||||
String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE =
|
||||
"android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
|
||||
|
||||
/**
|
||||
* Activity level {@link android.content.pm.PackageManager.Property PackageManager
|
||||
* .Property} for an app to inform the system that the activity should be excluded from the
|
||||
* compatibility override for orientation set by the device manufacturer.
|
||||
*
|
||||
* <p>With this property set to {@code true} or unset, device manufacturers can override
|
||||
* orientation for the activity using their discretion to improve display compatibility.
|
||||
*
|
||||
* <p>With this property set to {@code false}, device manufactured per-app override for
|
||||
* orientation won't be applied.
|
||||
*
|
||||
* <p><b>Syntax:</b>
|
||||
* <pre>
|
||||
* <activity>
|
||||
* <property
|
||||
* android:name="android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE"
|
||||
* android:value="true|false"/>
|
||||
* </activity>
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/263984287): Make this public API.
|
||||
String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE =
|
||||
"android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
|
||||
|
||||
/**
|
||||
* Activity level {@link android.content.pm.PackageManager.Property PackageManager
|
||||
* .Property} for an app to inform the system that the activity should be opted-out from the
|
||||
* compatibility override that fixes display orientation to landscape natural orientation when
|
||||
* an activity is fullscreen.
|
||||
*
|
||||
* <p>When this compat override is enabled and while display is fixed to the landscape natural
|
||||
* orientation, the orientation requested by the activity will be still respected by bounds
|
||||
* resolution logic. For instance, if an activity requests portrait orientation, then activity
|
||||
* will appear in the letterbox mode for fixed orientation with the display rotated to the
|
||||
* lanscape natural orientation.
|
||||
*
|
||||
* <p>The treatment is disabled by default but device manufacturers can enable the treatment
|
||||
* using their discretion to improve display compatibility on the displays that have
|
||||
* ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
|
||||
* orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
|
||||
* for more details).
|
||||
*
|
||||
* <p>With this property set to {@code true} or unset, the system wiil use landscape display
|
||||
* orientation when the following conditions are met:
|
||||
* <ul>
|
||||
* <li>Natural orientation of the display is landscape
|
||||
* <li>ignoreOrientationRequest display setting is enabled
|
||||
* <li>Activity is fullscreen.
|
||||
* <li>Device manufacturer enabled the treatment.
|
||||
* </ul>
|
||||
*
|
||||
* <p>With this property set to {@code false}, device manufactured per-app override for
|
||||
* display orientation won't be applied.
|
||||
*
|
||||
* <p><b>Syntax:</b>
|
||||
* <pre>
|
||||
* <activity>
|
||||
* <property
|
||||
* android:name="android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE"
|
||||
* android:value="true|false"/>
|
||||
* </activity>
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/263984287): Make this public API.
|
||||
String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE =
|
||||
"android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -3331,6 +3331,12 @@
|
||||
"group": "WM_DEBUG_STATES",
|
||||
"at": "com\/android\/server\/wm\/TaskFragment.java"
|
||||
},
|
||||
"1015746067": {
|
||||
"message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/DisplayContent.java"
|
||||
},
|
||||
"1022095595": {
|
||||
"message": "TaskFragment info changed name=%s",
|
||||
"level": "VERBOSE",
|
||||
|
||||
@@ -709,7 +709,8 @@ class ActivityClientController extends IActivityClientController.Stub {
|
||||
synchronized (mGlobalLock) {
|
||||
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
|
||||
return r != null
|
||||
? r.getRequestedOrientation() : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
? r.getOverrideOrientation()
|
||||
: ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1165,8 +1165,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
pw.println(prefix + "mVoiceInteraction=true");
|
||||
}
|
||||
pw.print(prefix); pw.print("mOccludesParent="); pw.println(mOccludesParent);
|
||||
pw.print(prefix); pw.print("mOrientation=");
|
||||
pw.println(ActivityInfo.screenOrientationToString(mOrientation));
|
||||
pw.print(prefix); pw.print("overrideOrientation=");
|
||||
pw.println(ActivityInfo.screenOrientationToString(getOverrideOrientation()));
|
||||
pw.print(prefix); pw.print("requestedOrientation=");
|
||||
pw.println(ActivityInfo.screenOrientationToString(super.getOverrideOrientation()));
|
||||
pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
|
||||
+ " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
|
||||
+ ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
|
||||
@@ -1964,6 +1966,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
new ComponentName(info.packageName, info.targetActivity);
|
||||
}
|
||||
|
||||
// Don't move below setActivityType since it triggers onConfigurationChange ->
|
||||
// resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
|
||||
// Don't move below setOrientation(info.screenOrientation) since it triggers
|
||||
// getOverrideOrientation that requires having mLetterboxUiController
|
||||
// initialised.
|
||||
mLetterboxUiController = new LetterboxUiController(mWmService, this);
|
||||
mCameraCompatControlEnabled = mWmService.mContext.getResources()
|
||||
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
|
||||
|
||||
mTargetSdk = info.applicationInfo.targetSdkVersion;
|
||||
mShowForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
|
||||
setOrientation(info.screenOrientation);
|
||||
@@ -2084,12 +2095,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
|
||||
launchMode = aInfo.launchMode;
|
||||
|
||||
// Don't move below setActivityType since it triggers onConfigurationChange ->
|
||||
// resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
|
||||
mLetterboxUiController = new LetterboxUiController(mWmService, this);
|
||||
mCameraCompatControlEnabled = mWmService.mContext.getResources()
|
||||
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
|
||||
|
||||
setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
|
||||
|
||||
immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
|
||||
@@ -2486,7 +2491,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
if (topAttached != null) {
|
||||
if (topAttached.isSnapshotCompatible(snapshot)
|
||||
// This trampoline must be the same rotation.
|
||||
&& mDisplayContent.getDisplayRotation().rotationForOrientation(mOrientation,
|
||||
&& mDisplayContent.getDisplayRotation().rotationForOrientation(
|
||||
getOverrideOrientation(),
|
||||
mDisplayContent.getRotation()) == snapshot.getRotation()) {
|
||||
return STARTING_WINDOW_TYPE_SNAPSHOT;
|
||||
}
|
||||
@@ -7704,13 +7710,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return mLetterboxUiController.getInheritedOrientation();
|
||||
}
|
||||
}
|
||||
if (mOrientation == SCREEN_ORIENTATION_BEHIND && task != null) {
|
||||
if (task != null && getOverrideOrientation() == SCREEN_ORIENTATION_BEHIND) {
|
||||
// We use Task here because we want to be consistent with what happens in
|
||||
// multi-window mode where other tasks orientations are ignored.
|
||||
final ActivityRecord belowCandidate = task.getActivity(
|
||||
a -> a.mOrientation != SCREEN_ORIENTATION_UNSET && !a.finishing
|
||||
&& a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND, this,
|
||||
false /* includeBoundary */, true /* traverseTopToBottom */);
|
||||
a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
|
||||
this /* boundary */, false /* includeBoundary */,
|
||||
true /* traverseTopToBottom */);
|
||||
if (belowCandidate != null) {
|
||||
return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
|
||||
}
|
||||
@@ -7718,6 +7724,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return super.getRequestedConfigurationOrientation(forDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this activity can be used as an orientation source for activities above with
|
||||
* {@link SCREEN_ORIENTATION_BEHIND}.
|
||||
*/
|
||||
boolean canDefineOrientationForActivitiesAbove() {
|
||||
if (finishing) {
|
||||
return false;
|
||||
}
|
||||
final int overrideOrientation = getOverrideOrientation();
|
||||
return overrideOrientation != SCREEN_ORIENTATION_UNSET
|
||||
&& overrideOrientation != SCREEN_ORIENTATION_BEHIND;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCancelFixedRotationTransform(int originalDisplayRotation) {
|
||||
if (this != mDisplayContent.getLastOrientationSource()) {
|
||||
@@ -7744,7 +7763,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
}
|
||||
}
|
||||
|
||||
void setRequestedOrientation(int requestedOrientation) {
|
||||
void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
|
||||
if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
|
||||
return;
|
||||
}
|
||||
@@ -7789,7 +7808,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// Allow app to specify orientation regardless of its visibility state if the current
|
||||
// candidate want us to use orientation behind. I.e. the visible app on-top of this one
|
||||
// wants us to use the orientation of the app behind it.
|
||||
return mOrientation;
|
||||
return getOverrideOrientation();
|
||||
}
|
||||
|
||||
// The {@link ActivityRecord} should only specify an orientation when it is not closing.
|
||||
@@ -7797,15 +7816,31 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// task being started in the wrong orientation during the transition.
|
||||
if (!getDisplayContent().mClosingApps.contains(this)
|
||||
&& (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) {
|
||||
return mOrientation;
|
||||
return getOverrideOrientation();
|
||||
}
|
||||
|
||||
return SCREEN_ORIENTATION_UNSET;
|
||||
}
|
||||
|
||||
/** Returns the app's preferred orientation regardless of its currently visibility state. */
|
||||
/**
|
||||
* Returns the app's preferred orientation regardless of its current visibility state taking
|
||||
* into account orientation per-app overrides applied by the device manufacturers.
|
||||
*/
|
||||
@Override
|
||||
protected int getOverrideOrientation() {
|
||||
return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app's preferred orientation regardless of its currently visibility state. This
|
||||
* is used to return a requested value to an app if they call {@link
|
||||
* android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value
|
||||
* with override can confuse an app if it's different from what they requested with {@link
|
||||
* android.app.Activity#setRequestedOrientation}.
|
||||
*/
|
||||
@ActivityInfo.ScreenOrientation
|
||||
int getRequestedOrientation() {
|
||||
return mOrientation;
|
||||
return super.getOverrideOrientation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8357,8 +8392,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// If orientation is respected when insets are applied, then stableBounds will be empty.
|
||||
boolean orientationRespectedWithInsets =
|
||||
orientationRespectedWithInsets(parentBounds, stableBounds);
|
||||
if (orientationRespectedWithInsets
|
||||
&& handlesOrientationChangeFromDescendant(mOrientation)) {
|
||||
if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant(
|
||||
getOverrideOrientation())) {
|
||||
// No need to letterbox because of fixed orientation. Display will handle
|
||||
// fixed-orientation requests and a display rotation is enough to respect requested
|
||||
// orientation with insets applied.
|
||||
@@ -9003,7 +9038,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
}
|
||||
|
||||
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
|
||||
&& !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation())) {
|
||||
&& !ActivityInfo.isFixedOrientationPortrait(
|
||||
getOverrideOrientation())) {
|
||||
return info.getMinAspectRatio();
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
|
||||
DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
|
||||
super(wms);
|
||||
// TODO(display-area): move this up to ConfigurationContainer
|
||||
mOrientation = SCREEN_ORIENTATION_UNSET;
|
||||
setOverrideOrientation(SCREEN_ORIENTATION_UNSET);
|
||||
mType = type;
|
||||
mName = name;
|
||||
mFeatureId = featureId;
|
||||
@@ -165,7 +165,8 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
|
||||
// If this is set to ignore the orientation request, we don't propagate descendant
|
||||
// orientation request.
|
||||
final int orientation = requestingContainer != null
|
||||
? requestingContainer.mOrientation : SCREEN_ORIENTATION_UNSET;
|
||||
? requestingContainer.getOverrideOrientation()
|
||||
: SCREEN_ORIENTATION_UNSET;
|
||||
return !getIgnoreOrientationRequest(orientation)
|
||||
&& super.onDescendantOrientationChanged(requestingContainer);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
@@ -1576,7 +1577,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
// If display rotation class tells us that it doesn't consider app requested orientation,
|
||||
// this display won't rotate just because of an app changes its requested orientation. Thus
|
||||
// it indicates that this display chooses not to handle this request.
|
||||
final int orientation = requestingContainer != null ? requestingContainer.mOrientation
|
||||
final int orientation = requestingContainer != null
|
||||
? requestingContainer.getOverrideOrientation()
|
||||
: SCREEN_ORIENTATION_UNSET;
|
||||
final boolean handled = handlesOrientationChangeFromDescendant(orientation);
|
||||
if (config == null) {
|
||||
@@ -1702,14 +1704,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
if (mTransitionController.useShellTransitionsRotation()) {
|
||||
return ROTATION_UNDEFINED;
|
||||
}
|
||||
final int activityOrientation = r.getOverrideOrientation();
|
||||
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM
|
||||
|| getIgnoreOrientationRequest(r.mOrientation)) {
|
||||
|| getIgnoreOrientationRequest(activityOrientation)) {
|
||||
return ROTATION_UNDEFINED;
|
||||
}
|
||||
if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
|
||||
if (activityOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
|
||||
// TODO(b/266280737): Use ActivityRecord#canDefineOrientationForActivitiesAbove
|
||||
final ActivityRecord nextCandidate = getActivity(
|
||||
a -> a.mOrientation != SCREEN_ORIENTATION_UNSET
|
||||
&& a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
|
||||
a -> a.getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
|
||||
&& a.getOverrideOrientation()
|
||||
!= ActivityInfo.SCREEN_ORIENTATION_BEHIND,
|
||||
r, false /* includeBoundary */, true /* traverseTopToBottom */);
|
||||
if (nextCandidate != null) {
|
||||
r = nextCandidate;
|
||||
@@ -2727,6 +2732,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
final int orientation = super.getOrientation();
|
||||
|
||||
if (!handlesOrientationChangeFromDescendant(orientation)) {
|
||||
ActivityRecord topActivity = topRunningActivity(/* considerKeyguardState= */ true);
|
||||
if (topActivity != null && topActivity.mLetterboxUiController
|
||||
.shouldUseDisplayLandscapeNaturalOrientation()) {
|
||||
ProtoLog.v(WM_DEBUG_ORIENTATION,
|
||||
"Display id=%d is ignoring orientation request for %d, return %d"
|
||||
+ " following a per-app override for %s",
|
||||
mDisplayId, orientation, SCREEN_ORIENTATION_LANDSCAPE, topActivity);
|
||||
return SCREEN_ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
mLastOrientationSource = null;
|
||||
// Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
|
||||
ProtoLog.v(WM_DEBUG_ORIENTATION,
|
||||
|
||||
@@ -1859,8 +1859,9 @@ public class DisplayRotation {
|
||||
if (source != null) {
|
||||
mLastOrientationSource = source.toString();
|
||||
final WindowState w = source.asWindowState();
|
||||
mSourceOrientation =
|
||||
w != null ? w.mAttrs.screenOrientation : source.mOrientation;
|
||||
mSourceOrientation = w != null
|
||||
? w.mAttrs.screenOrientation
|
||||
: source.getOverrideOrientation();
|
||||
} else {
|
||||
mLastOrientationSource = null;
|
||||
mSourceOrientation = SCREEN_ORIENTATION_UNSET;
|
||||
|
||||
@@ -296,8 +296,8 @@ final class DisplayRotationCompatPolicy {
|
||||
&& activity.getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
|
||||
// "locked" and "nosensor" values are often used by camera apps that can't
|
||||
// handle dynamic changes so we shouldn't force rotate them.
|
||||
&& activity.getRequestedOrientation() != SCREEN_ORIENTATION_NOSENSOR
|
||||
&& activity.getRequestedOrientation() != SCREEN_ORIENTATION_LOCKED
|
||||
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
|
||||
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
|
||||
&& mCameraIdPackageBiMap.containsPackageName(activity.packageName)
|
||||
&& activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
|
||||
}
|
||||
|
||||
@@ -17,11 +17,21 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.pm.ActivityInfo.isFixedOrientation;
|
||||
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
|
||||
import static android.content.pm.ActivityInfo.screenOrientationToString;
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
@@ -29,6 +39,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
|
||||
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
|
||||
@@ -62,6 +74,9 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_RE
|
||||
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
|
||||
import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTypeToString;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.content.pm.ActivityInfo.ScreenOrientation;
|
||||
@@ -111,6 +126,34 @@ final class LetterboxUiController {
|
||||
*/
|
||||
private final float mExpandedTaskBarHeight;
|
||||
|
||||
// TODO(b/265576778): Cache other overrides as well.
|
||||
|
||||
// Corresponds to OVERRIDE_ANY_ORIENTATION
|
||||
private final boolean mIsOverrideAnyOrientationEnabled;
|
||||
// Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
|
||||
private final boolean mIsOverrideToPortraitOrientationEnabled;
|
||||
// Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
|
||||
private final boolean mIsOverrideToNosensorOrientationEnabled;
|
||||
// Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
|
||||
private final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
|
||||
// Corresponds to OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION
|
||||
private final boolean mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled;
|
||||
|
||||
// Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION
|
||||
private final boolean mIsOverrideCameraCompatDisableForceRotationEnabled;
|
||||
// Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH
|
||||
private final boolean mIsOverrideCameraCompatDisableRefreshEnabled;
|
||||
// Corresponds to OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE
|
||||
private final boolean mIsOverrideCameraCompatEnableRefreshViaPauseEnabled;
|
||||
|
||||
// Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
|
||||
private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
|
||||
|
||||
@Nullable
|
||||
private final Boolean mBooleanPropertyAllowOrientationOverride;
|
||||
@Nullable
|
||||
private final Boolean mBooleanPropertyAllowDisplayOrientationOverride;
|
||||
|
||||
/*
|
||||
* WindowContainerListener responsible to make translucent activities inherit
|
||||
* constraints from the first opaque activity beneath them. It's null for not
|
||||
@@ -193,6 +236,35 @@ final class LetterboxUiController {
|
||||
|
||||
mExpandedTaskBarHeight =
|
||||
getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height);
|
||||
|
||||
mBooleanPropertyAllowOrientationOverride =
|
||||
readComponentProperty(packageManager, mActivityRecord.packageName,
|
||||
/* gatingCondition */ null,
|
||||
PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
|
||||
mBooleanPropertyAllowDisplayOrientationOverride =
|
||||
readComponentProperty(packageManager, mActivityRecord.packageName,
|
||||
/* gatingCondition */ null,
|
||||
PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE);
|
||||
|
||||
mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
|
||||
mIsOverrideToPortraitOrientationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT);
|
||||
mIsOverrideToReverseLandscapeOrientationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
|
||||
mIsOverrideToNosensorOrientationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
|
||||
mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION);
|
||||
|
||||
mIsOverrideCameraCompatDisableForceRotationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION);
|
||||
mIsOverrideCameraCompatDisableRefreshEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH);
|
||||
mIsOverrideCameraCompatEnableRefreshViaPauseEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
|
||||
|
||||
mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
|
||||
isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,8 +279,8 @@ final class LetterboxUiController {
|
||||
*/
|
||||
@Nullable
|
||||
private static Boolean readComponentProperty(PackageManager packageManager, String packageName,
|
||||
BooleanSupplier gatingCondition, String propertyName) {
|
||||
if (!gatingCondition.getAsBoolean()) {
|
||||
@Nullable BooleanSupplier gatingCondition, String propertyName) {
|
||||
if (gatingCondition != null && !gatingCondition.getAsBoolean()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
@@ -262,7 +334,7 @@ final class LetterboxUiController {
|
||||
if (!shouldEnableWithOverrideAndProperty(
|
||||
/* gatingCondition */ mLetterboxConfiguration
|
||||
::isPolicyForIgnoringRequestedOrientationEnabled,
|
||||
OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION,
|
||||
mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
|
||||
mBooleanPropertyIgnoreRequestedOrientation)) {
|
||||
return false;
|
||||
}
|
||||
@@ -307,6 +379,66 @@ final class LetterboxUiController {
|
||||
mIsRefreshAfterRotationRequested = isRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether should fix display orientation to landscape natural orientation when a task is
|
||||
* fullscreen and the display is ignoring orientation requests.
|
||||
*
|
||||
* <p>This treatment is enabled when the following conditions are met:
|
||||
* <ul>
|
||||
* <li>Opt-out component property isn't enabled
|
||||
* <li>Opt-in per-app override is enabled
|
||||
* <li>Task is in fullscreen.
|
||||
* <li>{@link DisplayContent#getIgnoreOrientationRequest} is enabled
|
||||
* <li>Natural orientation of the display is landscape.
|
||||
* </ul>
|
||||
*/
|
||||
boolean shouldUseDisplayLandscapeNaturalOrientation() {
|
||||
return shouldEnableWithOptInOverrideAndOptOutProperty(
|
||||
/* gatingCondition */ () -> mActivityRecord.mDisplayContent != null
|
||||
&& mActivityRecord.getTask() != null
|
||||
&& mActivityRecord.mDisplayContent.getIgnoreOrientationRequest()
|
||||
&& !mActivityRecord.getTask().inMultiWindowMode()
|
||||
&& mActivityRecord.mDisplayContent.getNaturalOrientation()
|
||||
== ORIENTATION_LANDSCAPE,
|
||||
mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled,
|
||||
mBooleanPropertyAllowDisplayOrientationOverride);
|
||||
}
|
||||
|
||||
@ScreenOrientation
|
||||
int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
|
||||
if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
if (mIsOverrideToReverseLandscapeOrientationEnabled
|
||||
&& (isFixedOrientationLandscape(candidate) || mIsOverrideAnyOrientationEnabled)) {
|
||||
Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
|
||||
+ mActivityRecord + " is overridden to "
|
||||
+ screenOrientationToString(SCREEN_ORIENTATION_REVERSE_LANDSCAPE));
|
||||
return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
||||
}
|
||||
|
||||
if (!mIsOverrideAnyOrientationEnabled && isFixedOrientation(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
if (mIsOverrideToPortraitOrientationEnabled) {
|
||||
Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
|
||||
+ mActivityRecord + " is overridden to "
|
||||
+ screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT));
|
||||
return SCREEN_ORIENTATION_PORTRAIT;
|
||||
}
|
||||
|
||||
if (mIsOverrideToNosensorOrientationEnabled) {
|
||||
Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
|
||||
+ mActivityRecord + " is overridden to "
|
||||
+ screenOrientationToString(SCREEN_ORIENTATION_NOSENSOR));
|
||||
return SCREEN_ORIENTATION_NOSENSOR;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether activity is eligible for activity "refresh" after camera compat force rotation
|
||||
* treatment. See {@link DisplayRotationCompatPolicy} for context.
|
||||
@@ -322,7 +454,7 @@ final class LetterboxUiController {
|
||||
return shouldEnableWithOptOutOverrideAndProperty(
|
||||
/* gatingCondition */ () -> mLetterboxConfiguration
|
||||
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
|
||||
OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH,
|
||||
mIsOverrideCameraCompatDisableRefreshEnabled,
|
||||
mBooleanPropertyCameraCompatAllowRefresh);
|
||||
}
|
||||
|
||||
@@ -344,7 +476,7 @@ final class LetterboxUiController {
|
||||
return shouldEnableWithOverrideAndProperty(
|
||||
/* gatingCondition */ () -> mLetterboxConfiguration
|
||||
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
|
||||
OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
|
||||
mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
|
||||
mBooleanPropertyCameraCompatEnableRefreshViaPause);
|
||||
}
|
||||
|
||||
@@ -363,15 +495,19 @@ final class LetterboxUiController {
|
||||
return shouldEnableWithOptOutOverrideAndProperty(
|
||||
/* gatingCondition */ () -> mLetterboxConfiguration
|
||||
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
|
||||
OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION,
|
||||
mIsOverrideCameraCompatDisableForceRotationEnabled,
|
||||
mBooleanPropertyCameraCompatAllowForceRotation);
|
||||
}
|
||||
|
||||
private boolean isCompatChangeEnabled(long overrideChangeId) {
|
||||
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} when the following conditions are met:
|
||||
* <ul>
|
||||
* <li>{@code gatingCondition} isn't {@code false}
|
||||
* <li>OEM didn't opt out with a {@code overrideChangeId} override
|
||||
* <li>OEM didn't opt out with a per-app override
|
||||
* <li>App developers didn't opt out with a component {@code property}
|
||||
* </ul>
|
||||
*
|
||||
@@ -379,12 +515,30 @@ final class LetterboxUiController {
|
||||
* disabled on per-app basis by OEMs or app developers.
|
||||
*/
|
||||
private boolean shouldEnableWithOptOutOverrideAndProperty(BooleanSupplier gatingCondition,
|
||||
long overrideChangeId, Boolean property) {
|
||||
boolean isOverrideChangeEnabled, Boolean property) {
|
||||
if (!gatingCondition.getAsBoolean()) {
|
||||
return false;
|
||||
}
|
||||
return !Boolean.FALSE.equals(property)
|
||||
&& !mActivityRecord.info.isChangeEnabled(overrideChangeId);
|
||||
return !FALSE.equals(property) && !isOverrideChangeEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} when the following conditions are met:
|
||||
* <ul>
|
||||
* <li>{@code gatingCondition} isn't {@code false}
|
||||
* <li>OEM did opt in with a per-app override
|
||||
* <li>App developers didn't opt out with a component {@code property}
|
||||
* </ul>
|
||||
*
|
||||
* <p>This is used for the treatments that are enabled based with the heuristic but can be
|
||||
* disabled on per-app basis by OEMs or app developers.
|
||||
*/
|
||||
private boolean shouldEnableWithOptInOverrideAndOptOutProperty(BooleanSupplier gatingCondition,
|
||||
boolean isOverrideChangeEnabled, Boolean property) {
|
||||
if (!gatingCondition.getAsBoolean()) {
|
||||
return false;
|
||||
}
|
||||
return !FALSE.equals(property) && isOverrideChangeEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,21 +547,20 @@ final class LetterboxUiController {
|
||||
* <li>{@code gatingCondition} isn't {@code false}
|
||||
* <li>App developers didn't opt out with a component {@code property}
|
||||
* <li>App developers opted in with a component {@code property} or an OEM opted in with a
|
||||
* component {@code property}
|
||||
* per-app override
|
||||
* </ul>
|
||||
*
|
||||
* <p>This is used for the treatments that are enabled only on per-app basis.
|
||||
*/
|
||||
private boolean shouldEnableWithOverrideAndProperty(BooleanSupplier gatingCondition,
|
||||
long overrideChangeId, Boolean property) {
|
||||
boolean isOverrideChangeEnabled, Boolean property) {
|
||||
if (!gatingCondition.getAsBoolean()) {
|
||||
return false;
|
||||
}
|
||||
if (Boolean.FALSE.equals(property)) {
|
||||
if (FALSE.equals(property)) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.TRUE.equals(property)
|
||||
|| mActivityRecord.info.isChangeEnabled(overrideChangeId);
|
||||
return TRUE.equals(property) || isOverrideChangeEnabled;
|
||||
}
|
||||
|
||||
boolean hasWallpaperBackgroundForLetterbox() {
|
||||
@@ -1224,7 +1377,8 @@ final class LetterboxUiController {
|
||||
// To avoid wrong behaviour, we're not forcing orientation for activities with not
|
||||
// fixed orientation (e.g. permission dialogs).
|
||||
return hasInheritedLetterboxBehavior()
|
||||
&& mActivityRecord.mOrientation != SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
&& mActivityRecord.getOverrideOrientation()
|
||||
!= SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
}
|
||||
|
||||
float getInheritedMinAspectRatio() {
|
||||
|
||||
@@ -73,6 +73,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ActivityInfo.ScreenOrientation;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
@@ -178,8 +179,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
protected final WindowList<E> mChildren = new WindowList<E>();
|
||||
|
||||
// The specified orientation for this window container.
|
||||
@ActivityInfo.ScreenOrientation
|
||||
protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
// Shouldn't be accessed directly since subclasses can override getOverrideOrientation.
|
||||
@ScreenOrientation
|
||||
private int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
|
||||
/**
|
||||
* The window container which decides its orientation since the last time
|
||||
@@ -1427,19 +1429,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
|
||||
/**
|
||||
* Gets the configuration orientation by the requested screen orientation
|
||||
* ({@link ActivityInfo.ScreenOrientation}) of this activity.
|
||||
* ({@link ScreenOrientation}) of this activity.
|
||||
*
|
||||
* @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
|
||||
* {@link Configuration#ORIENTATION_PORTRAIT},
|
||||
* {@link Configuration#ORIENTATION_UNDEFINED}).
|
||||
*/
|
||||
@ScreenOrientation
|
||||
int getRequestedConfigurationOrientation() {
|
||||
return getRequestedConfigurationOrientation(false /* forDisplay */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration orientation by the requested screen orientation
|
||||
* ({@link ActivityInfo.ScreenOrientation}) of this activity.
|
||||
* ({@link ScreenOrientation}) of this activity.
|
||||
*
|
||||
* @param forDisplay whether it is the requested config orientation for display.
|
||||
* If {@code true}, we may reverse the requested orientation if the root is
|
||||
@@ -1450,8 +1453,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* {@link Configuration#ORIENTATION_PORTRAIT},
|
||||
* {@link Configuration#ORIENTATION_UNDEFINED}).
|
||||
*/
|
||||
@ScreenOrientation
|
||||
int getRequestedConfigurationOrientation(boolean forDisplay) {
|
||||
int requestedOrientation = mOrientation;
|
||||
int requestedOrientation = getOverrideOrientation();
|
||||
final RootDisplayArea root = getRootDisplayArea();
|
||||
if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
|
||||
// Reverse the requested orientation if the orientation of its root is different from
|
||||
@@ -1461,7 +1465,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
// (portrait).
|
||||
// When an app below the DAG is requesting landscape, it should actually request the
|
||||
// display to be portrait, so that the DAG and the app will be in landscape.
|
||||
requestedOrientation = reverseOrientation(mOrientation);
|
||||
requestedOrientation = reverseOrientation(getOverrideOrientation());
|
||||
}
|
||||
|
||||
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
|
||||
@@ -1486,7 +1490,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
*
|
||||
* @param orientation the specified orientation.
|
||||
*/
|
||||
void setOrientation(int orientation) {
|
||||
void setOrientation(@ScreenOrientation int orientation) {
|
||||
setOrientation(orientation, null /* requestingContainer */);
|
||||
}
|
||||
|
||||
@@ -1494,17 +1498,17 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* Sets the specified orientation of this container. It percolates this change upward along the
|
||||
* hierarchy to let each level of the hierarchy a chance to respond to it.
|
||||
*
|
||||
* @param orientation the specified orientation. Needs to be one of {@link
|
||||
* android.content.pm.ActivityInfo.ScreenOrientation}.
|
||||
* @param orientation the specified orientation. Needs to be one of {@link ScreenOrientation}.
|
||||
* @param requestingContainer the container which orientation request has changed. Mostly used
|
||||
* to ensure it gets correct configuration.
|
||||
*/
|
||||
void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) {
|
||||
if (mOrientation == orientation) {
|
||||
void setOrientation(@ScreenOrientation int orientation,
|
||||
@Nullable WindowContainer requestingContainer) {
|
||||
if (getOverrideOrientation() == orientation) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOrientation = orientation;
|
||||
setOverrideOrientation(orientation);
|
||||
final WindowContainer parent = getParent();
|
||||
if (parent != null) {
|
||||
if (getConfiguration().orientation != getRequestedConfigurationOrientation()
|
||||
@@ -1523,9 +1527,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
}
|
||||
}
|
||||
|
||||
@ActivityInfo.ScreenOrientation
|
||||
@ScreenOrientation
|
||||
int getOrientation() {
|
||||
return getOrientation(mOrientation);
|
||||
return getOrientation(getOverrideOrientation());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1539,7 +1543,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* better match.
|
||||
* @return The orientation as specified by this branch or the window hierarchy.
|
||||
*/
|
||||
int getOrientation(int candidate) {
|
||||
@ScreenOrientation
|
||||
int getOrientation(@ScreenOrientation int candidate) {
|
||||
mLastOrientationSource = null;
|
||||
if (!providesOrientation()) {
|
||||
return SCREEN_ORIENTATION_UNSET;
|
||||
@@ -1549,16 +1554,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
// specified; otherwise we prefer to use the orientation of its topmost child that has one
|
||||
// specified and fall back on this container's unset or unspecified value as a candidate
|
||||
// if none of the children have a better candidate for the orientation.
|
||||
if (mOrientation != SCREEN_ORIENTATION_UNSET
|
||||
&& mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||
if (getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
|
||||
&& getOverrideOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||
mLastOrientationSource = this;
|
||||
return mOrientation;
|
||||
return getOverrideOrientation();
|
||||
}
|
||||
|
||||
for (int i = mChildren.size() - 1; i >= 0; --i) {
|
||||
final WindowContainer wc = mChildren.get(i);
|
||||
|
||||
// TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
|
||||
// TODO: Maybe mOverrideOrientation should default to SCREEN_ORIENTATION_UNSET vs.
|
||||
// SCREEN_ORIENTATION_UNSPECIFIED?
|
||||
final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
|
||||
? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
|
||||
@@ -1589,6 +1594,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
return candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns orientation specified on this level of hierarchy without taking children into
|
||||
* account, like {@link #getOrientation} does, allowing subclasses to override. See {@link
|
||||
* ActivityRecord#getOverrideOrientation} for an example.
|
||||
*/
|
||||
@ScreenOrientation
|
||||
protected int getOverrideOrientation() {
|
||||
return mOverrideOrientation;
|
||||
}
|
||||
|
||||
protected void setOverrideOrientation(@ScreenOrientation int orientation) {
|
||||
mOverrideOrientation = orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The deepest source which decides the orientation of this window container since the
|
||||
* last time {@link #getOrientation(int) was called.
|
||||
@@ -2635,7 +2654,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
|
||||
final long token = proto.start(fieldId);
|
||||
super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
|
||||
proto.write(ORIENTATION, mOrientation);
|
||||
proto.write(ORIENTATION, mOverrideOrientation);
|
||||
proto.write(VISIBLE, isVisible);
|
||||
writeIdentifierToProto(proto, IDENTIFIER);
|
||||
if (mSurfaceAnimator.isAnimating()) {
|
||||
|
||||
@@ -1736,7 +1736,7 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
|
||||
// No need to apply rotation if the display ignores orientation request.
|
||||
doCallRealMethod().when(displayContent).rotationForActivityInDifferentOrientation(any());
|
||||
pinnedActivity.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
|
||||
pinnedActivity.setOverrideOrientation(SCREEN_ORIENTATION_LANDSCAPE);
|
||||
displayContent.setIgnoreOrientationRequest(true);
|
||||
assertEquals(WindowConfiguration.ROTATION_UNDEFINED,
|
||||
displayContent.rotationForActivityInDifferentOrientation(pinnedActivity));
|
||||
|
||||
@@ -16,14 +16,27 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
|
||||
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
|
||||
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
@@ -89,6 +102,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
|
||||
public TestRule compatChangeRule = new PlatformCompatChangeRule();
|
||||
|
||||
private ActivityRecord mActivity;
|
||||
private Task mTask;
|
||||
private DisplayContent mDisplayContent;
|
||||
private LetterboxUiController mController;
|
||||
private LetterboxConfiguration mLetterboxConfiguration;
|
||||
@@ -488,6 +502,130 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
// overrideOrientationIfNeeded
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
|
||||
public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsPortrait()
|
||||
throws Exception {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
|
||||
public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsNosensor() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_NOSENSOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
|
||||
public void testOverrideOrientationIfNeeded_nosensorOverride_orientationFixed_returnsUnchanged() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
|
||||
public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationPortraitOrUndefined_returnsUnchanged() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
|
||||
public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationLandscape_returnsReverseLandscape() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_LANDSCAPE),
|
||||
SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
|
||||
public void testOverrideOrientationIfNeeded_portraitOverride_orientationFixed_returnsUnchanged() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_NOSENSOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT, OVERRIDE_ANY_ORIENTATION})
|
||||
public void testOverrideOrientationIfNeeded_portraitAndIgnoreFixedOverrides_returnsPortrait() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR, OVERRIDE_ANY_ORIENTATION})
|
||||
public void testOverrideOrientationIfNeeded_noSensorAndIgnoreFixedOverrides_returnsNosensor() {
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_NOSENSOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
|
||||
public void testOverrideOrientationIfNeeded_propertyIsFalse_returnsUnchanged()
|
||||
throws Exception {
|
||||
mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false);
|
||||
|
||||
mController = new LetterboxUiController(mWm, mActivity);
|
||||
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
|
||||
// shouldUseDisplayLandscapeNaturalOrientation
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
|
||||
public void testShouldUseDisplayLandscapeNaturalOrientation_override_returnsTrue() {
|
||||
prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
|
||||
assertTrue(mController.shouldUseDisplayLandscapeNaturalOrientation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
|
||||
public void testShouldUseDisplayLandscapeNaturalOrientation_overrideAndFalseProperty_returnsFalse()
|
||||
throws Exception {
|
||||
mockThatProperty(PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE, /* value */ false);
|
||||
|
||||
mController = new LetterboxUiController(mWm, mActivity);
|
||||
|
||||
prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
|
||||
assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
|
||||
public void testShouldUseDisplayLandscapeNaturalOrientation_portraitNaturalOrientation_returnsFalse() {
|
||||
prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
|
||||
doReturn(ORIENTATION_PORTRAIT).when(mDisplayContent).getNaturalOrientation();
|
||||
|
||||
assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
|
||||
public void testShouldUseDisplayLandscapeNaturalOrientation_disabledIgnoreOrientationRequest_returnsFalse() {
|
||||
prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
|
||||
mDisplayContent.setIgnoreOrientationRequest(false);
|
||||
|
||||
assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
|
||||
public void testShouldUseDisplayLandscapeNaturalOrientation_inMultiWindowMode_returnsFalse() {
|
||||
prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
|
||||
|
||||
spyOn(mTask);
|
||||
doReturn(true).when(mTask).inMultiWindowMode();
|
||||
|
||||
assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
|
||||
}
|
||||
|
||||
private void mockThatProperty(String propertyName, boolean value) throws Exception {
|
||||
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
|
||||
/* className */ "");
|
||||
@@ -496,6 +634,12 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
|
||||
doReturn(property).when(pm).getProperty(eq(propertyName), anyString());
|
||||
}
|
||||
|
||||
private void prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation() {
|
||||
spyOn(mDisplayContent);
|
||||
doReturn(ORIENTATION_LANDSCAPE).when(mDisplayContent).getNaturalOrientation();
|
||||
mDisplayContent.setIgnoreOrientationRequest(true);
|
||||
}
|
||||
|
||||
private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
|
||||
doReturn(true).when(mLetterboxConfiguration)
|
||||
.isPolicyForIgnoringRequestedOrientationEnabled();
|
||||
@@ -505,10 +649,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
|
||||
private ActivityRecord setUpActivityWithComponent() {
|
||||
mDisplayContent = new TestDisplayContent
|
||||
.Builder(mAtm, /* dw */ 1000, /* dh */ 2000).build();
|
||||
Task task = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
|
||||
mTask = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setOnTop(true)
|
||||
.setTask(task)
|
||||
.setTask(mTask)
|
||||
// Set the component to be that of the test class in order to enable compat changes
|
||||
.setComponent(ComponentName.createRelative(mContext,
|
||||
com.android.server.wm.LetterboxUiControllerTest.class.getName()))
|
||||
|
||||
@@ -468,7 +468,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
mWm.setRecentsAnimationController(mController);
|
||||
spyOn(mDisplayContent.mFixedRotationTransitionListener);
|
||||
final ActivityRecord recents = mock(ActivityRecord.class);
|
||||
recents.mOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
recents.setOverrideOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
|
||||
doReturn(ORIENTATION_PORTRAIT).when(recents)
|
||||
.getRequestedConfigurationOrientation(anyBoolean());
|
||||
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recents);
|
||||
|
||||
@@ -1557,7 +1557,7 @@ public class WindowContainerTests extends WindowTestsBase {
|
||||
|
||||
@Override
|
||||
int getOrientation() {
|
||||
return getOrientation(super.mOrientation);
|
||||
return getOrientation(super.getOverrideOrientation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user