平台:qcom msm8953 android7.1
现象:客户app或者应用商城下载的app在我们自己的Android板上运行是,会出现反方向显示的情况,如系统方向是90°,运行某些app,app打开后会是270°的方向。
解决方法:
思路1:理清AndroidGUI系统显示框架,刚开始从底层想去理清AndroidGUI系统显示框架,结果越看涉及的知识越来愈多,最后看的头脑一点都不清醒了,越看越糊涂,更别说解决这个bug了。于是开始转向思路2;
思路2:之前有了解过Android系统屏幕旋转是基于WMS和PMS的,另外,做过一段时间的Android应用开发,知道在Android应用中是可以通过xml去设置应用显示的方向的,于是结合这两点,开始往这方面靠。
首先找到一篇文章https://blog.csdn.net/jinzhuojun/article/details/50085491,大家可以结合这个阅读下源码,我在PMS,和WMS中分别加了点打印,然后抓取打开会出现问题的app,找到了一些信息,发现 在我打开app的时候产生屏幕旋转的现象在WMS中会进入
updateRotationUncheckedLocked这个方法,紧接着在这个方法中,我发现在该方法中运行到如图所示的时候,对屏幕方向进行了修改
那么看到这里图中第一句赋值语句中的右值的值是从何而来呢?往上跟踪源码发现,是经过rotationForOrientationLw这个方法而来,那这个方法在哪定义和实现的呢?继续跟踪可以看到是mPolicy中的一个方法,那么继续找到何处继承了这个代理类,最终跟踪到PMS中找到了该方法的实现。
@Override
public int rotationForOrientationLw(int orientation, int lastRotation) {
if (true) {
Slog.v(TAG, "rotationForOrientationLw(orient="
+ orientation + ", last=" + lastRotation
+ "); user=" + mUserRotation + " "
+ ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
? "USER_ROTATION_LOCKED" : "")
);
}
.......
if (DEBUG_LAYOUT) Slog.i(TAG, "orientation: " + orientation);
if (getScreenWidth(mContext) < getScreenHeight(mContext)) { //Determine the physical screen direction
Slog.v(TAG, "width < height");
switch (lastRotation) //Make the app direction follow system
{
case Surface.ROTATION_0:
mPortraitRotation = Surface.ROTATION_0; //shu portrait
mUpsideDownRotation = Surface.ROTATION_180; // fan shu
mLandscapeRotation = Surface.ROTATION_90; // heng landscape
mSeascapeRotation = Surface.ROTATION_270; //fan heng
break;
case Surface.ROTATION_90:
mPortraitRotation = Surface.ROTATION_90; //shu portrait
mUpsideDownRotation = Surface.ROTATION_270; // fan shu
mLandscapeRotation = Surface.ROTATION_0; // heng landscape
mSeascapeRotation = Surface.ROTATION_180; //fan heng
break;
case Surface.ROTATION_180:
mPortraitRotation = Surface.ROTATION_180; //shu portrait
mUpsideDownRotation = Surface.ROTATION_0; // fan shu
mLandscapeRotation = Surface.ROTATION_270; // heng landscape
mSeascapeRotation = Surface.ROTATION_90; //fan heng
break;
case Surface.ROTATION_270:
mPortraitRotation = Surface.ROTATION_270; //shu portrait
mUpsideDownRotation = Surface.ROTATION_90; // fan shu
mLandscapeRotation = Surface.ROTATION_180; // heng landscape
mSeascapeRotation = Surface.ROTATION_0; //fan heng
break;
}
} else {
Slog.v(TAG, "width > height");
switch (lastRotation)//Make the app direction follow system
{
case Surface.ROTATION_0:
mPortraitRotation = Surface.ROTATION_0; //shu portrait
mUpsideDownRotation = Surface.ROTATION_180; // fan shu
mLandscapeRotation = Surface.ROTATION_90; // heng landscape
mSeascapeRotation = Surface.ROTATION_270; //fan heng
break;
case Surface.ROTATION_90:
mPortraitRotation = Surface.ROTATION_90; //shu portrait
mUpsideDownRotation = Surface.ROTATION_270; // fan shu
mLandscapeRotation = Surface.ROTATION_0; // heng landscape
mSeascapeRotation = Surface.ROTATION_180; //fan heng
break;
case Surface.ROTATION_180:
mPortraitRotation = Surface.ROTATION_180; //shu portrait
mUpsideDownRotation = Surface.ROTATION_0; // fan shu
mLandscapeRotation = Surface.ROTATION_270; // heng landscape
mSeascapeRotation = Surface.ROTATION_90; //fan heng
break;
case Surface.ROTATION_270:
mPortraitRotation = Surface.ROTATION_270;
mUpsideDownRotation = Surface.ROTATION_90;
mLandscapeRotation = Surface.ROTATION_180;
mSeascapeRotation = Surface.ROTATION_0;
break;
}
}
switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: //portrait
// Return portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
Slog.v(TAG, "preferredRotation:" + preferredRotation);
return preferredRotation;
}
Slog.v(TAG, "mPortraitRotation:" + mPortraitRotation);
return mPortraitRotation;
case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: //landscape
// Return landscape unless overridden.
if (isLandscapeOrSeascape(preferredRotation)) {
return preferredRotation;
}
return mLandscapeRotation;
case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: //reversePortrait >= api 9
// Return reverse portrait unless overridden.
if (isAnyPortrait(preferredRotation)) {
return preferredRotation;
}
return mUpsideDownRotation;
case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: //reverseLandscape >= api 9
// 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;
return mDefaultOrientation;
}
}
}
代码略长,省略部分,只看重点,在这个方法中添加一些打印发现,这里正是对app 通过设置xml配置屏幕方向的一些分类情况处理,我们可以看到图中 switch (orientation) 处,这里分别对应了应用层的一些设置,如:“portrait”,"landscape"等,
那么分析到这里,我想是不是可以在这个分类处理之前做些处理,让app跟随系统方向,于是进行了标红处的代码添加,最终运行测试,OK,测试通过!!
PS: 横屏好像还有点问题,后面再细查。
PMS:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
WMS:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java