Android 7.1 WindowManagerService 屏幕旋转流程分析 (二)
一、概述
从上篇【Android 7.1 屏幕旋转流程分析】知道实际的旋转由WindowManagerService来完成,这里接着上面具体详细展开。 调了三个函数完成了三件事,即首先调用updateRotationUncheckedLocked()更新rotation,然后调用performSurfacePlacement()做屏幕的绘制,最后调用sendNewConfiguration()发送Configuration变更事件。
本篇对updateRotationUncheckedLocked()详细展开,后面的系列会继续详细介绍剩余的部分。
public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked("
+ "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); long origId = Binder.clearCallingIdentity();
boolean changed;
synchronized(mWindowMap) {
//(1)更新rotation
changed = updateRotationUncheckedLocked(false);
if (!changed || forceRelayout) {
getDefaultDisplayContentLocked().layoutNeeded = true;
//(2)做屏幕的绘制
mWindowPlacerLocked.performSurfacePlacement();
}
} if (changed || alwaysSendConfiguration) {
//(3)发送Configuration变更事件
sendNewConfiguration();
} Binder.restoreCallingIdentity(origId);
}
二、更新rotation
updateRotationUncheckedLocked()主要完成如下几件事:
A : 首先判断有下列情形的则返回false放弃更新rotation
(1)有延迟的Rotation尚未完成,即DeferredRotationPauseCount > 0
(2)上次旋转还没有完成旋转动画还在运行中,即screenRotationAnimation.isAnimating() == true
(3)旋转动画已完成但display还未unfrozen(display 还在Frozen状态)及 mDisplayFrozen == true
(4)display 不可用
B:获取设备方向
(PhoneWindowManager的rotationForOrientationLw()根据根据传感器数据计算转换为设备方向)和是否需要平滑(Seamlessly)旋转(PhoneWindowManager的shouldRotateSeamlessly()函数)如果Seamlessly则不能有旋转动画。
C:根据新的显示方向(Orientation)来更新DisplayInfo
D通过SurfaceControl.openTransaction()设置Surface参数
public boolean updateRotationUncheckedLocked(boolean inTransaction) {
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;
}
//如果上次的旋转动画还在运行中(即上次还未旋转完成则无需旋转,返回false)
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
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;
}
//display 尚未unfrozen
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 displayContent = getDefaultDisplayContentLocked();
final WindowList windows = displayContent.getWindowList(); final int oldRotation = mRotation;
//获取设备方向(根据传感器数据计算转换为设备方向)
int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
//获取rotateSeamlessly
boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
// 处理判断是否可以Seamlessly
if (rotateSeamlessly) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
if (w.mSeamlesslyRotated) {
return false;
} if (w.isChildWindow() & w.isVisibleNow() &&
!w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
rotateSeamlessly = false;
}
}
} boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
mLastOrientation, rotation); if (DEBUG_ORIENTATION) {
Slog.v(TAG_WM, "Selected orientation "
+ mLastOrientation + ", got rotation " + rotation
+ " which has " + (altOrientation ? "incompatible" : "compatible")
+ " metrics");
} if (mRotation == rotation && mAltOrientation == altOrientation) {
// No change.
return false;
} if (DEBUG_ORIENTATION) {
Slog.v(TAG_WM,
"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")
+ ", lastOrientation=" + mLastOrientation);
} mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation); mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
//发送WINDOW_FREEZE_TIMEOUT消息
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
mWaitingForConfig = true;
displayContent.layoutNeeded = true;
final int[] anim = new int[2];
if (displayContent.isDimming()) {
anim[0] = anim[1] = 0;
} else {
mPolicy.selectRotationAnimationLw(anim);
}
// 如果是Seamlessly则无旋转动画,因Seamlessly目前不支持旋转动画
if (!rotateSeamlessly) {
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
} 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.
//根据rotation 去更新DisplayInfo
updateDisplayAndOrientationLocked(mCurConfiguration.uiMode); final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (!inTransaction) {
if (SHOW_TRANSACTIONS) {
Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
}
// 设置surface参数
SurfaceControl.openTransaction();
}
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) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
}
} mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
} finally {
if (!inTransaction) {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
}
}
} for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
// 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;
mWindowPlacerLocked.mOrientationChangeComplete = false;
w.mLastFreezeDuration = 0;
}
}
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--) {
try {
mRotationWatchers.get(i).watcher.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
&& displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(),rotation);
} return true;
}
1)通过PhoneWindowManager获取orientation 和rotateSeamlessly
A:PhoneWindowManager的rotationForOrientationLw()
PhoneWindowManager的rotationForOrientationLw()根据传感器数据和各种场景和设置来更新preferredRotation 和orientation(注释比较详细,不赘述)
public int rotationForOrientationLw(int orientation, int lastRotation) { if (mForceDefaultOrientation) {
return Surface.ROTATION_0;
} synchronized (mLock) {
int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
if (sensorRotation < 0) {
sensorRotation = lastRotation;
} final int preferredRotation;
//根据各种场景和设置来更新preferredRotation 和orientation
if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
// Ignore sensor when lid switch is open and rotation is forced.
preferredRotation = mLidOpenRotation;
} else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
&& (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {
// Ignore sensor when in car dock unless explicitly enabled.
// This case can override the behavior of NOSENSOR, and can also
// enable 180 degree rotation while docked.
preferredRotation = mCarDockEnablesAccelerometer
? sensorRotation : mCarDockRotation;
} else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
|| mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
|| mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
&& (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
// Ignore sensor when in desk dock unless explicitly enabled.
// This case can override the behavior of NOSENSOR, and can also
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
} else if (mHdmiPlugged && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
} else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
&& mUndockedHdmiRotation >= 0) {
// Ignore sensor when plugged into HDMI and an undocked orientation has
// been specified in the configuration (only for legacy devices without
// full multi-display support).
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mUndockedHdmiRotation;
} else if (mDemoRotationLock) {
// Ignore sensor when demo rotation lock is enabled.
// Note that the dock orientation and HDMI rotation lock override this.
preferredRotation = mDemoRotation;
} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// Application just wants to remain locked in the last rotation.
preferredRotation = lastRotation;
} else if (!mSupportAutoRotation) {
// If we don't support auto-rotation then bail out here and ignore
// the sensor and any rotation lock settings.
preferredRotation = -1;
} else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|| orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
// Otherwise, use sensor only if requested by the application or enabled
// by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
if (mAllowAllRotations < 0) {
// Can't read this during init() because the context doesn't
// have display metrics at that time so we cannot determine
// tablet vs. phone then.
mAllowAllRotations = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
}
if (sensorRotation != Surface.ROTATION_180
|| mAllowAllRotations == 1
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
preferredRotation = sensorRotation;
} else {
preferredRotation = lastRotation;
}
} else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
&& orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
// Apply rotation lock. Does not apply to NOSENSOR.
// The idea is that the user rotation expresses a weak preference for the direction
// of gravity and as NOSENSOR is never affected by gravity, then neither should
// NOSENSOR be affected by rotation lock (although it will be affected by docks).
preferredRotation = mUserRotation;
} else {
// No overriding preference.
// We will do exactly what the application asked us to do.
preferredRotation = -1;
} switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
// Return portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
return mPortraitRotation; case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
// Return landscape unless overridden.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
return mLandscapeRotation; case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
// Return reverse portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
return mUpsideDownRotation; case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
// Return seascape unless overridden.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
return mSeascapeRotation; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
// Return either landscape rotation.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
if (isLandscapeOrSeascape(lastRotation)) {
return lastRotation;
}
return mLandscapeRotation; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
// Return either portrait rotation.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
if (isAnyPortrait(lastRotation)) {
return lastRotation;
}
return mPortraitRotation; default:
// For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
// just return the preferred orientation we already calculated.
if (preferredRotation >= 0) {
return preferredRotation;
}
return Surface.ROTATION_0;
}
}
}
B: shouldRotateSeamlessly()
判断是否需要平滑(Seamlessly)旋转,目前仅 top window且为fullscreen 状态时才会返回true,其他均为false,因为Seamlessly要求冻结Surface的各种状态并且影响旋转动画效果,所以此状态时不支持旋转动画。所以这种状态支持的场景也仅限于此。了解一下即可。
public boolean shouldRotateSeamlessly(int oldRotation, int newRotation) { if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
return false;
}
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
if (delta == Surface.ROTATION_180) {
return false;
} final WindowState w = mTopFullscreenOpaqueWindowState;
if (w != mFocusedWindow) {
return false;
}
if (w != null && !w.isAnimatingLw() &&
((w.getAttrs().rotationAnimation == ROTATION_ANIMATION_JUMPCUT) ||
(w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS))) {
return true;
}
return false;
}
2)更新显示信息(DisplayInfo)
根据新的显示方向(Orientation)来更新DisplayInfo,然后通过setDisplayInfoOverrideFromWindowManager()来更新显示设备最后计算frame Rect 给应用来做缩放用。
DisplayInfo updateDisplayAndOrientationLocked(int uiMode) {
// TODO(multidisplay): For now, apply Configuration to main screen only.
final DisplayContent displayContent = getDefaultDisplayContentLocked(); // Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == Surface.ROTATION_90
|| mRotation == 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 (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 = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode);
final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
displayInfo.rotation = mRotation;
displayInfo.logicalWidth = dw;
displayInfo.logicalHeight = dh;
displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
displayInfo.appWidth = appWidth;
displayInfo.appHeight = appHeight;
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);
} mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
mCompatDisplayMetrics);
return displayInfo;
}
A: DisplayManagerService.setDisplayInfoOverrideFromWindowManager()
window manager 通过此函数来更新逻辑显示设备(logical display)的大小变化和一些特性的变更。
首先通过sendDisplayEventLocked()会发送一个MSG_DELIVER_DISPLAY_EVENT消息然后通过,然后调用scheduleTraversalLocked()发送MSG_REQUEST_TRAVERSAL消息请求surface 和display处理变更请求。
public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
} private void setDisplayInfoOverrideFromWindowManagerInternal(int displayId, DisplayInfo info) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
if (display != null) {
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
//发送MSG_DELIVER_DISPLAY_EVENT消息
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
//发送MSG_REQUEST_TRAVERSAL消息
scheduleTraversalLocked(false);
}
}
}
} private void sendDisplayEventLocked(int displayId, int event) {
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
mHandler.sendMessage(msg);
}
发送MSG_REQUEST_TRAVERSAL消息请求,稍后由surface 和display处理变更请求。这样处理是为了异步执行。
private void scheduleTraversalLocked(boolean inTraversal) {
if (!mPendingTraversal && mWindowManagerInternal != null) {
mPendingTraversal = true;
if (!inTraversal) {
mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
}
}
}
B: computeCompatibleScaling() 计算frame Rect来供应用做缩放
public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
final int width = dm.noncompatWidthPixels;
final int height = dm.noncompatHeightPixels;
int shortSize, longSize;
if (width < height) {
shortSize = width;
longSize = height;
} else {
shortSize = height;
longSize = width;
}
int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f);
float aspect = ((float)longSize) / shortSize;
if (aspect > MAXIMUM_ASPECT_RATIO) {
aspect = MAXIMUM_ASPECT_RATIO;
}
int newLongSize = (int)(newShortSize * aspect + 0.5f);
int newWidth, newHeight;
if (width < height) {
newWidth = newShortSize;
newHeight = newLongSize;
} else {
newWidth = newLongSize;
newHeight = newShortSize;
} float sw = width/(float)newWidth;
float sh = height/(float)newHeight;
float scale = sw < sh ? sw : sh;
if (scale < 1) {
scale = 1;
} if (outDm != null) {
outDm.widthPixels = newWidth;
outDm.heightPixels = newHeight;
} return scale;
}
3)DisplayManagerService的performTraversalInTransactionFromWindowManager()
public void performTraversalInTransactionFromWindowManager() {
performTraversalInTransactionFromWindowManagerInternal();
}
private void performTraversalInTransactionFromWindowManagerInternal() {
synchronized (mSyncRoot) {
if (!mPendingTraversal) {
return;
}
mPendingTraversal = false; performTraversalInTransactionLocked();
} // List is self-synchronized copy-on-write.
for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
listener.onDisplayTransaction();
}
}
private void performTraversalInTransactionLocked() {
// Clear all viewports before configuring displays so that we can keep
// track of which ones we have configured.
clearViewportsLocked(); // Configure each display device.
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
configureDisplayInTransactionLocked(device);
device.performTraversalInTransactionLocked();
} // Tell the input system about these new viewports.
if (mInputManagerInternal != null) {
mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
}
}
private void configureDisplayInTransactionLocked(DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; // Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
if (!ownContent) {
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the default logical display contents.
display = null;
}
if (display == null) {
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
}
} // Apply the logical display configuration to the display device.
if (display == null) {
// TODO: no logical display for the device, blank it
Slog.w(TAG, "Missing logical display to use for physical display device: "
+ device.getDisplayDeviceInfoLocked());
return;
}
display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF); // Update the viewports if needed.
if (!mDefaultViewport.valid
&& (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
setViewportLocked(mDefaultViewport, display, device);
}
if (!mExternalTouchViewport.valid
&& info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
setViewportLocked(mExternalTouchViewport, display, device);
}
}
4)总结
Android 7.1 WindowManagerService 屏幕旋转流程分析 (二)的更多相关文章
- Android 7.1 WindowManagerService 屏幕旋转流程分析 (三)
三.屏幕的绘制 performSurfacePlacement()函数来触发window的绘制,这里最大的循环次数是6,当然一般不会到最大次数就会被Scheduled. final void perf ...
- Android 7.1 ActivityManagerService 屏幕旋转流程分析 (四)
四.Activity的更新(旋转) sendNewConfiguration()会调用到ActivityManagerService的updateConfiguration()来update Conf ...
- Android 7.1 屏幕旋转流程分析
Android 7.1 屏幕旋转流程分析 一.概述 Android屏幕的旋转在framework主要涉及到三个类,结构如图 PhoneWindowManager:为屏幕的横竖屏转换的管理类. Wi ...
- 【转】如何在 Android 程序中禁止屏幕旋转和重启Activity
原文网址:http://www.cnblogs.com/bluestorm/p/3665890.html 禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变 ...
- 如何在 Android 程序中禁止屏幕旋转和重启Activity
禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变化:在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android ...
- Android笔记--View绘制流程源码分析(二)
Android笔记--View绘制流程源码分析二 通过上一篇View绘制流程源码分析一可以知晓整个绘制流程之前,在activity启动过程中: Window的建立(activit.attach生成), ...
- Android 4.4 音量调节流程分析(二)
之前在Android 4.4 音量调节流程分析(一)里已经有简单的分析音量控制的流程,今天想接着继续分析下音量大小计算的方法.对于任一播放文件而言其本身都有着固定大小的音量Volume_Max,而在A ...
- Android系统分析之运营商显示流程分析之运营商信息的读取流程二
运营商显示流程分析之运营商信息的读取流程 一. SIM卡运营商信息的读取 从前面的 运营商信息的获取和赋值 可以知道SIM卡运营商的赋值最终是在 SIMRecords 中完成的, 而SIM卡信息的相关 ...
- 【Android】11.3 屏幕旋转和场景变换过程中GridView的呈现
分类:C#.Android.VS2015: 创建日期:2016-02-21 一.简介 实际上,对于布局文件中的View来说,大多数情况下,Android都会自动保存这些状态,并不需要我们都去处理它.这 ...
随机推荐
- 浅谈javascript的函数节流
什么是函数节流? 介绍前,先说下背景.在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(其核心就是绑定mousemove),这种事件有一个特点,就是用户不必特地捣乱,他在 ...
- 使用jquery ajaxForm提交表单
一.首先引用Jquery <script src="~/Scripts/jquery-1.9.1.min.js"></script> <script ...
- .net中LAMBDA表达式常用写法
这里主要是将数据库中的常用操作用LAMBDA表达式重新表示了下,用法不多,但相对较常用,等有时间了还会扩展,并将查询语句及LINQ到时也一并重新整理下: 1.select语句:books.Select ...
- Rsync服务
第1章 Rsync开篇介绍 1.1 rsync的定义 Rsync是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据同步备份的优秀工具.Rsync软件适用于unix/linux/windo ...
- [转载] Redis-benchmark使用总结
转载自http://blog.csdn.net/jiangguilong2000/article/details/24143721 Redis-benchmark为Redis性能测试工具. 指令说明: ...
- [转载] MapReduce工作原理讲解
转载自http://www.aboutyun.com/thread-6723-1-1.html 有时候我们在用,但是却不知道为什么.就像苹果砸到我们头上,这或许已经是很自然的事情了,但是牛顿却发现了地 ...
- [转载] Lucene 工作原理
转载自http://www.cnblogs.com/dewin/archive/2009/11/24/1609905.html Lucene是一个高性能的java全文检索工具包,它使用的是倒排文件索引 ...
- innobackupex: fatal error: no ‘innodb_buffer_pool_filename’解决方法
http://www.ttlsa.com/mysql/innobackupex-1-5-1-fatal-error-no-innodb_buffer_pool_filename/
- WPF中DataGrid垂直滚动条滚动后导致每行CheckBox选择错乱
问题: WPF的DataGrid中出现选取或者多选以及单选的时候,出现滚动条的时候,如果发生了滚动,默认情况下就会出现已经选择的CheckBox错乱.这样的原因何在? 解决方案: 经过查阅资料,了解到 ...
- jmockit学习总结
mock类型和实例 从依赖的测试代码调用的方法和构造函数是mock(模拟)的目标. Mocking提供了我们需要的机制,以便将被测试的代码与(一些)依赖关系隔离开来.我们通过声明适当的模拟字段和/或模 ...