Merge "Move rotation methods to DisplayContent"
This commit is contained in:
committed by
Android (Google) Code Review
commit
51d7a8a866
@@ -73,18 +73,24 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
import static com.android.server.wm.WindowManagerService.CUSTOM_SCREEN_ROTATION;
|
||||
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
|
||||
import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
|
||||
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
|
||||
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
|
||||
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
|
||||
import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
|
||||
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
|
||||
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
|
||||
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
|
||||
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
|
||||
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
|
||||
import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
|
||||
import static com.android.server.wm.WindowManagerService.dipToPixel;
|
||||
import static com.android.server.wm.WindowManagerService.logSurface;
|
||||
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
|
||||
@@ -94,6 +100,7 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager.StackId;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.GraphicBuffer;
|
||||
@@ -113,6 +120,7 @@ import android.util.MutableBoolean;
|
||||
import android.util.Slog;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.InputDevice;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManagerPolicy;
|
||||
@@ -181,12 +189,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
private final DisplayInfo mDisplayInfo = new DisplayInfo();
|
||||
private final Display mDisplay;
|
||||
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
|
||||
/**
|
||||
* For default display it contains real metrics, empty for others.
|
||||
* @see WindowManagerService#createWatermarkInTransaction()
|
||||
*/
|
||||
final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
|
||||
/** @see #computeCompatSmallestWidth(boolean, int, int, int, int) */
|
||||
private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
|
||||
/**
|
||||
* Compat metrics computed based on {@link #mDisplayMetrics}.
|
||||
* @see #updateDisplayAndOrientation(int)
|
||||
*/
|
||||
private final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
|
||||
|
||||
/** The desired scaling factor for compatible apps. */
|
||||
float mCompatibleScreenScale;
|
||||
|
||||
/**
|
||||
* Current rotation of the display.
|
||||
* Constants as per {@link android.view.Surface.Rotation}.
|
||||
*
|
||||
* @see WindowManagerService#updateRotationUncheckedLocked(boolean, int)
|
||||
* @see #updateRotationUnchecked(boolean)
|
||||
*/
|
||||
private int mRotation = 0;
|
||||
/**
|
||||
@@ -200,7 +223,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
* Flag indicating that the application is receiving an orientation that has different metrics
|
||||
* than it expected. E.g. Portrait instead of Landscape.
|
||||
*
|
||||
* @see WindowManagerService#updateRotationUncheckedLocked(boolean, int)
|
||||
* @see #updateRotationUnchecked(boolean)
|
||||
*/
|
||||
private boolean mAltOrientation = false;
|
||||
/**
|
||||
@@ -218,7 +241,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
*/
|
||||
private int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
|
||||
Rect mBaseDisplayRect = new Rect();
|
||||
private Rect mBaseDisplayRect = new Rect();
|
||||
private Rect mContentRect = new Rect();
|
||||
|
||||
// Accessed directly by all users.
|
||||
@@ -828,6 +851,514 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
return mLastWindowForcedOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update rotation of the display.
|
||||
*
|
||||
* Returns true if the rotation has been changed. In this case YOU MUST CALL
|
||||
* {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
|
||||
*/
|
||||
boolean updateRotationUnchecked(boolean inTransaction) {
|
||||
if (mService.mDeferredRotationPauseCount > 0) {
|
||||
// Rotation updates have been paused temporarily. Defer the update until
|
||||
// updates have been resumed.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScreenRotationAnimation screenRotationAnimation =
|
||||
mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
|
||||
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
|
||||
// Rotation updates cannot be performed while the previous rotation change
|
||||
// animation is still in progress. Skip this update. We will try updating
|
||||
// again after the animation is finished and the display is unfrozen.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
|
||||
return false;
|
||||
}
|
||||
if (mService.mDisplayFrozen) {
|
||||
// Even if the screen rotation animation has finished (e.g. isAnimating
|
||||
// returns false), there is still some time where we haven't yet unfrozen
|
||||
// the display. We also need to abort rotation here.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
|
||||
"Deferring rotation, still finishing previous rotation");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mService.mDisplayEnabled) {
|
||||
// No point choosing a rotation if the display is not enabled.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final int oldRotation = mRotation;
|
||||
final int lastOrientation = mLastOrientation;
|
||||
final boolean oldAltOrientation = mAltOrientation;
|
||||
int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
|
||||
final boolean rotateSeamlessly;
|
||||
|
||||
if (mService.mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
|
||||
final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
|
||||
if (seamlessRotated != null) {
|
||||
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
|
||||
// to complete (that is, waiting for windows to redraw). It's tempting to check
|
||||
// w.mSeamlessRotationCount but that could be incorrect in the case of
|
||||
// window-removal.
|
||||
return false;
|
||||
}
|
||||
|
||||
final WindowState cantSeamlesslyRotate = getWindow((w) ->
|
||||
w.isChildWindow() && w.isVisibleNow()
|
||||
&& !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
|
||||
if (cantSeamlesslyRotate != null) {
|
||||
// In what can only be called an unfortunate workaround we require seamlessly
|
||||
// rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE flag. Due to
|
||||
// limitations in the client API, there is no way for the client to set this flag in
|
||||
// a race free fashion. If we seamlessly rotate a window which does not have this
|
||||
// flag, but then gains it, we will get an incorrect visual result
|
||||
// (rotated viewfinder). This means if we want to support seamlessly rotating
|
||||
// windows which could gain this flag, we can't rotate windows without it. This
|
||||
// limits seamless rotation in N to camera framework users, windows without
|
||||
// children, and native code. This is unfortunate but having the camera work is our
|
||||
// primary goal.
|
||||
rotateSeamlessly = false;
|
||||
} else {
|
||||
rotateSeamlessly = true;
|
||||
}
|
||||
} else {
|
||||
rotateSeamlessly = false;
|
||||
}
|
||||
|
||||
// TODO: Implement forced rotation changes.
|
||||
// Set mAltOrientation to indicate that the application is receiving
|
||||
// an orientation that has different metrics than it expected.
|
||||
// eg. Portrait instead of Landscape.
|
||||
|
||||
final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw(
|
||||
lastOrientation, rotation);
|
||||
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
|
||||
+ ", got rotation " + rotation + " which has "
|
||||
+ (altOrientation ? "incompatible" : "compatible") + " metrics");
|
||||
|
||||
if (oldRotation == rotation && oldAltOrientation == altOrientation) {
|
||||
// No change.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
|
||||
+ (altOrientation ? " (alt)" : "") + " from " + oldRotation
|
||||
+ (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
|
||||
|
||||
if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
|
||||
mService.mWaitingForConfig = true;
|
||||
}
|
||||
|
||||
mRotation = rotation;
|
||||
mAltOrientation = altOrientation;
|
||||
if (isDefaultDisplay) {
|
||||
mService.mPolicy.setRotationLw(rotation);
|
||||
}
|
||||
|
||||
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
|
||||
mService.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
|
||||
mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
|
||||
WINDOW_FREEZE_TIMEOUT_DURATION);
|
||||
|
||||
setLayoutNeeded();
|
||||
final int[] anim = new int[2];
|
||||
if (isDimming()) {
|
||||
anim[0] = anim[1] = 0;
|
||||
} else {
|
||||
mService.mPolicy.selectRotationAnimationLw(anim);
|
||||
}
|
||||
|
||||
if (!rotateSeamlessly) {
|
||||
mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
|
||||
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
|
||||
screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
|
||||
mDisplayId);
|
||||
} else {
|
||||
// The screen rotation animation uses a screenshot to freeze the screen
|
||||
// while windows resize underneath.
|
||||
// When we are rotating seamlessly, we allow the elements to transition
|
||||
// to their rotated state independently and without a freeze required.
|
||||
screenRotationAnimation = null;
|
||||
|
||||
// We have to reset this in case a window was removed before it
|
||||
// finished seamless rotation.
|
||||
mService.mSeamlessRotationCount = 0;
|
||||
}
|
||||
|
||||
// We need to update our screen size information to match the new rotation. If the rotation
|
||||
// has actually changed then this method will return true and, according to the comment at
|
||||
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
|
||||
// By updating the Display info here it will be available to
|
||||
// #computeScreenConfiguration() later.
|
||||
updateDisplayAndOrientation(getConfiguration().uiMode);
|
||||
|
||||
if (!inTransaction) {
|
||||
if (SHOW_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
|
||||
}
|
||||
mService.openSurfaceTransaction();
|
||||
}
|
||||
try {
|
||||
// NOTE: We disable the rotation in the emulator because
|
||||
// it doesn't support hardware OpenGL emulation yet.
|
||||
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
|
||||
&& screenRotationAnimation.hasScreenshot()) {
|
||||
if (screenRotationAnimation.setRotationInTransaction(
|
||||
rotation, mService.mFxSession,
|
||||
MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
|
||||
mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
|
||||
mService.scheduleAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
if (rotateSeamlessly) {
|
||||
forAllWindows(w -> {
|
||||
w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
|
||||
}, true /* traverseTopToBottom */);
|
||||
}
|
||||
|
||||
mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
|
||||
} finally {
|
||||
if (!inTransaction) {
|
||||
mService.closeSurfaceTransaction();
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forAllWindows(w -> {
|
||||
// Discard surface after orientation change, these can't be reused.
|
||||
if (w.mAppToken != null) {
|
||||
w.mAppToken.destroySavedSurfaces();
|
||||
}
|
||||
if (w.mHasSurface && !rotateSeamlessly) {
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
|
||||
w.mOrientationChanging = true;
|
||||
mService.mRoot.mOrientationChangeComplete = false;
|
||||
w.mLastFreezeDuration = 0;
|
||||
}
|
||||
w.mReportOrientationChanged = true;
|
||||
}, true /* traverseTopToBottom */);
|
||||
|
||||
if (rotateSeamlessly) {
|
||||
mService.mH.removeMessages(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT);
|
||||
mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
|
||||
SEAMLESS_ROTATION_TIMEOUT_DURATION);
|
||||
}
|
||||
|
||||
for (int i = mService.mRotationWatchers.size() - 1; i >= 0; i--) {
|
||||
final WindowManagerService.RotationWatcher rotationWatcher
|
||||
= mService.mRotationWatchers.get(i);
|
||||
if (rotationWatcher.mDisplayId == mDisplayId) {
|
||||
try {
|
||||
rotationWatcher.mWatcher.onRotationChanged(rotation);
|
||||
} catch (RemoteException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (multi-display): Magnification is supported only for the default display.
|
||||
// Announce rotation only if we will not animate as we already have the
|
||||
// windows in final state. Otherwise, we make this call at the rotation end.
|
||||
if (screenRotationAnimation == null && mService.mAccessibilityController != null
|
||||
&& isDefaultDisplay) {
|
||||
mService.mAccessibilityController.onRotationChangedLocked(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update {@link #mDisplayInfo} and other internal variables when display is rotated or config
|
||||
* changed.
|
||||
* Do not call if {@link WindowManagerService#mDisplayReady} == false.
|
||||
*/
|
||||
private DisplayInfo updateDisplayAndOrientation(int uiMode) {
|
||||
// Use the effective "visual" dimensions based on current rotation
|
||||
final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
|
||||
final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
|
||||
final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
|
||||
int dw = realdw;
|
||||
int dh = realdh;
|
||||
|
||||
if (mAltOrientation) {
|
||||
if (realdw > realdh) {
|
||||
// Turn landscape into portrait.
|
||||
int maxw = (int)(realdh/1.3f);
|
||||
if (maxw < realdw) {
|
||||
dw = maxw;
|
||||
}
|
||||
} else {
|
||||
// Turn portrait into landscape.
|
||||
int maxh = (int)(realdw/1.3f);
|
||||
if (maxh < realdh) {
|
||||
dh = maxh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update application display metrics.
|
||||
final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
|
||||
mDisplayId);
|
||||
final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
|
||||
mDisplayId);
|
||||
mDisplayInfo.rotation = mRotation;
|
||||
mDisplayInfo.logicalWidth = dw;
|
||||
mDisplayInfo.logicalHeight = dh;
|
||||
mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
|
||||
mDisplayInfo.appWidth = appWidth;
|
||||
mDisplayInfo.appHeight = appHeight;
|
||||
if (isDefaultDisplay) {
|
||||
mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
|
||||
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||||
}
|
||||
mDisplayInfo.getAppMetrics(mDisplayMetrics);
|
||||
if (mDisplayScalingDisabled) {
|
||||
mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
|
||||
} else {
|
||||
mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
|
||||
}
|
||||
|
||||
mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
|
||||
mDisplayInfo);
|
||||
|
||||
mBaseDisplayRect.set(0, 0, dw, dh);
|
||||
|
||||
if (isDefaultDisplay) {
|
||||
mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
|
||||
mCompatDisplayMetrics);
|
||||
}
|
||||
return mDisplayInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute display configuration based on display properties and policy settings.
|
||||
* Do not call if mDisplayReady == false.
|
||||
*/
|
||||
void computeScreenConfiguration(Configuration config) {
|
||||
final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode);
|
||||
|
||||
final int dw = displayInfo.logicalWidth;
|
||||
final int dh = displayInfo.logicalHeight;
|
||||
config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
config.screenWidthDp =
|
||||
(int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
|
||||
config.uiMode, mDisplayId) / mDisplayMetrics.density);
|
||||
config.screenHeightDp =
|
||||
(int)(mService.mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
|
||||
config.uiMode, mDisplayId) / mDisplayMetrics.density);
|
||||
final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
|
||||
|| displayInfo.rotation == Surface.ROTATION_270);
|
||||
|
||||
computeSizeRangesAndScreenLayout(displayInfo, mDisplayId, rotated, config.uiMode, dw, dh,
|
||||
mDisplayMetrics.density, config);
|
||||
|
||||
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
|
||||
| ((displayInfo.flags & Display.FLAG_ROUND) != 0
|
||||
? Configuration.SCREENLAYOUT_ROUND_YES
|
||||
: Configuration.SCREENLAYOUT_ROUND_NO);
|
||||
|
||||
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
|
||||
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
|
||||
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
|
||||
dh, mDisplayId);
|
||||
config.densityDpi = displayInfo.logicalDensityDpi;
|
||||
|
||||
config.colorMode =
|
||||
(displayInfo.isHdr()
|
||||
? Configuration.COLOR_MODE_HDR_YES
|
||||
: Configuration.COLOR_MODE_HDR_NO)
|
||||
| (displayInfo.isWideColorGamut()
|
||||
? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
|
||||
: Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
|
||||
|
||||
// Update the configuration based on available input devices, lid switch,
|
||||
// and platform configuration.
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
|
||||
config.keyboard = Configuration.KEYBOARD_NOKEYS;
|
||||
config.navigation = Configuration.NAVIGATION_NONAV;
|
||||
|
||||
int keyboardPresence = 0;
|
||||
int navigationPresence = 0;
|
||||
final InputDevice[] devices = mService.mInputManager.getInputDevices();
|
||||
final int len = devices != null ? devices.length : 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
InputDevice device = devices[i];
|
||||
if (!device.isVirtual()) {
|
||||
final int sources = device.getSources();
|
||||
final int presenceFlag = device.isExternal() ?
|
||||
WindowManagerPolicy.PRESENCE_EXTERNAL :
|
||||
WindowManagerPolicy.PRESENCE_INTERNAL;
|
||||
|
||||
// TODO(multi-display): Configure on per-display basis.
|
||||
if (mService.mIsTouchDevice) {
|
||||
if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
|
||||
InputDevice.SOURCE_TOUCHSCREEN) {
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
|
||||
}
|
||||
} else {
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
|
||||
}
|
||||
|
||||
if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
|
||||
config.navigation = Configuration.NAVIGATION_TRACKBALL;
|
||||
navigationPresence |= presenceFlag;
|
||||
} else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
|
||||
&& config.navigation == Configuration.NAVIGATION_NONAV) {
|
||||
config.navigation = Configuration.NAVIGATION_DPAD;
|
||||
navigationPresence |= presenceFlag;
|
||||
}
|
||||
|
||||
if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
||||
config.keyboard = Configuration.KEYBOARD_QWERTY;
|
||||
keyboardPresence |= presenceFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.navigation == Configuration.NAVIGATION_NONAV && mService.mHasPermanentDpad) {
|
||||
config.navigation = Configuration.NAVIGATION_DPAD;
|
||||
navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
|
||||
}
|
||||
|
||||
// Determine whether a hard keyboard is available and enabled.
|
||||
// TODO(multi-display): Should the hardware keyboard be tied to a display or to a device?
|
||||
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
|
||||
if (hardKeyboardAvailable != mService.mHardKeyboardAvailable) {
|
||||
mService.mHardKeyboardAvailable = hardKeyboardAvailable;
|
||||
mService.mH.removeMessages(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
|
||||
mService.mH.sendEmptyMessage(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
|
||||
}
|
||||
|
||||
// Let the policy update hidden states.
|
||||
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
|
||||
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
|
||||
config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
|
||||
mService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
|
||||
}
|
||||
|
||||
private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
|
||||
int displayId) {
|
||||
mTmpDisplayMetrics.setTo(mDisplayMetrics);
|
||||
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
|
||||
final int unrotDw, unrotDh;
|
||||
if (rotated) {
|
||||
unrotDw = dh;
|
||||
unrotDh = dw;
|
||||
} else {
|
||||
unrotDw = dw;
|
||||
unrotDh = dh;
|
||||
}
|
||||
int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
|
||||
displayId);
|
||||
return sw;
|
||||
}
|
||||
|
||||
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
|
||||
DisplayMetrics dm, int dw, int dh, int displayId) {
|
||||
dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
|
||||
displayId);
|
||||
dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
|
||||
uiMode, displayId);
|
||||
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
|
||||
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
|
||||
if (curSize == 0 || size < curSize) {
|
||||
curSize = size;
|
||||
}
|
||||
return curSize;
|
||||
}
|
||||
|
||||
private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
|
||||
boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
|
||||
|
||||
// We need to determine the smallest width that will occur under normal
|
||||
// operation. To this, start with the base screen size and compute the
|
||||
// width under the different possible rotations. We need to un-rotate
|
||||
// the current screen dimensions before doing this.
|
||||
int unrotDw, unrotDh;
|
||||
if (rotated) {
|
||||
unrotDw = dh;
|
||||
unrotDh = dw;
|
||||
} else {
|
||||
unrotDw = dw;
|
||||
unrotDh = dh;
|
||||
}
|
||||
displayInfo.smallestNominalAppWidth = 1<<30;
|
||||
displayInfo.smallestNominalAppHeight = 1<<30;
|
||||
displayInfo.largestNominalAppWidth = 0;
|
||||
displayInfo.largestNominalAppHeight = 0;
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
|
||||
unrotDh);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
|
||||
unrotDw);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
|
||||
unrotDh);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
|
||||
unrotDw);
|
||||
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
|
||||
displayId);
|
||||
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
|
||||
outConfig.screenLayout = sl;
|
||||
}
|
||||
|
||||
private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
|
||||
int uiMode, int displayId) {
|
||||
// Get the app screen size at this rotation.
|
||||
int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
|
||||
int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
|
||||
|
||||
// Compute the screen layout size class for this rotation.
|
||||
int longSize = w;
|
||||
int shortSize = h;
|
||||
if (longSize < shortSize) {
|
||||
int tmp = longSize;
|
||||
longSize = shortSize;
|
||||
shortSize = tmp;
|
||||
}
|
||||
longSize = (int)(longSize/density);
|
||||
shortSize = (int)(shortSize/density);
|
||||
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
|
||||
}
|
||||
|
||||
private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
|
||||
int uiMode, int dw, int dh) {
|
||||
final int width = mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
|
||||
displayId);
|
||||
if (width < displayInfo.smallestNominalAppWidth) {
|
||||
displayInfo.smallestNominalAppWidth = width;
|
||||
}
|
||||
if (width > displayInfo.largestNominalAppWidth) {
|
||||
displayInfo.largestNominalAppWidth = width;
|
||||
}
|
||||
final int height = mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode,
|
||||
displayId);
|
||||
if (height < displayInfo.smallestNominalAppHeight) {
|
||||
displayInfo.smallestNominalAppHeight = height;
|
||||
}
|
||||
if (height > displayInfo.largestNominalAppHeight) {
|
||||
displayInfo.largestNominalAppHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
DockedStackDividerController getDockedDividerController() {
|
||||
return mDividerControllerLocked;
|
||||
}
|
||||
|
||||
@@ -55,13 +55,11 @@ import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
|
||||
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
|
||||
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
|
||||
@@ -740,7 +738,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
|
||||
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
|
||||
// TODO(multi-display): Update rotation for different displays separately.
|
||||
final int displayId = defaultDisplay.getDisplayId();
|
||||
if (mService.updateRotationUncheckedLocked(false, displayId)) {
|
||||
if (defaultDisplay.updateRotationUnchecked(false /* inTransaction */)) {
|
||||
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
|
||||
} else {
|
||||
mUpdateRotation = false;
|
||||
|
||||
@@ -111,7 +111,6 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -592,11 +591,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
boolean mIsTouchDevice;
|
||||
|
||||
final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
|
||||
final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
|
||||
final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
|
||||
final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
|
||||
|
||||
final H mH = new H();
|
||||
|
||||
final Choreographer mChoreographer = Choreographer.getInstance();
|
||||
@@ -841,9 +835,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
final Configuration mTempConfiguration = new Configuration();
|
||||
|
||||
// The desired scaling factor for compatible apps.
|
||||
float mCompatibleScreenScale;
|
||||
|
||||
// If true, only the core apps and services are being launched because the device
|
||||
// is in a special boot mode, such as being encrypted or waiting for a decryption password.
|
||||
// For example, when this flag is true, there will be no wallpaper service.
|
||||
@@ -2461,10 +2452,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// to keep override configs clear of non-empty values (e.g. fontSize).
|
||||
mTempConfiguration.unset();
|
||||
mTempConfiguration.updateFrom(currentConfig);
|
||||
computeScreenConfigurationLocked(mTempConfiguration, displayId);
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
|
||||
displayContent.computeScreenConfiguration(mTempConfiguration);
|
||||
if (currentConfig.diff(mTempConfiguration) != 0) {
|
||||
mWaitingForConfig = true;
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
|
||||
displayContent.setLayoutNeeded();
|
||||
int anim[] = new int[2];
|
||||
if (displayContent.isDimming()) {
|
||||
@@ -2505,7 +2496,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
if (dc.isDefaultDisplay) {
|
||||
mPolicy.setCurrentOrientationLw(req);
|
||||
}
|
||||
if (updateRotationUncheckedLocked(inTransaction, displayId)) {
|
||||
if (dc.updateRotationUnchecked(inTransaction)) {
|
||||
// changed
|
||||
return true;
|
||||
}
|
||||
@@ -3843,10 +3834,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
mDeferredRotationPauseCount -= 1;
|
||||
if (mDeferredRotationPauseCount == 0) {
|
||||
// TODO(multi-display): Update rotation for different displays separately.
|
||||
final int displayId = DEFAULT_DISPLAY;
|
||||
final boolean changed = updateRotationUncheckedLocked(false, displayId);
|
||||
final DisplayContent displayContent = getDefaultDisplayContentLocked();
|
||||
final boolean changed = displayContent.updateRotationUnchecked(
|
||||
false /* inTransaction */);
|
||||
if (changed) {
|
||||
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
|
||||
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3862,9 +3855,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
try {
|
||||
final boolean rotationChanged;
|
||||
// TODO(multi-display): Update rotation for different displays separately.
|
||||
int displayId = DEFAULT_DISPLAY;
|
||||
final DisplayContent displayContent = getDefaultDisplayContentLocked();
|
||||
synchronized (mWindowMap) {
|
||||
rotationChanged = updateRotationUncheckedLocked(false, displayId);
|
||||
rotationChanged = displayContent.updateRotationUnchecked(
|
||||
false /* inTransaction */);
|
||||
if (!rotationChanged || forceRelayout) {
|
||||
getDefaultDisplayContentLocked().setLayoutNeeded();
|
||||
mWindowPlacerLocked.performSurfacePlacement();
|
||||
@@ -3872,234 +3866,13 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
|
||||
if (rotationChanged || alwaysSendConfiguration) {
|
||||
sendNewConfiguration(displayId);
|
||||
sendNewConfiguration(displayContent.getDisplayId());
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(multidisplay): Rotate any display? Move to DisplayContent
|
||||
/**
|
||||
* Updates the current rotation of the specified display.
|
||||
*
|
||||
* Returns true if the rotation has been changed. In this case YOU MUST CALL
|
||||
* {@link #sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
|
||||
*/
|
||||
boolean updateRotationUncheckedLocked(boolean inTransaction, int displayId) {
|
||||
if (mDeferredRotationPauseCount > 0) {
|
||||
// Rotation updates have been paused temporarily. Defer the update until
|
||||
// updates have been resumed.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScreenRotationAnimation screenRotationAnimation =
|
||||
mAnimator.getScreenRotationAnimationLocked(displayId);
|
||||
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
|
||||
// Rotation updates cannot be performed while the previous rotation change
|
||||
// animation is still in progress. Skip this update. We will try updating
|
||||
// again after the animation is finished and the display is unfrozen.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
|
||||
return false;
|
||||
}
|
||||
if (mDisplayFrozen) {
|
||||
// Even if the screen rotation animation has finished (e.g. isAnimating
|
||||
// returns false), there is still some time where we haven't yet unfrozen
|
||||
// the display. We also need to abort rotation here.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
|
||||
"Deferring rotation, still finishing previous rotation");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mDisplayEnabled) {
|
||||
// No point choosing a rotation if the display is not enabled.
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final DisplayContent dc = mRoot.getDisplayContent(displayId);
|
||||
|
||||
final int oldRotation = dc.getRotation();
|
||||
final int lastOrientation = dc.getLastOrientation();
|
||||
final boolean oldAltOrientation = dc.getAltOrientation();
|
||||
int rotation = mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
|
||||
final boolean rotateSeamlessly;
|
||||
|
||||
if (mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
|
||||
final WindowState seamlessRotated = dc.getWindow((w) -> w.mSeamlesslyRotated);
|
||||
if (seamlessRotated != null) {
|
||||
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
|
||||
// to complete (that is, waiting for windows to redraw). It's tempting to check
|
||||
// w.mSeamlessRotationCount but that could be incorrect in the case of
|
||||
// window-removal.
|
||||
return false;
|
||||
}
|
||||
|
||||
final WindowState cantSeamlesslyRotate = dc.getWindow((w) ->
|
||||
w.isChildWindow() && w.isVisibleNow()
|
||||
&& !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
|
||||
if (cantSeamlesslyRotate != null) {
|
||||
// In what can only be called an unfortunate workaround we require seamlessly
|
||||
// rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE flag. Due to
|
||||
// limitations in the client API, there is no way for the client to set this flag in
|
||||
// a race free fashion. If we seamlessly rotate a window which does not have this
|
||||
// flag, but then gains it, we will get an incorrect visual result
|
||||
// (rotated viewfinder). This means if we want to support seamlessly rotating
|
||||
// windows which could gain this flag, we can't rotate windows without it. This
|
||||
// limits seamless rotation in N to camera framework users, windows without
|
||||
// children, and native code. This is unfortunate but having the camera work is our
|
||||
// primary goal.
|
||||
rotateSeamlessly = false;
|
||||
} else {
|
||||
rotateSeamlessly = true;
|
||||
}
|
||||
} else {
|
||||
rotateSeamlessly = false;
|
||||
}
|
||||
|
||||
// TODO: Implement forced rotation changes.
|
||||
// Set mAltOrientation to indicate that the application is receiving
|
||||
// an orientation that has different metrics than it expected.
|
||||
// eg. Portrait instead of Landscape.
|
||||
|
||||
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(lastOrientation, rotation);
|
||||
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
|
||||
+ ", got rotation " + rotation + " which has "
|
||||
+ (altOrientation ? "incompatible" : "compatible") + " metrics");
|
||||
|
||||
if (oldRotation == rotation && oldAltOrientation == altOrientation) {
|
||||
// No change.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
|
||||
+ (altOrientation ? " (alt)" : "") + " from " + oldRotation
|
||||
+ (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
|
||||
|
||||
if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
|
||||
mWaitingForConfig = true;
|
||||
}
|
||||
|
||||
dc.setRotation(rotation);
|
||||
dc.setAltOrientation(altOrientation);
|
||||
if (dc.isDefaultDisplay) {
|
||||
mPolicy.setRotationLw(rotation);
|
||||
}
|
||||
|
||||
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
|
||||
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
|
||||
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
|
||||
|
||||
dc.setLayoutNeeded();
|
||||
final int[] anim = new int[2];
|
||||
if (dc.isDimming()) {
|
||||
anim[0] = anim[1] = 0;
|
||||
} else {
|
||||
mPolicy.selectRotationAnimationLw(anim);
|
||||
}
|
||||
|
||||
if (!rotateSeamlessly) {
|
||||
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
|
||||
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
|
||||
screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId);
|
||||
} else {
|
||||
// The screen rotation animation uses a screenshot to freeze the screen
|
||||
// while windows resize underneath.
|
||||
// When we are rotating seamlessly, we allow the elements to transition
|
||||
// to their rotated state independently and without a freeze required.
|
||||
screenRotationAnimation = null;
|
||||
|
||||
// We have to reset this in case a window was removed before it
|
||||
// finished seamless rotation.
|
||||
mSeamlessRotationCount = 0;
|
||||
}
|
||||
|
||||
// We need to update our screen size information to match the new rotation. If the rotation
|
||||
// has actually changed then this method will return true and, according to the comment at
|
||||
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
|
||||
// By updating the Display info here it will be available to
|
||||
// computeScreenConfigurationLocked later.
|
||||
updateDisplayAndOrientationLocked(dc.getConfiguration().uiMode, displayId);
|
||||
|
||||
final DisplayInfo displayInfo = dc.getDisplayInfo();
|
||||
if (!inTransaction) {
|
||||
if (SHOW_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
|
||||
}
|
||||
openSurfaceTransaction();
|
||||
}
|
||||
try {
|
||||
// NOTE: We disable the rotation in the emulator because
|
||||
// it doesn't support hardware OpenGL emulation yet.
|
||||
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
|
||||
&& screenRotationAnimation.hasScreenshot()) {
|
||||
if (screenRotationAnimation.setRotationInTransaction(
|
||||
rotation, mFxSession,
|
||||
MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(),
|
||||
displayInfo.logicalWidth, displayInfo.logicalHeight)) {
|
||||
scheduleAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
if (rotateSeamlessly) {
|
||||
dc.forAllWindows(w -> {
|
||||
w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
|
||||
}, true /* traverseTopToBottom */);
|
||||
}
|
||||
|
||||
mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
|
||||
} finally {
|
||||
if (!inTransaction) {
|
||||
closeSurfaceTransaction();
|
||||
if (SHOW_LIGHT_TRANSACTIONS) {
|
||||
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dc.forAllWindows(w -> {
|
||||
// Discard surface after orientation change, these can't be reused.
|
||||
if (w.mAppToken != null) {
|
||||
w.mAppToken.destroySavedSurfaces();
|
||||
}
|
||||
if (w.mHasSurface && !rotateSeamlessly) {
|
||||
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
|
||||
w.mOrientationChanging = true;
|
||||
mRoot.mOrientationChangeComplete = false;
|
||||
w.mLastFreezeDuration = 0;
|
||||
}
|
||||
w.mReportOrientationChanged = true;
|
||||
}, true /* traverseTopToBottom */);
|
||||
|
||||
if (rotateSeamlessly) {
|
||||
mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
|
||||
mH.sendEmptyMessageDelayed(H.SEAMLESS_ROTATION_TIMEOUT, SEAMLESS_ROTATION_TIMEOUT_DURATION);
|
||||
}
|
||||
|
||||
for (int i = mRotationWatchers.size() - 1; i >= 0; i--) {
|
||||
final RotationWatcher rotationWatcher = mRotationWatchers.get(i);
|
||||
if (rotationWatcher.mDisplayId == displayId) {
|
||||
try {
|
||||
rotationWatcher.mWatcher.onRotationChanged(rotation);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (multidisplay): Magnification is supported only for the default display.
|
||||
// Announce rotation only if we will not animate as we already have the
|
||||
// windows in final state. Otherwise, we make this call at the rotation end.
|
||||
if (screenRotationAnimation == null && mAccessibilityController != null
|
||||
&& dc.getDisplayId() == DEFAULT_DISPLAY) {
|
||||
mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultDisplayRotation() {
|
||||
synchronized (mWindowMap) {
|
||||
@@ -4572,7 +4345,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// Something changed (E.g. device rotation), but no configuration update is needed.
|
||||
// E.g. changing device rotation by 180 degrees. Go ahead and perform surface
|
||||
// placement to unfreeze the display since we froze it when the rotation was updated
|
||||
// in updateRotationUncheckedLocked.
|
||||
// in DisplayContent#updateRotationUnchecked.
|
||||
synchronized (mWindowMap) {
|
||||
if (mWaitingForConfig) {
|
||||
mWaitingForConfig = false;
|
||||
@@ -4597,297 +4370,9 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
return null;
|
||||
}
|
||||
final Configuration config = new Configuration();
|
||||
computeScreenConfigurationLocked(config, displayId);
|
||||
return config;
|
||||
}
|
||||
|
||||
private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
|
||||
int uiMode, int dw, int dh) {
|
||||
final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode, displayId);
|
||||
if (width < displayInfo.smallestNominalAppWidth) {
|
||||
displayInfo.smallestNominalAppWidth = width;
|
||||
}
|
||||
if (width > displayInfo.largestNominalAppWidth) {
|
||||
displayInfo.largestNominalAppWidth = width;
|
||||
}
|
||||
final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode, displayId);
|
||||
if (height < displayInfo.smallestNominalAppHeight) {
|
||||
displayInfo.smallestNominalAppHeight = height;
|
||||
}
|
||||
if (height > displayInfo.largestNominalAppHeight) {
|
||||
displayInfo.largestNominalAppHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
private int reduceConfigLayout(int curLayout, int rotation, float density,
|
||||
int dw, int dh, int uiMode, int displayId) {
|
||||
// Get the app screen size at this rotation.
|
||||
int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
|
||||
int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
|
||||
|
||||
// Compute the screen layout size class for this rotation.
|
||||
int longSize = w;
|
||||
int shortSize = h;
|
||||
if (longSize < shortSize) {
|
||||
int tmp = longSize;
|
||||
longSize = shortSize;
|
||||
shortSize = tmp;
|
||||
}
|
||||
longSize = (int)(longSize/density);
|
||||
shortSize = (int)(shortSize/density);
|
||||
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
|
||||
}
|
||||
|
||||
private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
|
||||
boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
|
||||
|
||||
// We need to determine the smallest width that will occur under normal
|
||||
// operation. To this, start with the base screen size and compute the
|
||||
// width under the different possible rotations. We need to un-rotate
|
||||
// the current screen dimensions before doing this.
|
||||
int unrotDw, unrotDh;
|
||||
if (rotated) {
|
||||
unrotDw = dh;
|
||||
unrotDh = dw;
|
||||
} else {
|
||||
unrotDw = dw;
|
||||
unrotDh = dh;
|
||||
}
|
||||
displayInfo.smallestNominalAppWidth = 1<<30;
|
||||
displayInfo.smallestNominalAppHeight = 1<<30;
|
||||
displayInfo.largestNominalAppWidth = 0;
|
||||
displayInfo.largestNominalAppHeight = 0;
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
|
||||
unrotDh);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
|
||||
unrotDw);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
|
||||
unrotDh);
|
||||
adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
|
||||
unrotDw);
|
||||
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
|
||||
displayId);
|
||||
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
|
||||
displayId);
|
||||
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
|
||||
outConfig.screenLayout = sl;
|
||||
}
|
||||
|
||||
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
|
||||
DisplayMetrics dm, int dw, int dh, int displayId) {
|
||||
dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
|
||||
displayId);
|
||||
dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
|
||||
displayId);
|
||||
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
|
||||
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
|
||||
if (curSize == 0 || size < curSize) {
|
||||
curSize = size;
|
||||
}
|
||||
return curSize;
|
||||
}
|
||||
|
||||
private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw,
|
||||
int dh, int displayId) {
|
||||
mTmpDisplayMetrics.setTo(dm);
|
||||
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
|
||||
final int unrotDw, unrotDh;
|
||||
if (rotated) {
|
||||
unrotDw = dh;
|
||||
unrotDh = dw;
|
||||
} else {
|
||||
unrotDw = dw;
|
||||
unrotDh = dh;
|
||||
}
|
||||
int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
|
||||
displayId);
|
||||
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
|
||||
displayId);
|
||||
return sw;
|
||||
}
|
||||
|
||||
/** Do not call if mDisplayReady == false */
|
||||
private DisplayInfo updateDisplayAndOrientationLocked(int uiMode, int displayId) {
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
|
||||
|
||||
// TODO(multi-display): Implement rotation for secondary displays.
|
||||
final boolean isDefaultDisplay = displayContent.isDefaultDisplay;
|
||||
final int displayRotation = displayContent.getRotation();
|
||||
final boolean altDisplayOrientation = displayContent.getAltOrientation();
|
||||
|
||||
// Use the effective "visual" dimensions based on current rotation
|
||||
final boolean rotated = (displayRotation == Surface.ROTATION_90
|
||||
|| displayRotation == Surface.ROTATION_270);
|
||||
final int realdw = rotated ?
|
||||
displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
|
||||
final int realdh = rotated ?
|
||||
displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
|
||||
int dw = realdw;
|
||||
int dh = realdh;
|
||||
|
||||
if (altDisplayOrientation) {
|
||||
if (realdw > realdh) {
|
||||
// Turn landscape into portrait.
|
||||
int maxw = (int)(realdh/1.3f);
|
||||
if (maxw < realdw) {
|
||||
dw = maxw;
|
||||
}
|
||||
} else {
|
||||
// Turn portrait into landscape.
|
||||
int maxh = (int)(realdw/1.3f);
|
||||
if (maxh < realdh) {
|
||||
dh = maxh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update application display metrics.
|
||||
final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, displayRotation, uiMode,
|
||||
displayId);
|
||||
final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, displayRotation, uiMode,
|
||||
displayId);
|
||||
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
|
||||
displayInfo.rotation = displayRotation;
|
||||
displayInfo.logicalWidth = dw;
|
||||
displayInfo.logicalHeight = dh;
|
||||
displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
|
||||
displayInfo.appWidth = appWidth;
|
||||
displayInfo.appHeight = appHeight;
|
||||
if (isDefaultDisplay) {
|
||||
displayInfo.getLogicalMetrics(mRealDisplayMetrics,
|
||||
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||||
}
|
||||
displayInfo.getAppMetrics(mDisplayMetrics);
|
||||
if (displayContent.mDisplayScalingDisabled) {
|
||||
displayInfo.flags |= Display.FLAG_SCALING_DISABLED;
|
||||
} else {
|
||||
displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
|
||||
}
|
||||
|
||||
mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
|
||||
displayContent.getDisplayId(), displayInfo);
|
||||
|
||||
displayContent.mBaseDisplayRect.set(0, 0, dw, dh);
|
||||
if (false) {
|
||||
Slog.i(TAG_WM, "Set app display size: " + appWidth + " x " + appHeight);
|
||||
}
|
||||
|
||||
if (isDefaultDisplay) {
|
||||
mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
|
||||
mCompatDisplayMetrics);
|
||||
}
|
||||
return displayInfo;
|
||||
}
|
||||
|
||||
/** Do not call if mDisplayReady == false */
|
||||
private void computeScreenConfigurationLocked(Configuration config, int displayId) {
|
||||
final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(config.uiMode, displayId);
|
||||
|
||||
final int dw = displayInfo.logicalWidth;
|
||||
final int dh = displayInfo.logicalHeight;
|
||||
config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
|
||||
Configuration.ORIENTATION_LANDSCAPE;
|
||||
config.screenWidthDp =
|
||||
(int)(mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation, config.uiMode,
|
||||
displayId) / mDisplayMetrics.density);
|
||||
config.screenHeightDp =
|
||||
(int)(mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation, config.uiMode,
|
||||
displayId) / mDisplayMetrics.density);
|
||||
final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
|
||||
|| displayInfo.rotation == Surface.ROTATION_270);
|
||||
|
||||
computeSizeRangesAndScreenLayout(displayInfo, displayId, rotated, config.uiMode, dw, dh,
|
||||
mDisplayMetrics.density, config);
|
||||
|
||||
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
|
||||
| ((displayInfo.flags & Display.FLAG_ROUND) != 0
|
||||
? Configuration.SCREENLAYOUT_ROUND_YES
|
||||
: Configuration.SCREENLAYOUT_ROUND_NO);
|
||||
|
||||
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
|
||||
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
|
||||
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode,
|
||||
mDisplayMetrics, dw, dh, displayId);
|
||||
config.densityDpi = displayInfo.logicalDensityDpi;
|
||||
|
||||
config.colorMode =
|
||||
(displayInfo.isHdr()
|
||||
? Configuration.COLOR_MODE_HDR_YES
|
||||
: Configuration.COLOR_MODE_HDR_NO)
|
||||
| (displayInfo.isWideColorGamut()
|
||||
? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
|
||||
: Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
|
||||
|
||||
// Update the configuration based on available input devices, lid switch,
|
||||
// and platform configuration.
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
|
||||
config.keyboard = Configuration.KEYBOARD_NOKEYS;
|
||||
config.navigation = Configuration.NAVIGATION_NONAV;
|
||||
|
||||
int keyboardPresence = 0;
|
||||
int navigationPresence = 0;
|
||||
final InputDevice[] devices = mInputManager.getInputDevices();
|
||||
final int len = devices != null ? devices.length : 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
InputDevice device = devices[i];
|
||||
if (!device.isVirtual()) {
|
||||
final int sources = device.getSources();
|
||||
final int presenceFlag = device.isExternal() ?
|
||||
WindowManagerPolicy.PRESENCE_EXTERNAL :
|
||||
WindowManagerPolicy.PRESENCE_INTERNAL;
|
||||
|
||||
if (mIsTouchDevice) {
|
||||
if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
|
||||
InputDevice.SOURCE_TOUCHSCREEN) {
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
|
||||
}
|
||||
} else {
|
||||
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
|
||||
}
|
||||
|
||||
if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
|
||||
config.navigation = Configuration.NAVIGATION_TRACKBALL;
|
||||
navigationPresence |= presenceFlag;
|
||||
} else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
|
||||
&& config.navigation == Configuration.NAVIGATION_NONAV) {
|
||||
config.navigation = Configuration.NAVIGATION_DPAD;
|
||||
navigationPresence |= presenceFlag;
|
||||
}
|
||||
|
||||
if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
||||
config.keyboard = Configuration.KEYBOARD_QWERTY;
|
||||
keyboardPresence |= presenceFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {
|
||||
config.navigation = Configuration.NAVIGATION_DPAD;
|
||||
navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
|
||||
}
|
||||
|
||||
// Determine whether a hard keyboard is available and enabled.
|
||||
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
|
||||
if (hardKeyboardAvailable != mHardKeyboardAvailable) {
|
||||
mHardKeyboardAvailable = hardKeyboardAvailable;
|
||||
mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
|
||||
mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
|
||||
}
|
||||
|
||||
// Let the policy update hidden states.
|
||||
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
|
||||
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
|
||||
config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
|
||||
mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
|
||||
displayContent.computeScreenConfiguration(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
void notifyHardKeyboardStatusChange() {
|
||||
@@ -6099,7 +5584,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
displayId);
|
||||
final Configuration currentDisplayConfig = displayContent.getConfiguration();
|
||||
mTempConfiguration.setTo(currentDisplayConfig);
|
||||
computeScreenConfigurationLocked(mTempConfiguration, displayId);
|
||||
displayContent.computeScreenConfiguration(mTempConfiguration);
|
||||
configChanged |= currentDisplayConfig.diff(mTempConfiguration) != 0;
|
||||
|
||||
if (configChanged) {
|
||||
@@ -6562,7 +6047,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
if (updateRotation) {
|
||||
if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
|
||||
configChanged |= updateRotationUncheckedLocked(false, displayId);
|
||||
configChanged |= displayContent.updateRotationUnchecked(
|
||||
false /* inTransaction */);
|
||||
}
|
||||
|
||||
if (configChanged) {
|
||||
@@ -6605,8 +6091,9 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
String[] toks = line.split("%");
|
||||
if (toks != null && toks.length > 0) {
|
||||
// TODO(multi-display): Show watermarks on secondary displays.
|
||||
mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
|
||||
mRealDisplayMetrics, mFxSession, toks);
|
||||
final DisplayContent displayContent = getDefaultDisplayContentLocked();
|
||||
mWatermark = new Watermark(displayContent.getDisplay(),
|
||||
displayContent.mRealDisplayMetrics, mFxSession, toks);
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
@@ -7642,9 +7129,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
if (DEBUG_ORIENTATION) {
|
||||
Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
|
||||
}
|
||||
final int displayId = w.getDisplayId();
|
||||
if (updateRotationUncheckedLocked(false, displayId)) {
|
||||
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
|
||||
final DisplayContent displayContent = w.getDisplayContent();
|
||||
if (displayContent.updateRotationUnchecked(false /* inTransaction */)) {
|
||||
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1273,8 +1273,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
|
||||
void prelayout() {
|
||||
if (mEnforceSizeCompat) {
|
||||
mGlobalScale = mService.mCompatibleScreenScale;
|
||||
mInvGlobalScale = 1/mGlobalScale;
|
||||
mGlobalScale = getDisplayContent().mCompatibleScreenScale;
|
||||
mInvGlobalScale = 1 / mGlobalScale;
|
||||
} else {
|
||||
mGlobalScale = mInvGlobalScale = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user