做网站用哪个ecalipse,广西建设网站网址多少钱,专业的公司网站制作服务,企业介绍ppt案例欣赏前言
在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置#xff0c;该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数#xff0c;应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境#xff0c;以提高用户体验。
一、类定…前言
在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境以提高用户体验。
一、类定义 frameworks/base/core/java/android/app/WindowConfiguration.java public class WindowConfiguration implements Parcelable, ComparableWindowConfiguration {//包含装饰窗口在内的窗口显示区域private Rect mBounds new Rect();//不包含装饰窗口在内的窗口显示区域private Rect mAppBounds;//可显示的最大区域private final Rect mMaxBounds new Rect();//当前屏幕设备的旋转角度private int mRotation ROTATION_UNDEFINED;//当前窗口模式private WindowingMode int mWindowingMode;//屏幕窗口模式private WindowingMode int mDisplayWindowingMode;/** hide */IntDef(prefix { WINDOWING_MODE_ }, value {WINDOWING_MODE_UNDEFINED,//未定义WINDOWING_MODE_FULLSCREEN,//全屏WINDOWING_MODE_MULTI_WINDOW,//多窗口WINDOWING_MODE_PINNED,WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,WINDOWING_MODE_FREEFORM,})public interface WindowingMode {}//Activity的类型private ActivityType int mActivityType;/** hide */IntDef(prefix { ACTIVITY_TYPE_ }, value {ACTIVITY_TYPE_UNDEFINED,ACTIVITY_TYPE_STANDARD,ACTIVITY_TYPE_HOME,ACTIVITY_TYPE_RECENTS,ACTIVITY_TYPE_ASSISTANT,ACTIVITY_TYPE_DREAM,})public interface ActivityType {}//窗口是否总是位于最上层private AlwaysOnTop int mAlwaysOnTop;/** hide */IntDef(prefix { ALWAYS_ON_TOP_ }, value {ALWAYS_ON_TOP_UNDEFINED,ALWAYS_ON_TOP_ON,ALWAYS_ON_TOP_OFF,})private interface AlwaysOnTop {}
}该类主要有以下几个关键属性
mBounds 屏幕尺寸mAppBounds不包含装饰窗口在内的窗口显示区域**根据源码发现mAppBounds只排除了导航栏这个装饰窗口所在的区域状态栏和输入法等装饰窗口所在的区域是被包含在内的**mMaxBounds窗口可显示的最大区域mRotation当前屏幕设备的旋转角度mWindowingMode当前窗口的窗口模式例如未定义、全屏、分屏、多窗口等ActivityType页面类型例如未定义、标准、首页、最近任务等mAlwaysOnTop窗口是否总是位于最上层
二、WindowConfiguration的属性设置
2.1 Configuration类
WindowConfiguration在Android系统中基本都是作为Configuration类的内部属性出现的。 frameworks/base/core/java/android/content/res/Configuration.java public final class Configuration implements Parcelable, ComparableConfiguration {public final WindowConfiguration windowConfiguration new WindowConfiguration();}2.2 计算当前屏幕尺寸和当前窗口可显示的最大区域
这里我们主要是结合WMS模块的相关代码来分析WindowConfiguration的各个属性的来源系统主要是通过DisplayContent的computeScreenConfiguration方法来计算当前屏幕对应的窗口配置信息的。 frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java class DisplayContent extends WindowContainerDisplayContent.DisplayChildWindowContainerimplements WindowManagerPolicy.DisplayContentInfo {DisplayInfo computeScreenConfiguration(Configuration outConfig, int rotation) {final boolean rotated (rotation ROTATION_90 || rotation ROTATION_270);//屏幕旋转角度final int dw rotated ? mBaseDisplayHeight : mBaseDisplayWidth;//屏幕宽度final int dh rotated ? mBaseDisplayWidth : mBaseDisplayHeight;//屏幕高度//注释1对屏幕的实际宽高进行存储outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());final int uiMode getConfiguration().uiMode;//UI模式final DisplayCutout displayCutout calculateDisplayCutoutForRotation(rotation).getDisplayCutout();//计算屏幕的显示切口//注释2调用computeScreenAppConfiguration方法computeScreenAppConfiguration(outConfig, dw, dh, rotation, uiMode, displayCutout);...代码省略... }}在注释1处根据屏幕旋转角度和基本显示尺寸确定屏幕的实际宽高并将其存储到WindowConfiguration的mMaxBounds属性和mBounds属性中。 在注释2处将屏幕实际宽度、高度、旋转角度、UI模式、屏幕显示切口作为参数调用computeScreenAppConfiguration方法计算当前窗口可显示的安全区域。
2.3 计算当前窗口可显示的安全区域
class DisplayContent extends WindowContainerDisplayContent.DisplayChildWindowContainerimplements WindowManagerPolicy.DisplayContentInfo {private final DisplayPolicy mDisplayPolicy;private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,int rotation, int uiMode, DisplayCutout displayCutout) {//注释1获取不包含系统装饰窗口的可显示屏幕区域final Point appSize mDisplayPolicy.getNonDecorDisplaySize(dw, dh, rotation, uiMode, displayCutout);//注释2获取不包含系统装饰窗口的可显示屏幕边界mDisplayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);final int leftInset mTmpRect.left;final int topInset mTmpRect.top;//注释3存储应用的可显示的安全区域outConfig.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,leftInset appSize.x /* right */, topInset appSize.y /* bottom */);//存储屏幕旋转角度outConfig.windowConfiguration.setRotation(rotation);//存储屏幕是横屏还是竖屏outConfig.orientation (dw dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;//屏幕像素密度final float density mDisplayMetrics.density;final Point configSize mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, uiMode,displayCutout);outConfig.screenWidthDp (int) (configSize.x / density);outConfig.screenHeightDp (int) (configSize.y / density);outConfig.compatScreenWidthDp (int) (outConfig.screenWidthDp / mCompatibleScreenScale);outConfig.compatScreenHeightDp (int) (outConfig.screenHeightDp / mCompatibleScreenScale);final boolean rotated (rotation ROTATION_90 || rotation ROTATION_270);outConfig.compatSmallestScreenWidthDp computeCompatSmallestWidth(rotated, uiMode, dw,dh);}}frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java public class DisplayPolicy {Point getNonDecorDisplaySize(int fullWidth, int fullHeight, int rotation, int uiMode,DisplayCutout displayCutout) {int width fullWidth;int height fullHeight;int navBarReducedHeight 0;int navBarReducedWidth 0;//获取导航栏的位置final int navBarPosition navigationBarPosition(fullWidth, fullHeight, rotation);if (hasNavigationBar()) {if (navBarPosition NAV_BAR_BOTTOM) {navBarReducedHeight getNavigationBarHeight(rotation, uiMode);} else if (navBarPosition NAV_BAR_LEFT || navBarPosition NAV_BAR_RIGHT) {navBarReducedWidth getNavigationBarWidth(rotation, uiMode, navBarPosition);}}if (mExtraNavBarAlt ! null) {final LayoutParams altBarParams mExtraNavBarAlt.getLayoutingAttrs(rotation);final int altBarPosition getAltBarPosition(altBarParams);if (altBarPosition ALT_BAR_BOTTOM || altBarPosition ALT_BAR_TOP) {if (altBarPosition navBarPosition) {navBarReducedHeight Math.max(navBarReducedHeight,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));} else {navBarReducedHeight getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR);}} else if (altBarPosition ALT_BAR_LEFT || altBarPosition ALT_BAR_RIGHT) {if (altBarPosition navBarPosition) {navBarReducedWidth Math.max(navBarReducedWidth,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else {navBarReducedWidth getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR);}}}//当前窗口的安全显示区域为屏幕宽高减去导航栏所在的区域height - navBarReducedHeight;width - navBarReducedWidth;//如果屏幕显示切口对象不为空还要减去该区域if (displayCutout ! null) {height - displayCutout.getSafeInsetTop() displayCutout.getSafeInsetBottom();width - displayCutout.getSafeInsetLeft() displayCutout.getSafeInsetRight();}return new Point(width, height);}public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,DisplayCutout displayCutout, Rect outInsets) {outInsets.setEmpty();//系统存在导航栏if (hasNavigationBar()) {final int uiMode mService.mPolicy.getUiMode();//获取导航栏的位置最终返回的边界区域要去掉导航栏所在的区域int position navigationBarPosition(displayWidth, displayHeight, displayRotation);if (position NAV_BAR_BOTTOM) {outInsets.bottom getNavigationBarHeight(displayRotation, uiMode);} else if (position NAV_BAR_RIGHT) {outInsets.right getNavigationBarWidth(displayRotation, uiMode, position);} else if (position NAV_BAR_LEFT) {outInsets.left getNavigationBarWidth(displayRotation, uiMode, position);}}if (mExtraNavBarAlt ! null) {final LayoutParams extraNavLayoutParams mExtraNavBarAlt.getLayoutingAttrs(displayRotation);final int position getAltBarPosition(extraNavLayoutParams);if (position ALT_BAR_BOTTOM) {outInsets.bottom Math.max(outInsets.bottom,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position ALT_BAR_RIGHT) {outInsets.right Math.max(outInsets.right,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position ALT_BAR_LEFT) {outInsets.left Math.max(outInsets.left,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position ALT_BAR_TOP) {outInsets.top Math.max(outInsets.top,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));}}//如果屏幕显示切口对象不为空还要减去该区域if (displayCutout ! null) {outInsets.left displayCutout.getSafeInsetLeft();outInsets.top displayCutout.getSafeInsetTop();outInsets.right displayCutout.getSafeInsetRight();outInsets.bottom displayCutout.getSafeInsetBottom();}}}在注释1处调用DisplayPolicy的getNonDecorDisplaySize方法获取不包含系统装饰窗口的可显示屏幕区域将结果存放在类型为Point的appSize对象中结合getNonDecorDisplaySize方法源码可以发现该方法只是去除了导航栏窗口所在的区域另外如果有屏幕显示切口区域还会去除屏幕显示切口区域。 在注释2处调用DisplayPolicy的getNonDecorInsetsLw方法获取不包含系统装饰窗口的可显示屏幕边界将结果存放在类型为Rect的mTmpRect对象中结合getNonDecorInsetsLw方法源码可以发现该方法只是去除了导航栏窗口所在的区域另外如果有屏幕显示切口区域还会去除屏幕显示切口区域。 在注释3处会结合appSize和mTmpRect将当前窗口可显示的安全区域存储到Configuration的WindowConfiguration中。
三、WindowConfiguration的作用
WindowConfiguration的toString方法包含了此类的所有关键信息。
public class WindowConfiguration implements Parcelable, ComparableWindowConfiguration {Overridepublic String toString() {return { mBounds mBounds mAppBounds mAppBounds mMaxBounds mMaxBounds mWindowingMode windowingModeToString(mWindowingMode) mDisplayWindowingMode windowingModeToString(mDisplayWindowingMode) mActivityType activityTypeToString(mActivityType) mAlwaysOnTop alwaysOnTopToString(mAlwaysOnTop) mRotation (mRotation ROTATION_UNDEFINED? undefined : rotationToString(mRotation)) };}public static String windowingModeToString(WindowingMode int windowingMode) {switch (windowingMode) {case WINDOWING_MODE_UNDEFINED: return undefined;case WINDOWING_MODE_FULLSCREEN: return fullscreen;case WINDOWING_MODE_MULTI_WINDOW: return multi-window;case WINDOWING_MODE_PINNED: return pinned;case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return split-screen-primary;case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return split-screen-secondary;case WINDOWING_MODE_FREEFORM: return freeform;}return String.valueOf(windowingMode);}public static String activityTypeToString(ActivityType int applicationType) {switch (applicationType) {case ACTIVITY_TYPE_UNDEFINED: return undefined;case ACTIVITY_TYPE_STANDARD: return standard;case ACTIVITY_TYPE_HOME: return home;case ACTIVITY_TYPE_RECENTS: return recents;case ACTIVITY_TYPE_ASSISTANT: return assistant;case ACTIVITY_TYPE_DREAM: return dream;}return String.valueOf(applicationType);}public static String alwaysOnTopToString(AlwaysOnTop int alwaysOnTop) {switch (alwaysOnTop) {case ALWAYS_ON_TOP_UNDEFINED: return undefined;case ALWAYS_ON_TOP_ON: return on;case ALWAYS_ON_TOP_OFF: return off;}return String.valueOf(alwaysOnTop);}
}
//frameworks/base/core/java/android/view/Surface.java
public class Surface implements Parcelable {public static String rotationToString(int rotation) {switch (rotation) {case Surface.ROTATION_0: {return ROTATION_0;}case Surface.ROTATION_90: {return ROTATION_90;}case Surface.ROTATION_180: {return ROTATION_180;}case Surface.ROTATION_270: {return ROTATION_270;}default: {return Integer.toString(rotation);}}}
}当我们调用如下方法 Log.i(TAG, getWindowInfo: config getResources().getConfiguration());或者通过dumpsys window windows导出当前所有窗口的堆栈信息都可以得到和Configuration类相关的以下信息
config{1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w764dp h324dp 480dpi nrml long land finger -keyb/h/h -nav/h winConfig{ mBoundsRect(0, 0 - 2400, 1080) mAppBoundsRect(107, 0 - 2400, 1080) mMaxBoundsRect(0, 0 - 2400, 1080) mDisplayRotationROTATION_90 mWindowingModefullscreen mDisplayWindowingModefullscreen mActivityTypestandard mAlwaysOnTopundefined mRotationROTATION_90} s.2 fontWeightAdjustment0mThemeChanged 0, mThemeChangedFlags 0, mFlipFont 0, mAccessibleChanged -1, mUxIconConfig 3468921665126662176, mMaterialColor 0, mUserId 0, mFontUserId 0, mFontVariationSettings 226, mFoldingAngle -1.0, mIconPackName , mDarkModeBackgroundMaxL 0.0, mDarkModeDialogBgMaxL 27.0, mDarkModeForegroundMinL 100.0, mOplusConfigType 1, mOplusChangedConfigs 0, OpSans 0, mBurmeseFontFlag 2, mFlag 0, mPuttDisplayFlag -1}这里我们重点关注和WindowConfiguration相关的信息
winConfig{ mBoundsRect(0, 0 - 2400, 1080) mAppBoundsRect(107, 0 - 2400, 1080) mMaxBoundsRect(0, 0 - 2400, 1080) mWindowingModefullscreen mDisplayWindowingModefullscreen mActivityTypestandard mAlwaysOnTopundefined mRotationROTATION_90}mBoundsRect(0, 0 - 2400, 1080)屏幕尺寸mAppBoundsRect(107, 0 - 2400, 1080)窗口可显示的安全区域此属性会影响应用具体加载那个layout下面的布局文件系统会优先选择尺寸最接近2293x1080的布局文件。mMaxBoundsRect(0, 0 - 2400, 1080)窗口可显示的最大区域mWindowingModefullscreen窗口为全屏模式mDisplayWindowingModefullscreen屏幕设备窗口为全屏模式mActivityTypestandard页面类型未定义mAlwaysOnTopundefined窗口悬浮模式未定义mRotationROTATION_90屏幕设备的旋转角度为90度
借助这些属性开发者能够更好地适配不同的设备配置和屏幕状态确保应用在不同环境下的一致性和优化。
四、修改WindowConfiguration的配置信息刷新窗口UI视图
4.1 通过adb 修改屏幕旋转角度
我们可以通过以下指令获取当前屏幕的旋转角度
adb shell settings get system user_rotation #0自然方向竖屏1右旋转 90 度横屏2倒转 180 度反向竖屏3左旋转 270 横屏还可以通过如下配置修改当前屏幕的旋转角度
adb shell settings put system user_rotation value4.2 实现原理
当我们修改system数据库中的user_rotation字段的时候会触发以下代码逻辑。 frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java //frameworks/base/core/java/android/provider/Settings.java
public final class Settings {public static final String USER_ROTATION user_rotation;
}
public class DisplayRotation {private final WindowManagerService mService;private class SettingsObserver extends ContentObserver {SettingsObserver(Handler handler) {super(handler);}void observe() {final ContentResolver resolver mContext.getContentResolver();...代码省略...//注释1监听system数据库user_rotation字段的变化resolver.registerContentObserver(Settings.System.getUriFor(Settings.System.USER_ROTATION), false, this,UserHandle.USER_ALL);updateSettings();}Overridepublic void onChange(boolean selfChange) {//注释2判断设置是否发生了变化如果发生了变化调用WMS的updateRotation方法if (updateSettings()) {mService.updateRotation(true /* alwaysSendConfiguration */,false /* forceRelayout */);}}}private boolean updateSettings() {final ContentResolver resolver mContext.getContentResolver();boolean shouldUpdateRotation false;synchronized (mLock) {...代码省略...//获取当前屏的旋转角度final int userRotation Settings.System.getIntForUser(resolver,Settings.System.USER_ROTATION, Surface.ROTATION_0,UserHandle.USER_CURRENT);if (mUserRotation ! userRotation) {mUserRotation userRotation;shouldUpdateRotation true;}...代码省略...return shouldUpdateRotation;}}在注释1处DisplayRotation类会监听system数据库的user_rotation字段的变化当该字段发生变化的时候会在注释2处调用WindowManagerServices的updateRotation方法来通知窗口当前屏幕的旋转角度发生了变化。
4.3 WindowManagerService的updateRotation方法 frameworksbase/services/core/java/com/android/server/wm/WindowManagerService.java public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {//更新当前的屏幕的旋转角度Overridepublic void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);}private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {...代码省略...try {synchronized (mGlobalLock) {boolean layoutNeeded false;final int displayCount mRoot.mChildren.size();for (int i 0; i displayCount; i) {final DisplayContent displayContent mRoot.mChildren.get(i);Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, updateRotation: display);final boolean rotationChanged displayContent.updateRotationUnchecked();Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);if (rotationChanged) {mAtmService.getTaskChangeNotificationController().notifyOnActivityRotation(displayContent.mDisplayId);}if (!rotationChanged || forceRelayout) {displayContent.setLayoutNeeded();layoutNeeded true;}if (rotationChanged || alwaysSendConfiguration) {//更新屏幕设备的配置信息displayContent.sendNewConfiguration();}}...代码省略...}} finally {Binder.restoreCallingIdentity(origId);Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}} }
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {void setLayoutNeeded() {mLayoutNeeded true;}void sendNewConfiguration() {if (!isReady()) {return;}if (mDisplayRotation.isWaitingForRemoteRotation()) {return;}//更新屏幕设备的配置信息final boolean configUpdated updateDisplayOverrideConfigurationLocked();if (configUpdated) {return;}}boolean updateDisplayOverrideConfigurationLocked() {final RecentsAnimationController recentsAnimationController mWmService.getRecentsAnimationController();if (recentsAnimationController ! null) {recentsAnimationController.cancelAnimationForDisplayChange();}Configuration values new Configuration();computeScreenConfiguration(values);mAtmService.mH.sendMessage(PooledLambda.obtainMessage(ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,mDisplayId));Settings.System.clearConfiguration(values);updateDisplayOverrideConfigurationLocked(values, null /* starting */,false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);return mAtmService.mTmpUpdateConfigurationResult.changes ! 0;}}