现象: 代码路径: android/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java android/frameworks/base/core/java/android/content/pm/PackageParser.java 日志分析流程: adb shell dumpsys activity> D:\window.txt adb shell dumpsys window > D:\window.txt 通过dumpsys 命令看输出的overrideconfiguration中bound的值,从日志分析看,从mAppBounds数组中可以知道该应用距离左边486,并且maxAspectRatio的值为1.86
mStartActivity:
packageName=com.spotify.music processName=com.spotify.music
launchedFromUid=10109 launchedFromPackage=com.spotify.music userId=0
app=ProcessRecord{d8ed953 5223:com.spotify.music/u0a109}
Intent { act=com.spotify.mobile.android.service.action.session.LOGIN flg=0x10000000 cmp=com.spotify.music/com.spotify.mobile.android.service.LoginActivity (has extras) }
frontOfTask=true task=TaskRecord{98078b #7 A=com.spotify.music U=0 StackId=3 sz=1}
taskAffinity=com.spotify.music
mActivityComponent=com.spotify.music/com.spotify.mobile.android.service.LoginActivity
baseDir=/data/app/com.spotify.music-HT6cXhHmdVjBWex3Fa446A==/base.apk
dataDir=/data/user/0/com.spotify.music
stateNotNeeded=false componentSpecified=true mActivityType=standard
compat={160dpi} labelRes=0x7f10006f icon=0x7f0802c7 theme=0x7f1101eb
mLastReportedConfigurations:
mGlobalConfig={1.0 ?mcc?mnc [zh_CN] ldltr sw-47dp w1433dp h440dp 160dpi nrml long land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 440) mAppBounds=Rect(486, 0 - 1919, 440) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.6}
mOverrideConfig={1.0 ?mcc?mnc [zh_CN] ldltr sw-47dp w818dp h439dp 160dpi nrml long land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1304, 440) mAppBounds=Rect(486, 0 - 1304, 440) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} s.3}
CurrentConfiguration={1.0 ?mcc?mnc [zh_CN] ldltr sw-47dp w818dp h439dp 160dpi nrml long land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1304, 440) mAppBounds=Rect(486, 0 - 1304, 440) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} s.3}
RequestedOverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?ldr ?wideColorGamut ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 1304, 440) mAppBounds=null mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=undefined mAlwaysOnTop=undefined mRotation=undefined}}
ResolvedOverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp w818dp h439dp ?density nrml long ?ldr ?wideColorGamut land ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 1304, 440) mAppBounds=Rect(486, 0 - 1304, 440) mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=undefined mAlwaysOnTop=undefined mRotation=undefined} s.3}
bounds=Rect(0, 0 - 1304, 440)
taskDescription: label="null" icon=null iconResource=0 iconFilename=null primaryColor=ff121212
backgroundColor=ff121212
statusBarColor=ff121212
navigationBarColor=ff000000
launchFailed=false launchCount=1 lastLaunchTime=-5m25s469ms
haveState=false icicle=null
state=RESUMED stopped=false delayedResume=false finishing=false
keysPaused=false inHistory=true visible=true sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
fullscreen=true noDisplay=false immersive=false launchMode=2
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=standard
nowVisible=true lastVisibleTime=-5m25s106ms
resizeMode=RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
mLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=false
maxAspectRatio=1.86
minAspectRatio=1.333
原因:Android P应用显示宽高比maxAspectRatio使用导致的,那么为什么maxAspectRatio=1.86会导致部分应用半屏呢? 在PackageParser.java文件中setMaxAspectRatio()方法中,如果应用的targetSdkVersion 小于26,那么maxAspectRatio 的值就是1.86,这样会导致应用半屏,还有如果targetSdkVersion 的值大于26,那么maxAspectRatio 的值就是0,这样应用就会是全屏。我们可以去看源码
/**
* Sets every the max aspect ratio of every child activity that doesn't already have an aspect
* ratio set.
*/
private void setMaxAspectRatio(Package owner) {
// Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
// NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
if (owner.applicationInfo.maxAspectRatio != 0) {
// Use the application max aspect ration as default if set.
maxAspectRatio = owner.applicationInfo.maxAspectRatio;
} else if (owner.mAppMetaData != null
&& owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
}
for (Activity activity : owner.activities) {
// If the max aspect ratio for the activity has already been set, skip.
if (activity.hasMaxAspectRatio()) {
continue;
}
// By default we prefer to use a values defined on the activity directly than values
// defined on the application. We do not check the styled attributes on the activity
// as it would have already been set when we processed the activity. We wait to process
// the meta data here since this method is called at the end of processing the
// application and all meta data is guaranteed.
final float activityAspectRatio = activity.metaData != null
? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
: maxAspectRatio;
activity.setMaxAspectRatio(activityAspectRatio);
}
}
解决思路:当我们进入一个Activity时候,会去先解析AndroidManifest.xml一些属性的值,我们会重新启动Activity设置宽度和高度,从Activity的启动流程分析,就找到了ActivityRecord.java中computeBound函数,在该函数中我们把maxAspectRatio 值修改为0就解决该问题
private void computeBounds(Rect outBounds) {
outBounds.setEmpty();
final float maxAspectRatio = 0;//info.maxAspectRatio;
final ActivityStack stack = getStack();
if (task == null || stack == null || task.inMultiWindowMode() || maxAspectRatio == 0
|| isInVrUiMode(getConfiguration())) {
// We don't set override configuration if that activity task isn't fullscreen. I.e. the
// activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
// the activity. This is indicated by an empty {@link outBounds}. We also don't set it
// if we are in VR mode.
return;
}
// We must base this on the parent configuration, because we set our override
// configuration's appBounds based on the result of this method. If we used our own
// configuration, it would be influenced by past invocations.
final Rect appBounds = getParent().getWindowConfiguration().getAppBounds();
final int containingAppWidth = appBounds.width();
final int containingAppHeight = appBounds.height();
int maxActivityWidth = containingAppWidth;
int maxActivityHeight = containingAppHeight;
if (containingAppWidth < containingAppHeight) {
// Width is the shorter side, so we use that to figure-out what the max. height
// should be given the aspect ratio.
maxActivityHeight = (int) ((maxActivityWidth * maxAspectRatio) + 0.5f);
} else {
// Height is the shorter side, so we use that to figure-out what the max. width
// should be given the aspect ratio.
maxActivityWidth = (int) ((maxActivityHeight * maxAspectRatio) + 0.5f);
}
if (containingAppWidth <= maxActivityWidth && containingAppHeight <= maxActivityHeight) {
// The display matches or is less than the activity aspect ratio, so nothing else to do.
// Return the existing bounds. If this method is running for the first time,
// {@link #getOverrideBounds()} will be empty (representing no override). If the method has run
// before, then effect of {@link #getOverrideBounds()} will already have been applied to the
// value returned from {@link getConfiguration}. Refer to
// {@link TaskRecord#computeOverrideConfiguration}.
outBounds.set(getOverrideBounds());
return;
}
// Compute configuration based on max supported width and height.
// Also account for the left / top insets (e.g. from display cutouts), which will be clipped
// away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
// bounds would end up too small.
outBounds.set(0, 0, maxActivityWidth + appBounds.left, maxActivityHeight + appBounds.top);
if (service.mWindowManager.getNavBarPosition() == NAV_BAR_LEFT) {
// Position the activity frame on the opposite side of the nav bar.
outBounds.left = appBounds.right - maxActivityWidth;
outBounds.right = appBounds.right;
}
}
|