当前位置: 首页 > news >正文

经营网站需要什么费用html5 js全屏滑动网站源码

经营网站需要什么费用,html5 js全屏滑动网站源码,成都网站建设时代汇创,用ps做网站尺寸一 概述 本篇文章主要讲 Window、WindowManager、WindowManagerService 三者之间的关系及其运行机制。总的来说 Window 表示的是一种抽象的功能集合#xff0c;具体实现为 PhoneWindow。WindowManager 是外界访问 Window 的入口#xff0c;对 Window 的访问必须通过 Window…一 概述 本篇文章主要讲 Window、WindowManager、WindowManagerService 三者之间的关系及其运行机制。总的来说 Window 表示的是一种抽象的功能集合具体实现为 PhoneWindow。WindowManager 是外界访问 Window 的入口对 Window 的访问必须通过 WindowManager而 WindowManager 和 WindowManagerService 的交互是一个 IPC 过程。Android 中所有的视图都是通过 Window 来呈现的不管是 Activity、Dialog、Toast他们的视图都是附加在 Window 上的。Window 是一个抽象概念每一个 Window 都对应着一个 View 和一个 ViewRootImplWindow 和 View 通过 ViewRootImpl 来建立联系。View 才是 Window 存在的实体可以理解为 WindowManager 中的 addView() 方法即为 add 一个 Window。 如上图所示我们平时所见的一个窗口是由一个根 View 和一个 Window 绑定然后这一个 Window 统一被 WindowManagerService 所管理。这些被 WindowManagerService 所管理的 Window 按照一定的次序和位置通过 SurfaceFlinger 显示到最终屏幕上。上图里面没有提到 WindowManager WindowManager 在其中扮演的是这么一个角色用户想添加更新或者移除 Window 是通过调用 WindowManager 的方法来操作。而用户的这些操作指令从 WindowManager 通过 IPC 传递到 WindowManagerService最后由 WindowManagerService 来统筹安排这些 Window 的布局和次序。接下来详细说明其中的运作机制。 1.1 Window Window 表示一个窗口。其实不管是 Activity、Dialog、还是 Toast 他们的视图实际上都是附加在 Window 上的。Window 有三种类型分别是应用 Window、子 Window 和系统 Window。应用类 Window 对应一个 Acitivity子 Window 不能单独存在需要依附在特定的父 Window 中比如常见的一些 Dialog 就是一个子 Window。系统 Window 是需要声明权限才能创建的 Window比如 Toast 和系统状态栏都是系统 Window。 Window 是分层的每个 Window 都有对应的 z-ordered层级大的会覆盖在层级小的 Window 上面。在三种 Window 中应用 Window 层级范围是 1~99子 Window 层级范围是 1000~1999系统 Window 层级范围是 2000~2999这些层级范围对应着 WindowManager.LayoutParams 的 type 参数如果想要 Window 位于所有 Window 的最顶层那么采用较大的层级即可很显然系统 Window 的层级是最大的当我们采用系统层级时需要声明权限。 Window 是一个抽象概念每一个 Window 都对应着一个根 View 和一个 ViewRootImplWindow 和 View 通过 ViewRootImpl 来建立联系。如下图所示 其中 ViewRootImpl 负责对 View 的渲染具体如何实现在后续文章会介绍在此先行略过。 1.2  WindowManager WindowManager 是整个窗口管理机制里面的枢纽也是需要重点要介绍的。WindowManager 实现了 ViewManager 接口这个接口定义了我们对于 Window 的基本操作 public interface ViewManager {public void addView(View view, ViewGroup.LayoutParams params);public void updateViewLayout(View view, ViewGroup.LayoutParams params);public void removeView(View view); }这三个方法其实就是 WindowManager 对外提供的主要功能即添加 View、更新 View 和删除 View。看一个通过 WindowManager 添加 Window 的例子 public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Button floatingButton new Button(MainActivity.this);floatingButton.setText(button);WindowManager.LayoutParams layoutParams new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,0, 0,PixelFormat.TRANSPARENT);// flag 设置 Window 属性layoutParams.flags WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;// type 设置 Window 类别层级layoutParams.type WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;layoutParams.gravity Gravity.CENTER;WindowManager windowManager getWindowManager();windowManager.addView(floatingButton, layoutParams);} }如下效果 代码中并没有调用 Activity 的 setContentView 方法而是直接通过 WindowManager 添加 Window并将其 type 设置为 TYPE_APPLICATION_OVERLAY。表示在所有应用之上。由效果图可以看到这个 Button 并不是在 MainActivity 对应的那个 View 里面而是一个类似独立的存在。其实从这里可以感受到真正承载 View 的其实是 Window同时也可以猜出之所以 Activity 会对应一个页面是因为 Activity 持有 Window 从而来持有 View对于窗口显示来说Activity 其实不是必须存在的。比如我们常用的 Toast 它其实就没有与之对应的 Activity而是类似于上述 Button 产生的方式产生在界面上的。接下来我们用源码的角度看下 Activity 中是如何创建 Window 的。 1.3 Activity 中 Window 创建过程 在 Activity 启动过程中 ActivityThread 会调用 performLaunchActivity() 这个函数这个函数里面会经过层层深入会调用 Activity 的 OnCreate() 方法而在 performLaunchActivity() 中调 OnCreate() 方法前会调用 Activity 的 attach() 方法今天我们要关注的就是这个方法 // Activity.java final void attach(Context context, ActivityThread aThread, ......) {attachBaseContext(context);......// 创建PhoneWindow并设置其回调接口mWindow new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);......// 将该Window和WindowManager绑定mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! 0);......// 设置管理Activity的Window的WindowManagermWindowManager mWindow.getWindowManager();...... }在 attach() 这个方法中创建了 Activity 的 Window同时为该 Window 绑定 WindowManager将这个 WindowManager 传给 Activity 的成员变量 mWindowManager。同时我们可以看到 Window 的具体实现类是 PhoneWindow。 进去 setWindowManager() 方法中看一下 public void setWindowManager(WindowManager wm, IBinder appToken,String appName, boolean hardwareAccelerated) {......if (wm null) {wm (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);}mWindowManager ((WindowManagerImpl)wm).createLocalWindowManager(this); }该方法里面可以看到如果传入的 wm 为空则将其重新赋值。这里其实是获取了 WindowManagerService 的代理因为 WindowManagerService 和 Activity 所在的应用不在一个进程里这里是通过 Binder 通信获取的一个 WindowManagerService 代理。获取完 WindowManagerService 代理后通过它来创建出一个真正要用的 WindowManager 并赋值。即这句代码 mWindowManager ((WindowManagerImpl)wm).createLocalWindowManager(this);public WindowManagerImpl createLocalWindowManager(Window parentWindow) {return new WindowManagerImpl(mContext, parentWindow); }这个函数很简单只是创建了一个 WindowManagerImpl 对象。从这里可以看到 WindowManager 真正的实现类是WindowManagerImpl。 到此我们对 Activity 的 attach() 方法分析的差不多了这个方法主要是创建出 Activity 的 Window 对象并且获取了管理该 Window 的 WindowManager。而此时其实并没有将 Activity 对应的 View 附属到这个 Window 中。而将这个 View 附属到 Window 的代码其实就是我们在 OnCreate() 中使用的 setContentView(int layoutResID) public void setContentView(LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar(); }该方法最终调用的是 getWindow() 的 setContentView而 getWindow() 获取的就是在 attach() 中创建的 PhoneWindow我们再进去看一下 public void setContentView(int layoutResID) {if (mContentParent null) {installDecor();//创建DecorView} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {final Scene newScene Scene.getSceneForLayout(mContentParent, layoutResID,getContext());transitionTo(newScene);} else {//inflate layoutResIDmLayoutInflater.inflate(layoutResID, mContentParent);}mContentParent.requestApplyInsets();final Callback cb getCallback();if (cb ! null !isDestroyed()) {cb.onContentChanged();}mContentParentExplicitlySet true; }这里如果没有 DecorView 就创建一个DecorView 是 Activity 中的顶级 View是一个 FrameLayout一般来说它的内部包含标题栏和内容栏但是这个会随着主题的变化而改变不管怎么样内容栏是一定存在的并且有固定 id”android.R.id.content”。而内容栏里面就是将用户自定义的 layout 放进去。之后再回调 onContentChanged() 通知 Activity 视图已经发生改变。此时就将 View 和 Window 关联了起来。不过现在仍然没有将对应的画面展示到手机屏幕上。因为此时还没讲 Window 加入到 WindowManager 中更不要说还要提交给 WindowManagerService 来统筹安排展示了。 Window 加入到 WindowManager 这一过程要在调用完 Acitivy 的 onResume() 方法后来实现之后会调用 Activity 的 makeVisible() void makeVisible() {if (!mWindowAdded) {ViewManager wm getWindowManager();wm.addView(mDecor, getWindow().getAttributes());mWindowAdded true;}mDecor.setVisibility(View.VISIBLE); }这个函数里首先判断 Window 是否已经添加到 WindowManager 中没有的话取出在刚刚 attach() 方法中创建的 WindowManager将 DecorView 加入进去这里的 DecorView 其实就是 Window 所持有那个。然后再将 DecorView 设置为显示状态来显示我们的布局。 至此才正真将 Window 加入到 WindowManager 中。接下来我们看一下 WindowManager 里面的几个核心方法。 1.4 WindowManager的核心方法 在实际使用中无法直接访问 Window对 Window 的访问必须通过 WindowManager。我们已经知道 WindowManager 提供的三个接口方法 addView、updateViewLayout 以及 removeView 都是针对 View 的而这些 View 都被其对应的 Window 所持有所以上面这些操作实际上相当于对 Window 的操作WindowManager 是一个接口它的真正实现由上文可知是 WindowManagerImpl 类。 看一下 WindowManagerImpl 的这三个方法 Override public void addView(NonNull View view, NonNull ViewGroup.LayoutParams params) {applyDefaultToken(params);mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }Override public void updateViewLayout(NonNull View view, NonNull ViewGroup.LayoutParams params) {applyDefaultToken(params);mGlobal.updateViewLayout(view, params); }public void removeView(View view) {mGlobal.removeView(view, false); }可以看到这三个方法都交给了 mGlobal 去实现而 mGlobal 是一个 WindowManagerGlobal 类。我们看一下 WindowManagerGlobal 的 addView() 方法至于 updateViewLayout() 和 removeView() 原理类似只是一个用来添加 View另两个用来更新和移除 View。 public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {......final WindowManager.LayoutParams wparams (WindowManager.LayoutParams) params;......ViewRootImpl root;View panelParentView null;synchronized (mLock) {......int index findViewLocked(view, false);if (index 0) {......}......root new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);// do this last because it fires off messages to start doing thingstry {root.setView(view, wparams, panelParentView);} catch (RuntimeException e) {// BadTokenException or InvalidDisplayException, clean up.if (index 0) {removeViewLocked(index, true);}throw e;}}}在 WindowManagerGlobal 内部有如下几个集合比较重要 private final ArrayListView mViews new ArrayListView();private final ArrayListViewRootImpl mRoots new ArrayListViewRootImpl();private final ArrayListWindowManager.LayoutParams mParams new ArrayListWindowManager.LayoutParams();private final ArraySetView mDyingViews new ArraySetView();其中 mViews 存储的是所有 Window 所对应的 ViewmRoots 存储的是所有 Window 所对应的 ViewRootImplmParams 存储的是所有 Window 所对应的布局参数mDyingViews 存储了那些正在被删除的 View 对象或者说是那些已经调用了 removeView 方法但是操作删除还未完成的 Window 对象。在 addView () 方法中将这些相关对象添加到对应集合中。最后调用 root.setView() 方法 ViewRootImpl.java public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {if (mView null) {mView view;...... int res; /* WindowManagerImpl.ADD_OKAY; */ requestLayout();......try {mOrigWindowType mWindowAttributes.type;mAttachInfo.mRecomputeGlobalAttributes true;collectViewAttributes();res mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,mTempInsets);setFrame(mTmpFrame);} catch (RemoteException e) {......} finally {......}...... }} }setView() 中会调用一个很重要的方法 requestLayout()其主要是用来刷新页面其中还有一个很重要的方法 addToDisplay framework/base/services/core/java/com/android/server/wm/Session.java   Overridepublic int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,InsetsState outInsetsState) {return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,outInsetsState);}mWindowSession 的类型是 IWindowSession它是一个 Binder 对象真正的实现类是 Session这也就是之前提到的 IPC 调用的位置。也就是说在这里完成了 WindowManager 和 WindowManagerService 的通信将 Window 信息传给了WindowManagerService。 1.5 WindowManagerService 上文已经通过 WindowManagerService 的代理调用了其 addWindow() 方法该方法非常复杂。主要的操作就是将传来的 Window 根据它的参数尤其是其 type保存起来。方便 SurfaceFlinger 渲染。 WindowManagerService 服务大致按照以下方式来控制哪些窗口需要显示以及要显示在哪里 由于每一个 Activity 窗口的大小都等于屏幕的大小因此只要对每一个 Activity 窗口设置一个不同的 Z 轴位置然后就可以使得位于最上面的即当前被激活的 Activity 窗口才是可见的。 每一个子窗口的 Z 轴位置都比它的父窗口大但是大小要比父窗口小这时候 Activity 窗口及其所弹出的子窗口都可以同时显示出来。 对于非全屏 Activity 窗口来说它会在屏幕的上方留出一块区域用来显示状态栏。这块留出来的区域称对于屏幕来说称为装饰区decoration而对于 Activity 窗口来说称为内容边衬区Content Inset。 输入法窗口只有在需要的时候才会出现它同样是出现在屏幕的装饰区或者说 Activity 窗口的内容边衬区的。 对于壁纸窗口它出现需要壁纸的 Activity 窗口的下方这时候要求 Activity 窗口是半透明的这样就可以将它后面的壁纸窗口一同显示出来。 两个 Activity 窗口在切换过程实际上就是前一个窗口显示退出动画而后一个窗口显示开始动画的过程而在动画的显示过程中窗口的大小会有一个变化的过程这样就导致前后两个 Activity 窗口的大小不再都等于屏幕的大小因而它们就有可能同时都处于可见的状态。事实上Activity 窗口的切换过程是相当复杂的因为即将要显示的 Activity 窗口可能还会被设置一个启动窗口Starting Window。一个被设置了启动窗口的 Activity 窗口要等到它的启动窗口显示了之后才可以显示出来。 同时在 Android 系统中WindowManagerService 服务是通过一个实现了 WindowManagerPolicy 接口的策略类来计算一个窗口的位置和大小的。例如在 Phone 平台上这个策略类就是 PhoneWindowManager。这样做的好处就是对于不同的平台实现不同的策略类来达到不同的窗口控制模式。 1.6 总结 创建 Window将 View 和 ViewRootImpl 同 Window 绑定。 WindowManager 的 addView()、updateViewLayout() 和 removeView() 方法操作 Window。 将 WindowManager 这些操作方法转移给 WindowManagerGobal 来调用。 调用与 Window 绑定的 ViewRootImpl 的 setView() 方法。 setView() 方法里面会通过 mWindowSession 这个 Binder 对象将 Window 传给 WindowManagerService。 WindowManagerService 来管理各个 Window 的大小和显示位置来让 SurfaceFlinger 渲染。 二 WMS启动过程 在 Android 系统中从设计的角度来看窗口管理系统是基于 C/S 模式的。整个窗口系统分为服务端和客户端两大部分客户端负责请求创建窗口和使用窗口服务端完成窗口的维护窗口显示等。 在 Client 端并不是直接和 WindowManagerService 交互而是直接和本地对象 WindowManager 交互然后由 WindowManager 完成和 WindowManagerService 的交互。对于 Android 应用来说这个交互是透明的应用感觉不到 WindowManagerService 的存在。本篇文章我们来介绍窗口管理服务 WindowManagerService 的启动过程。 2.1 WMS全貌 2.2 WMS功能  窗口管理 WMS 是窗口的管理者它负责窗口的启动、添加和删除另外窗口的大小和层级也是由 WMS 进行管理的。窗口管理的核心成员有 DisplayContent、WindowToken 和 WindowState。 窗口动画 窗口间进行切换时使用窗口动画可以显得更炫一些窗口动画由 WMS 的动画子系统来负责动画子系统的管理者为 WindowAnimator。 输入系统的中转站 通过对窗口的触摸从而产生触摸事件InputManagerServiceIMS会对触摸事件进行处理它会寻找一个最合适的窗口来处理触摸反馈信息WMS 是窗口的管理者因此WMS “理所应当” 的成为了输入系统的中转站。 Surface管理 窗口并不具备有绘制的功能因此每个窗口都需要有一块 Surface 来供自己绘制。为每个窗口分配 Surface 是由 WMS 来完成的。WMS 的职责可以简单总结为下图。 2.3 WMS重要成员  说明 WMS 继承于 IWindowManager.Stub作为 Binder 服务端 mSessions ArraySet 类型的变量元素类型为 Session保存着所有的 Session 对象Session 继承于 IWindowSession.Stub作为 Binder 服务端它主要用于进程间通信其他的应用程序进程想要和 WMS 进程进行通信就需要经过 Session并且每个应用程序进程都会对应一个SessionWMS 保存这些 Session 用来记录所有向 WMS 提出窗口管理服务的客户端。 mPolicy WindowManagerPolicy 类型的变量是窗口管理策略的接口类用来定义一个窗口策略所要遵循的通用规范并提供了 WindowManager 所有的特定的 UI 行为。具体实现类为 PhoneWindowManager这个实现类在 WMS 创建时被创建。WMP 允许定制窗口层级和特殊窗口类型以及关键的调度和布局。 DisplayContent 的成员变量 mTokenMap保存所有的 WindowToken 对象以 IBinder 为 key可以是 IAppWindowToken 或者其他 Binder 的 Bp 端另一端情况ActivityRecord.Token extends IApplicationToken.Stub mWindowMap WindowHashMap 类型的变量WindowHashMap 继承了 HashMap它限制了 HashMap 的 key 值的类型为 IBindervalue 值的类型为 WindowState。保存 WMS 中所有的 WindowState 对象mResizingWindows ArrayList 类型的变量元素类型为 WindowState。mResizingWindows 是用来存储正在调整大小的窗口的列表。mAnimator WindowAnimator 类型的变量用于管理窗口的动画以及特效动画。mH H 类型的变量系统的 Handler 类用于将任务加入到主线程的消息队列中这样代码逻辑就会在主线程中执行。 涉及代码如下 frameworks/base/services/java/com/android/server/SystemServer.java frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java frameworks/base/services/core/java/com/android/server/DisplayThread.java frameworks/base/services/core/java/com/android/server/wm/WindowState.java frameworks/base/services/core/java/com/android/server/wm/AppWindowToken.java frameworks/base/services/core/java/com/android/server/input/InputManagerService.java frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java frameworks/base/services/core/java/com/android/server/wm/TaskPositioningController.java frameworks/base/services/core/java/com/android/server/wm/DragDropController.java2.4 SystemServer frameworks/base/services/java/com/android/server/SystemServer.java 2.4.1 main /*** The main entry point from zygote.*/ public static void main(String[] args) {new SystemServer().run(); }private void run() {......// 初始化系统上下文createSystemContext();// 初始化SystemServiceManagermSystemServiceManager new SystemServiceManager(mSystemContext);......// 启动相互依赖关系复杂的服务startBootstrapServices();// 启动相互独立的基本服务startCoreServices();// 启动其他服务startOtherServices();...... }2.4.2 startOtherServices private void startOtherServices() {// 启动WMS前, 需要先启动SensorServiceConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);mSensorServiceStart null;WindowManagerService wm WindowManagerService.main(context,inputManager, !mFirstBoot, mOnlyCore, new PhoneWindowManager(),mActivityManagerService.mActivityTaskManager);ServiceManager.addService(Context.WINDOW_SERVICE, wm, false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);......// 所有WMS相关的实体对象初始化完成wm.onInitReady();......// Display readywm.displayReady();......// WMS readywm.systemReady();......final WindowManagerService windowManagerF wm;// 启动SystemUIService服务startSystemUi(context, windowManagerF);...... }private static void startSystemUi(Context context,WindowManagerService windowManager) {Intent intent new Intent();intent.setComponent(new ComponentName(com.android.systemui,com.android.systemui.SystemUIService));intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);context.startServiceAsUser(intent, UserHandle.SYSTEM);// System UI已启动windowManager.onSystemUiStarted(); }2.5 WindowManagerService frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java 2.5.1  组成元素 // ActivityTaskManager服务相关 // 管理Activity和其容器(如task/stacks/displays)的系统服务 final IActivityTaskManager mActivityTaskManager; final ActivityTaskManagerService mAtmService;// DisplayManager服务相关, 管理Display属性 final DisplayManagerInternal mDisplayManagerInternal; final DisplayManager mDisplayManager; final DisplayWindowSettings mDisplayWindowSettings;// ActivityManager服务相关, 用于和四大组件交互 final IActivityManager mActivityManager; final ActivityManagerInternal mAmInternal;// PowerManager服务相关, 管理电源状态 PowerManager mPowerManager; PowerManagerInternal mPowerManagerInternal;// 输入管理服务 final InputManagerService mInputManager; // 包管理本地系统服务 final PackageManagerInternal mPmInternal;// 根窗口容器 RootWindowContainer mRoot; // 提供UI相关行为的策略类, 其实现类为PhoneWindowManager WindowManagerPolicy mPolicy; // 在一个单独的task中执行动画和Surface操作的类 final WindowAnimator mAnimator; // 用来确定Window和Surface位置的类 final WindowSurfacePlacer mWindowPlacerLocked; // 任务快照管理器(当App不可见时, 会将Task的快照以Bitmap形式存在缓存中) final TaskSnapshotController mTaskSnapshotController; // Task定位控制器 final TaskPositioningController mTaskPositioningController; // View的拖/拉操作控制器 final DragDropController mDragDropController;// 当前活跃状态的Session连接队列(通常一个进程中包含一个Session, 用于和WindowManager交互) final ArraySetSession mSessions new ArraySet(); // IBinder, WindowState客户端Window token和服务端WindowState的映射 final WindowHashMap mWindowMap new WindowHashMap();// AppWindowToken是一个窗口容器类, 可以理解为正在显示Window的App // 或Activity的窗口令牌(继承于WindowToken) // replace超时的AppWindowToken令牌列表 final ArrayListAppWindowToken mWindowReplacementTimeouts new ArrayList(); // WindowState表示服务端描述的Window final ArrayListWindowState mResizingWindows new ArrayList(); final ArrayListWindowState mPendingRemove new ArrayList(); final ArrayListWindowState mDestroySurface new ArrayList(); final ArrayListWindowState mDestroyPreservedSurface new ArrayList(); final ArrayListWindowState mForceRemoves new ArrayList(); ArrayListWindowState mWaitingForDrawn new ArrayList(); private ArrayListWindowState mHidingNonSystemOverlayWindows new ArrayList(); WindowState[] mPendingRemoveTmp new WindowState[20];// 主线程Handler final H mH new H();2.5.2 启动过程 2.5.2.1 main public static WindowManagerService main(final Context context,final InputManagerService im, final boolean showBootMsgs,final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm) {return main(context, im, showBootMsgs, onlyCore, policy, atm, SurfaceControl.Transaction::new); }public static WindowManagerService main(final Context context,final InputManagerService im, final boolean showBootMsgs,final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, TransactionFactory transactionFactory) {//运行在android.display线程DisplayThread.getHandler().runWithScissors(() -sInstance new WindowManagerService(context, im, showBootMsgs, onlyCore, policy, atm, transactionFactory), 0);return sInstance; }在 “android.display” 线程中执行 WindowManagerService 对象的初始化过程其中 final H mH new H()此处 H 继承于 Handler无参初始化的过程便会采用当前所在线程的 Looper。那就是说WindowManagerService.H.handleMessage() 方法运行在 “android.display” 线程。 2.5.2.2 Handler.runWithScissors  Handler.java public final boolean runWithScissors(final Runnable r, long timeout) {//当前线程跟当前Handler都指向同一个Looper,则直接运行if (Looper.myLooper() mLooper) {r.run();return true;}BlockingRunnable br new BlockingRunnable(r);return br.postAndWait(this, timeout); }2.5.2.3 postAndWait Handler.java ::BlockingRunnable private static final class BlockingRunnable implements Runnable {private final Runnable mTask;private boolean mDone;public BlockingRunnable(Runnable task) {mTask task;}public void run() {try {mTask.run();} finally {synchronized (this) {mDone true;notifyAll();}}}public boolean postAndWait(Handler handler, long timeout) {if (!handler.post(this)) {return false;}synchronized (this) {if (timeout 0) {final long expirationTime SystemClock.uptimeMillis() timeout;while (!mDone) {long delay expirationTime - SystemClock.uptimeMillis();if (delay 0) {return false; // timeout}try {wait(delay);} catch (InterruptedException ex) {}}} else {while (!mDone) {try {wait();} catch (InterruptedException ex) {}}}}return true;} }由此可见BlockingRunnable.postAndWait() 方法是阻塞操作就是先将消息放入 Handler 所指向的线程此处是指 ”android.display” 线程由于该方法本身运行在 system_server 主线程。也就意味着 system_server 主线程会进入等待状态直到 handler 线程执行完成后再唤醒 system_server 主线程。所以在 WindowManagerService 启动完成之后SystemServer 主线程才能继续往下走。 WMS 所在的线程就是 DisplayThread 这个显示线程这个线程不仅被 WMS 使用DisplayManagerService、InputManagerService 也会使用。当实例化 WindowManagerService 时它的成员变量 mH 就与 DisplayThread 产生了关联后期可以通过 mH 这个 handler 投递事件到 DisplayThread 的 looper 队列中。mH 是 WMS 的内部类 final class H extends Handler {}。 2.5.2.4 构造方法 private WindowManagerService(Context context, InputManagerService inputManager,boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, TransactionFactory transactionFactory) {installLock(this, INDEX_WINDOW);mGlobalLock atm.getGlobalLock();mAtmService atm;mContext context;mAllowBootMessages showBootMsgs;mOnlyCore onlyCore;// 各种变量读取mLimitedAlphaCompositing context.getResources().getBoolean(com.android.internal.R.bool.config_sf_limitedAlpha);mHasPermanentDpad context.getResources().getBoolean(com.android.internal.R.bool.config_hasPermanentDpad);mInTouchMode context.getResources().getBoolean(com.android.internal.R.bool.config_defaultInTouchMode);......mInputManager inputManager;mDisplayManagerInternal LocalServices.getService(DisplayManagerInternal.class);// Display设置mDisplayWindowSettings new DisplayWindowSettings(this);mTransactionFactory transactionFactory;mTransaction mTransactionFactory.make();//PhoneWindowManager(继承于WindowManagerPolicy, 用来提供UI相关的一些行为)mPolicy policy;// 在一个单独的task中执行动画和Surface操作的类mAnimator new WindowAnimator(this);// 根Window容器mRoot new RootWindowContainer(this);// 用来确定Window和Surface的位置mWindowPlacerLocked new WindowSurfacePlacer(this);// 任务快照管理器(当App不可见时, 会将Task的快照以Bitmap形式存在缓存中)mTaskSnapshotController new TaskSnapshotController(this);LocalServices.addService(WindowManagerPolicy.class, mPolicy);mDisplayManager (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);// Keyguard处理器mKeyguardDisableHandler KeyguardDisableHandler.create(mContext, mPolicy, mH);// PowerManager是控制设备电池状态的管理器mPowerManager (PowerManager)context.getSystemService(Context.POWER_SERVICE);// PowerManagerInternal是PowerMananger的本地服务mPowerManagerInternal LocalServices.getService(PowerManagerInternal.class);if (mPowerManagerInternal ! null) {mPowerManagerInternal.registerLowPowerModeObserver(new PowerManagerInternal.LowPowerModeListener() {Overridepublic int getServiceType() {return ServiceType.ANIMATION;}Overridepublic void onLowPowerModeChanged(PowerSaveState result) {synchronized (mGlobalLock) {// 低电量模式发生变化时, 需要调整对应的动画final boolean enabled result.batterySaverEnabled; if (mAnimationsDisabled ! enabled !mAllowAnimationsInLowPowerMode) {mAnimationsDisabled enabled;dispatchNewAnimatorScaleLocked(null);}}}});// 获取是否允许动画mAnimationsDisabled mPowerManagerInternal.getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;}mScreenFrozenLock mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, SCREEN_FROZEN);mScreenFrozenLock.setReferenceCounted(false);// 获取IActivity.Stub.Proxy(new BinderProxy())mActivityManager ActivityManager.getService();// 获取IActivityTaskManager.Stub.ProxymActivityTaskManager ActivityTaskManager.getService();// ActivityManagerInternal是ActivityManager的本地服务mAmInternal LocalServices.getService(ActivityManagerInternal.class);// ActivityTaskManagerInternal是ActivityTaskManager的本地服务mAtmInternal LocalServices.getService(ActivityTaskManagerInternal.class);mAppOps (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);AppOpsManager.OnOpChangedInternalListener opListener new AppOpsManager.OnOpChangedInternalListener() {Override public void onOpChanged(int op, String packageName) {updateAppOpsState();}};mAppOps.startWatchingMode(OP_SYSTEM_ALERT_WINDOW, null, opListener);mAppOps.startWatchingMode(AppOpsManager.OP_TOAST_WINDOW,null, opListener);// PackageManagerInternal是PackageManager的本地服务mPmInternal LocalServices.getService(PackageManagerInternal.class);// 注册Package suspend/unsuspend广播final IntentFilter suspendPackagesFilter new IntentFilter();suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);context.registerReceiverAsUser(new BroadcastReceiver() {Overridepublic void onReceive(Context context, Intent intent) {final String[] affectedPackages intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);final boolean suspended Intent.ACTION_PACKAGES_SUSPENDED.equals(intent.getAction());updateHiddenWhileSuspendedState(new ArraySet(Arrays.asList(affectedPackages)), suspended);}}, UserHandle.ALL, suspendPackagesFilter, null, null);// 获取并设置window scale设置final ContentResolver resolver context.getContentResolver();mWindowAnimationScaleSetting Settings.Global.getFloat(resolver,Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);......// 注册广播, 当DevicePolicyManager状态发生变化时设置keyguard属性是否可用IntentFilter filter new IntentFilter();filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);mContext.registerReceiverAsUser(mBroadcastReceiver,UserHandle.ALL, filter, null, null);mLatencyTracker LatencyTracker.getInstance(context);mSettingsObserver new SettingsObserver(); ...... mSurfaceAnimationRunner new SurfaceAnimationRunner(mPowerManagerInternal);mAllowTheaterModeWakeFromLayout context.getResources().getBoolean(com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);// Task定位控制器mTaskPositioningController new TaskPositioningController(this,mInputManager, mActivityTaskManager, mH.getLooper());// View的拖/拉操作控制器mDragDropController new DragDropController(this, mH.getLooper()); ......// 注册WindowManager的本地服务WindowManagerInternalLocalServices.addService(WindowManagerInternal.class, new LocalService()); }2.2.5.5 onInitReady public void onInitReady() {// 初始化PhoneWindowManagerinitPolicy();// 添加Watchdog monitorWatchdog.getInstance().addMonitor(this); // 调用SurfaceControl.openTransaction(), 启动一个事务openSurfaceTransaction();// 创建水印createWatermarkInTransaction();// 结束事务closeSurfaceTransaction(createWatermarkInTransaction); // 显示模拟器显示层showEmulatorDisplayOverlayIfNeeded(); }2.5.2.6 initPolicy private void initPolicy() {UiThread.getHandler().runWithScissors(new Runnable() {Overridepublic void run() {WindowManagerPolicyThread.set(Thread.currentThread(),Looper.myLooper());mPolicy.init(mContext, WindowManagerService.this,WindowManagerService.this);}}, 0);}PhoneWindowManager 的初始化运行在 “android.ui” 线程。 2.5.2.7 displayReady public void displayReady() {synchronized (mGlobalLock) {// 设置RootWindowContainer的Window列表的最大宽度if (mMaxUiWidth 0) {mRoot.forAllDisplays(displayContent - displayContent.setMaxUiWidth(mMaxUiWidth));}final boolean changed applyForcedPropertiesForDefaultDisplay();mAnimator.ready();mDisplayReady true;if (changed) {// 重新配置DiaplayContent属性reconfigureDisplayLocked(getDefaultDisplayContentLocked());}mIsTouchDevice mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);}// 1.修改当前configuration 2.确保当前Activity正在运行当前configurationmActivityTaskManager.updateConfiguration(null);// 更新CircularDisplayMaskupdateCircularDisplayMaskIfNeeded(); }2.5.2.8 systemReady public void systemReady() {mSystemReady true;mPolicy.systemReady();mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);mTaskSnapshotController.systemReady();// 是否支持色域mHasWideColorGamutSupport queryWideColorGamutSupport();// 是否支持HDR渲染mHasHdrSupport queryHdrSupport();UiThread.getHandler().post(mSettingsObserver::updateSystemUiSettings);UiThread.getHandler().post(mSettingsObserver::updatePointerLocation);// 获取IVrManager.Stub.Proxy, 并注册状态变化listenerIVrManager vrManager IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE));if (vrManager ! null) {final boolean vrModeEnabled vrManager.getVrModeState();synchronized (mGlobalLock) {vrManager.registerListener(mVrStateCallbacks);if (vrModeEnabled) {mVrModeEnabled vrModeEnabled;mVrStateCallbacks.onVrStateChanged(vrModeEnabled);}}} }2.6 总结 整个启动过程涉及3个线程system_server 主线程“android.display”“android.ui”整个过程是采用阻塞方式(利用 Handler.runWithScissors) 执行的。其中 WindowManagerService.mH 的 Looper 运行在 “android.display” 进程也就意味着 WMS.H.handleMessage() 在该线程执行。 流程如下 三 创建和添加Window  主要从系统和应用两个层次分析 Window 的添加过程以及论述重要组件之间的关系 SystemUI (如 StatusBar) 和 Activity 中 Window 的创建和添加 Activity / PhoneWindow / DecorView / StatusBar / ViewRootImpl 之间的关系 涉及代码如下 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.javaframeworks/base/core/java/android/app/ContextImpl.java frameworks/base/core/java/android/app/ActivityThread.java frameworks/base/core/java/android/app/Activity.java frameworks/base/core/java/android/view/WindowManagerImpl.java frameworks/base/core/java/android/view/Window.java frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java frameworks/base/core/java/com/android/internal/policy/DecorView.javaframeworks/base/packages/SystemUI/AndroidManifest.xml frameworks/base/packages/SystemUI/res/values/config.xml frameworks/base/packages/SystemUI/res/layout/super_status_bar.xml frameworks/base/packages/SystemUI/res/layout/status_bar.xml frameworks/base/core/res/res/layout/screen_simple.xml3.1 系统窗口的添加 SystemUI 包括很多子类, 状态栏 StatusBar 是最常见的一种。本文以 StatusBar 为例进行分析。 SystemUI 运行的进程名是 SystemUIApplication。 3.1.1 SystemUIApplication frameworks/base/packages/SystemUI/AndroidManifest.xml applicationandroid:name.SystemUIApplicationandroid:persistenttrueandroid:allowClearUserDatafalseandroid:allowBackupfalseandroid:hardwareAcceleratedtrueandroid:labelstring/app_labelandroid:icondrawable/iconandroid:processcom.android.systemuiandroid:supportsRtltrueandroid:themestyle/Theme.SystemUIandroid:defaultToDeviceProtectedStoragetrueandroid:directBootAwaretrueandroid:appComponentFactoryandroidx.core.app.CoreComponentFactory...service android:nameSystemUIService android:exportedtrue/... /applicationSystemUI 调用链 SystemUIApplication.onCreate - SystemUIService.onCreate - SystemUIApplication.startServicesIfNeeded - mServices[i].start() - SystemBars.start 3.1.2 SystemBars.start frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java public class SystemBars extends SystemUI {private SystemUI mStatusBar;Overridepublic void start() {createStatusBarFromConfig();}private void createStatusBarFromConfig() {// 从config.xml中读取className-com.android.systemui.statusbar.phone.StatusBarfinal String clsName mContext.getString(R.string.config_statusBarComponent);// 反射创建StatusBar对象Class? cls mContext.getClassLoader().loadClass(clsName);mStatusBar (SystemUI) cls.newInstance();mStatusBar.mContext mContext;mStatusBar.mComponents mComponents;// 将StatusBar注入系统UI的根组件if (mStatusBar instanceof StatusBar) {SystemUIFactory.getInstance().getRootComponent().getStatusBarInjector().createStatusBar((StatusBar) mStatusBar);}// 创建状态栏View, 并将其添加到WindowManagermStatusBar.start();} }SystemBars.start 做的事情 读取配置文件中的属性 config_statusBarComponent得到字符串 className 为 StatusBar 的字符串 利用反射创建 StatusBar 对象并调用 StatusBar 的 start 方法用来创建状态栏 View 并将其添加到 WindowManager 中 3.1.3 StatusBar 3.1.3.1 StatusBar.start frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java public class StatusBar extends SystemUI implements DemoMode,ActivityStarter, OnUnlockMethodChangedListener,OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,ColorExtractor.OnColorsChangedListener, ConfigurationListener,StatusBarStateController.StateListener, ShadeController,ActivityLaunchAnimator.Callback, AmbientPulseManager.OnAmbientChangedListener,AppOpsController.Callback {protected WindowManager mWindowManager;protected IWindowManager mWindowManagerService;// 状态栏最外层Viewprotected StatusBarWindowView mStatusBarWindow;// CollapsedStatusBarFragment的根View(即StatusBarWindowView的childView)protected PhoneStatusBarView mStatusBarView;Overridepublic void start() {......// 获取WindowManagerImplmWindowManager (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);// 获取IWindowManager.Stub.ProxymWindowManagerService WindowManagerGlobal.getWindowManagerService();......// 创建状态栏View, 并将其添加到WindowManagercreateAndAddWindows(result);......}...... }3.1.3.2 StatusBar.createAndAddWindows // 创建状态栏View, 并将其添加到WindowManager public void createAndAddWindows(Nullable RegisterStatusBarResult result) {// 根据布局文件super_status_bar.xml创建StatusBarWindowView. makeStatusBarView(result);mStatusBarWindowController Dependency.get(StatusBarWindowController.class);// 将StatusBarWindowView添加到WindowManager. mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); }// 获取状态栏高度, App就是借鉴这个方法 public int getStatusBarHeight() {if (mNaturalBarHeight 0) {final Resources res mContext.getResources();mNaturalBarHeight res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);}return mNaturalBarHeight; }这里要提一下 getStatusBarHeight 这个方法App 开发中获取状态栏高度就是借鉴的这个方法只不过是反射获取该属性。基本思路就是看源码中 StatusBar 对应的布局然后读取其高度属性。  3.1.3.3 StatusBar.makeStatusBarView protected void makeStatusBarView(Nullable RegisterStatusBarResult result) {......// 根据布局文件super_status_bar.xml创建StatusBarWindowViewinflateStatusBarWindow(context);mStatusBarWindow.setService(this);mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());......// status_bar_container位置填充CollapsedStatusBarFragment// CollapsedStatusBarFragment对应的布局文件为status_bar.xmlFragmentHostManager.get(mStatusBarWindow).addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) - {// Fragment创建完成时, 初始化CollapsedStatusBarFragment statusBarFragment (CollapsedStatusBarFragment) fragment;statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);PhoneStatusBarView oldStatusBarView mStatusBarView;mStatusBarView (PhoneStatusBarView) fragment.getView();mStatusBarView.setBar(this);mStatusBarView.setPanel(mNotificationPanel);mStatusBarView.setScrimController(mScrimController);mStatusBarView.setBouncerShowing(mBouncerShowing);if (oldStatusBarView ! null) {float fraction oldStatusBarView.getExpansionFraction();boolean expanded oldStatusBarView.isExpanded();mStatusBarView.panelExpansionChanged(fraction, expanded);}......mStatusBarWindow.setStatusBarView(mStatusBarView);......}).getFragmentManager().beginTransaction().replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),CollapsedStatusBarFragment.TAG).commit();......// 创建导航栏(仅针对CarStatusBar)createNavigationBar(result);...... }3.1.3.4 StatusBar.inflateStatusBarWindow protected void inflateStatusBarWindow(Context context) {// 从super_status_bar.xml布局文件创建StatusBarWindowViewmStatusBarWindow (StatusBarWindowView) mInjectionInflater.injectable(LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null); }3.1.4 StatusBarWindowController.add frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java // Adds the status bar view to the window manager. public void add(ViewGroup statusBarView, int barHeight) {mLp new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,barHeight,WindowManager.LayoutParams.TYPE_STATUS_BAR,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,PixelFormat.TRANSLUCENT);mLp.token new Binder();mLp.gravity Gravity.TOP;mLp.softInputMode WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;mLp.setTitle(StatusBar);mLp.packageName mContext.getPackageName();mLp.layoutInDisplayCutoutMode LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;mStatusBarView statusBarView;mBarHeight barHeight;mWindowManager.addView(mStatusBarView, mLp);mLpChanged.copyFrom(mLp);onThemeChanged(); }总结 StatusBar.start 做的事情 一句话总结就是创建状态栏 View 并将其添加到 WindowManager 中。 具体过程为 根据布局文件 super_status_bar.xml 创建 StatusBarWindowView上述布局文件中 id 为 status_bar_container 的位置填充 CollapsedStatusBarFragment创建导航栏(仅针对 CarStatusBar )StatusBarWindowView 添加到 WindowManager 3.2 应用窗口添加 3.2.1 ActivityThread.performLaunchActivity frameworks/base/core/java/android/app/ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r,Intent customIntent) {...... try {......// 将Activity attach到Applicationactivity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken); ......}......return activity; }3.2.2 Activity.attach frameworks/base/core/java/android/app/Activity.java final void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,......) {attachBaseContext(context);......//创建PhoneWindowmWindow new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);......mUiThread Thread.currentThread(); mMainThread aThread;mInstrumentation instr;mToken token;...... //设置WindowManagerImplmWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! 0);//设置父Windowif (mParent ! null) {mWindow.setContainer(mParent.getWindow());} // 获取本地创建的WindowManagerImpl//(这个和上面setWindowManager设置进来不是同一个实例)mWindowManager mWindow.getWindowManager();...... }3.2.3 Activity.setContentView 在 Activity 启动过程中我们知道执行完 attach 方法后就要执行回调 Activity 的 onCreate 方法了我们会在 onCreate 方法中使用 setContentView(layoutResID)来完成布局文件的加载那么我们来看下 setContentView 这个方法的执行流程 public void setContentView(LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar(); }3.2.4 PhoneWindow.setContentView Override public void setContentView(int layoutResID) {if (mContentParent null) {installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {......} else {// 将布局layoutResID添加到DecorView中id为R.id.content的位置mLayoutInflater.inflate(layoutResID, mContentParent);}mContentParent.requestApplyInsets();final Callback cb getCallback();if (cb ! null !isDestroyed()) {cb.onContentChanged();}mContentParentExplicitlySet true; }3.2.5 ActivityThread.handleResumeActivity Override public void handleResumeActivity(IBinder token, ......) {...... final ActivityClientRecord r performResumeActivity(token, finalStateRequest, reason); final Activity a r.activity; ...... //当Window还未添加到WindowManager, 且还未finish当前Activity或//未启动新Activity时, 需要先添加到WindowManagerboolean willBeVisible !a.mStartedActivity;if (!willBeVisible) {willBeVisible ActivityTaskManager.getService().willActivityBeVisible(a.getActivityToken()); }if (r.window null !a.mFinished willBeVisible) {// 拿到PhoneWindowr.window r.activity.getWindow();// 拿到DecorViewView decor r.window.getDecorView();// 设置DecorView不可见decor.setVisibility(View.INVISIBLE);// 获取本地创建的WindowManagerImplViewManager wm a.getWindowManager();// 设置Window各属性(如type为TYPE_BASE_APPLICATION)WindowManager.LayoutParams l r.window.getAttributes();a.mDecor decor;l.type WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode | forwardBit;if (r.mPreserveWindow) {a.mWindowAdded true;r.mPreserveWindow false;// 获取DecorView的ViewPootImpl(每个View都有一个ViewRootImpl)ViewRootImpl impl decor.getViewRootImpl(); // 通知子View已经被重建(DecorView还是旧实例, // Activity是新实例, 因此需要更新callbacks) // 1.通常情况下, ViewRootImpl通过 //WindowManagerImpl#addView-ViewRootImpl#setView //设置Activity的callbacks回调 // 2.但是如果DecorView复用时, 需要主动告诉ViewRootImpl callbacks可能发生变化if (impl ! null) {impl.notifyChildRebuilt();}}// 当Activity可见时, 添加DecorView到WindowManagerImpl//或回调Window属性变化方法if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded true;wm.addView(decor, l);} else {a.onWindowAttributesChanged(l);}}} else if (!willBeVisible) {r.hideForNow true;}// Get rid of anything left hanging around.cleanUpPendingRemoveWindows(r, false /* force */);if (!r.activity.mFinished willBeVisible r.activity.mDecor ! null !r.hideForNow) {// 调用Activity.onConfigurationChanged方法if (r.newConfig ! null) {performConfigurationChangedForActivity(r, r.newConfig);r.newConfig null;}// 更新DecorView的LayoutParamsWindowManager.LayoutParams l r.window.getAttributes();if ((l.softInputMode WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)! forwardBit) {l.softInputMode (l.softInputMode (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) |forwardBit;if (r.activity.mVisibleFromClient) {ViewManager wm a.getWindowManager();View decor r.window.getDecorView();wm.updateViewLayout(decor, l);}}r.activity.mVisibleFromServer true;mNumVisibleActivities;// 设置Activity可见if (r.activity.mVisibleFromClient) {r.activity.makeVisible();}} r.nextIdle mNewActivities;mNewActivities r;Looper.myQueue().addIdleHandler(new Idler()); }在 Activity 创建过程中会创建和添加 PhoneWindow Activity 中 PhoneWindow 的创建和添加过程 handleLaunchActivity 过程 创建 Activity 和 Application 实例调用 Activity.attach 方法将 Activity attach 到 Application在 Activity 中创建 PhoneWindowPhoneWindow 又创建 DecorView。设置 WindowManagerImpl 到 PhoneWindow.调用 Activity.onCreate - setContentView(layoutResID) 将 layoutResId 添加到 DecorView 中 R.id.content 位置 handleResumeActivity 过程 PhoneWindow 中的 DecorView 添加到 WindowManager设置 DecorView 可见 3.3 PhoneWindowDecorView详解 我们已经分析了 Activity 中 PhoneWindow 的创建和添加过程在 Activity#onCreate 中会调用PhoneWindow#installDecor 创建 DecorView 和子 View。接下来我们来分析下 PhoneWindow 和 DecorView 的组成。 3.3.1 PhoneWindow frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java 3.3.1.1 PhoneWindow.installDecor // 创建DecorView及其子View private void installDecor() {mForceDecorInstall false;if (mDecor null) {// 创建DecorViewmDecor generateDecor(-1);mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);......} else {mDecor.setWindow(this);}if (mContentParent null) {// 根据设置的Window相关属性, 设置PhoneWindow特性//给PhoneWindow的根DecorView添加子View, 并返回ContentViewmContentParent generateLayout(mDecor); ...... // 对于R.layout.screen_simple没有该元素// 但对于R.layout.screen_action_bar包含该元素final DecorContentParent decorContentParent (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent); // 如果根View为ActionBarOverlayLayout, 则设置// ActionBarOverlayLayout的title/icon/logo/menu等if (decorContentParent ! null) {mDecorContentParent decorContentParent;mDecorContentParent.setWindowCallback(getCallback());if (mDecorContentParent.getTitle() null) {mDecorContentParent.setWindowTitle(mTitle);}final int localFeatures getLocalFeatures();for (int i 0; i FEATURE_MAX; i) {if ((localFeatures (1 i)) ! 0) {mDecorContentParent.initFeature(i);}}mDecorContentParent.setUiOptions(mUiOptions);if ((mResourcesSetFlags FLAG_RESOURCE_SET_ICON) ! 0 ||(mIconRes ! 0 !mDecorContentParent.hasIcon())) {mDecorContentParent.setIcon(mIconRes);} else if ((mResourcesSetFlags FLAG_RESOURCE_SET_ICON) 0 mIconRes 0 !mDecorContentParent.hasIcon()) {mDecorContentParent.setIcon(getContext().getPackageManager().getDefaultActivityIcon());mResourcesSetFlags | FLAG_RESOURCE_SET_ICON_FALLBACK;}if ((mResourcesSetFlags FLAG_RESOURCE_SET_LOGO) ! 0 ||(mLogoRes ! 0 !mDecorContentParent.hasLogo())) {mDecorContentParent.setLogo(mLogoRes);}PanelFeatureState st getPanelState(FEATURE_OPTIONS_PANEL, false);if (!isDestroyed() (st null || st.menu null) !mIsStartingWindow) {invalidatePanelMenu(FEATURE_ACTION_BAR);}} else {// 如果有title元素, 更新titlemTitleView findViewById(R.id.title);if (mTitleView ! null) {if ((getLocalFeatures() (1 FEATURE_NO_TITLE)) ! 0) {final View titleContainer findViewById(R.id.title_container);if (titleContainer ! null) {titleContainer.setVisibility(View.GONE);} else {mTitleView.setVisibility(View.GONE);}mContentParent.setForeground(null);} else {mTitleView.setText(mTitle);}}}......} }3.1.1.2 PhoneWindow.generateDecor protected DecorView generateDecor(int featureId) {......Context context;if (mUseDecorContext) {Context applicationContext getContext().getApplicationContext();if (applicationContext null) {context getContext();} else {context new DecorContext(applicationContext, getContext());if (mTheme ! -1) {context.setTheme(mTheme);}}} else {context getContext();}return new DecorView(context, featureId, this, getAttributes()); }3.1.1.3 PhoneWindow.generateLayout protected ViewGroup generateLayout(DecorView decor) {// Apply data from current theme.TypedArray a getWindowStyle();mIsFloating a.getBoolean(R.styleable.Window_windowIsFloating, false);int flagsToUpdate (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) (~getForcedWindowFlags());if (mIsFloating) {setLayout(WRAP_CONTENT, WRAP_CONTENT);setFlags(0, flagsToUpdate);} else {setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR,flagsToUpdate);}if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {requestFeature(FEATURE_NO_TITLE);} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {// Dont allow an action bar if there is no title.requestFeature(FEATURE_ACTION_BAR);} ...... final Context context getContext();......WindowManager.LayoutParams params getAttributes();...... // Inflate the window decor. int layoutResource;int features getLocalFeatures();// System.out.println(Features: 0x Integer.toHexString(features));if ((features (1 FEATURE_SWIPE_TO_DISMISS)) ! 0) {layoutResource R.layout.screen_swipe_dismiss;setCloseOnSwipeEnabled(true);} else if ((features ((1 FEATURE_LEFT_ICON) |(1 FEATURE_RIGHT_ICON))) ! 0) {if (mIsFloating) {TypedValue res new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogTitleIconsDecorLayout, res, true);layoutResource res.resourceId;} else {layoutResource R.layout.screen_title_icons;}// XXX Remove this once action bar supports these features.removeFeature(FEATURE_ACTION_BAR);// System.out.println(Title Icons!);} else if ((features ((1 FEATURE_PROGRESS) |(1 FEATURE_INDETERMINATE_PROGRESS))) ! 0 (features (1 FEATURE_ACTION_BAR)) 0) {layoutResource R.layout.screen_progress;// System.out.println(Progress!);} else if ((features (1 FEATURE_CUSTOM_TITLE)) ! 0) {// Special case for a window with a custom title.// If the window is floating, we need a dialog layoutif (mIsFloating) {TypedValue res new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogCustomTitleDecorLayout, res, true);layoutResource res.resourceId;} else {layoutResource R.layout.screen_custom_title;}// XXX Remove this once action bar supports these features.removeFeature(FEATURE_ACTION_BAR);} else if ((features (1 FEATURE_NO_TITLE)) 0) {// If no other features and not embedded, only need a title.// If the window is floating, we need a dialog layoutif (mIsFloating) {......} else if ((features (1 FEATURE_ACTION_BAR)) ! 0) {layoutResource a.getResourceId(R.styleable.Window_windowActionBarFullscreenDecorLayout,R.layout.screen_action_bar);} else {layoutResource R.layout.screen_title;}// System.out.println(Title!);} else if ((features (1 FEATURE_ACTION_MODE_OVERLAY)) ! 0) {layoutResource R.layout.screen_simple_overlay_action_mode;} else {// Embedded, so no decoration is needed.layoutResource R.layout.screen_simple;// System.out.println(Simple!);}mDecor.startChanging();// DecorView添加子View. 从父到子依次是:DecorView - //DecorCaptionView(不一定包含) - root(即layoutResource对应的View)mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);// 获取R.id.content对应的ContentViewViewGroup contentParent (ViewGroup)findViewById(ID_ANDROID_CONTENT); ...... // 仅最顶层Window执行if (getContainer() null) {mDecor.setWindowBackground(mBackgroundDrawable);final Drawable frame;if (mFrameResource ! 0) {frame getContext().getDrawable(mFrameResource);} else {frame null;}mDecor.setWindowFrame(frame);mDecor.setElevation(mElevation);mDecor.setClipToOutline(mClipToOutline);if (mTitle ! null) {setTitle(mTitle);}if (mTitleColor 0) {mTitleColor mTextColor;}setTitleColor(mTitleColor);}mDecor.finishChanging();return contentParent; }3.3.2 DecorView frameworks/base/core/java/com/android/internal/policy/DecorView.java 3.3.2.1 onResourcesLoaded void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {if (mBackdropFrameRenderer ! null) {loadBackgroundDrawablesIfNeeded();mBackdropFrameRenderer.onResourcesLoaded(this, mResizingBackgroundDrawable, ......);}// 创建DecorCaptionView(即包含系统按钮如最大化,关闭等的标题)mDecorCaptionView createDecorCaptionView(inflater);final View root inflater.inflate(layoutResource, null);if (mDecorCaptionView ! null) {// 从父到子依次是:DecorView - DecorCaptionView - rootif (mDecorCaptionView.getParent() null) {addView(mDecorCaptionView,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}mDecorCaptionView.addView(root,new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));} else {// 从父到子依次是:DecorView - rootaddView(root, 0,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}mContentRoot (ViewGroup) root;initializeElevation(); }private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {DecorCaptionView decorCaptionView null;for (int i getChildCount() - 1; i 0 decorCaptionView null; i--) {View view getChildAt(i);if (view instanceof DecorCaptionView) { // The decor was most likely saved from a relaunch - so reuse it.decorCaptionView (DecorCaptionView) view;removeViewAt(i);}}final WindowManager.LayoutParams attrs mWindow.getAttributes();final boolean isApplication attrs.type TYPE_BASE_APPLICATION ||attrs.type TYPE_APPLICATION ||attrs.type TYPE_DRAWN_APPLICATION;final WindowConfiguration winConfig getResources().getConfiguration().windowConfiguration;if (!mWindow.isFloating() isApplication winConfig.hasWindowDecorCaption()) {if (decorCaptionView null) {decorCaptionView inflateDecorCaptionView(inflater);}decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);} else {decorCaptionView null;} // Tell the decor if it has a visible caption.enableCaption(decorCaptionView ! null);return decorCaptionView; }总结 PhoneWindow.installDecor 该方法在 Activity#setContentView(layoutResID) 里调用用来在 PhoneWindow 创建 DecorView 及其子 View。 PhoneWindow#installDecor 具体步骤 generateDecor创建 DecorView (是一个 FrameLayout ) generateLayout根据设置的 Window 相关属性设置 PhoneWindow 特性。给 PhoneWindow 的根 DecorView 添加子 View并返回 ContentView 读取配置文件中的 Window 相关的属性 declare-styleable name“Window”根据设置的 Window 各属性值设置 PhoneWindow 的特性(例如requestFeature/setFlags/WindowManager.LayoutParams)以及选择对应的 layout (默认为 screen_simple)DecorView 添加子 View。从父到子依次是DecorView - DecorCaptionView (不一定包含) - root (即上述 layout对应的 View)返回 root (即 R.layout.screen_simple ) 中 R.id.content 对应的 ContentView (即一个 FrameLayout) DecorCaptionView 即包含系统按钮如最大化关闭等的标题此处不做详细介绍。 frameworks/base/core/res/res/layout/screen_simple.xml 3.4 ActivityPhoneWindowDecorView关系图 上图是根据源码总结出来的各个类的关系图。主要包含一下三部分  StatusBar 状态栏 (系统 UI )其根 View 为 StatusBarWindowView通过 WindowManagerImpl.addView 添加到窗口管理器 DecorView (1) 应用程序 View. 通过 WindowManagerImpl.addView 添加到窗口管理器. 一个页面对应一个 Activity一个 Activity 包含一个 PhoneWindowPhoneWindow 的根 View 即为 DecorViewDecorView 为 FrameLayout (2) 根据创建 Activity 时设置的 Window 属性的不同选择不同的 layout 布局并将该 layout 布局添加到 DecorView 中。最简单的为 R.layout.screen_simple (3) 上述 layout 布局 R.layout.screen_simple 为 LinearLayout包含2个元素: id/action_mode_bar_stub 和 android:id/content。即标题栏和内容体。在 Activity#onCreate - setContentView(layoutResID) 调用时会将layoutResID 填充到 android:id/content NavigationBar 通常指的手机底部的虚拟按键。 上面我们已经知道 StatusBar 和 DecorView 都会添加到 WindowManagerImpl通过窗口管理器进行管理。因此开发者可以定制状态栏和应用程序的 UI 样式及他们之间的显示关系。 下面以沉浸式状态栏实现为例 我们实现这样的效果需要遵循几个步骤: (1) 状态栏透明 (2) DecorView 占满整个屏幕 (3) NavigationBar 的控制 实现代码如下 private static void transparentStatusBar(final Activity activity) {Window window activity.getWindow();if (Build.VERSION.SDK_INT Build.VERSION_CODES.LOLLIPOP) {// Android 5.0及以上, 设置DecorView全屏和系统状态栏透明window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);int option View.SYSTEM_UI_FLAG_LAYOUT_STABLE |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;window.getDecorView().setSystemUiVisibility(option);window.setStatusBarColor(Color.TRANSPARENT);} else {// Android 4.4 设置系统状态栏透明(不能实现DecorView全屏)// 由于Android 4.4不存在PhoneWindow#setStatusBarColor这个方法.// 因此设置透明状态栏需要在DecorView添加一个AlphaStatusBarViewaddStatusBarAlpha(activity, 0)window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);} }// 仅仅用于Android 4.4 private static void addStatusBarAlpha(final Activity activity,final int alpha) {ViewGroup parent (ViewGroup) activity.getWindow().getDecorView()View fakeStatusBarView parent.findViewWithTag(TAG_ALPHA);if (fakeStatusBarView ! null) {if (fakeStatusBarView.getVisibility() View.GONE) {fakeStatusBarView.setVisibility(View.VISIBLE);}fakeStatusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));} else {parent.addView(createAlphaStatusBarView(parent.getContext(), alpha));} }// 仅仅用于Android 4.4 private static View createAlphaStatusBarView(final Context context, final int alpha) {View statusBarView new View(context);statusBarView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight()));statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));statusBarView.setTag(TAG_ALPHA);return statusBarView; }系统 UI 的可见性 : 系统 UI (如 StatusBar 和 NavigationBar)可以在 Activity 中通过 DecorView#setSystemUiVisibility 控制。 (1) 设置 DecorView 全屏 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN (2) 隐藏 NavigationBar View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION (3) 其他参考 View.SYSTEM_UI_FLAG_XXX 3.6 理解ViewRootImpl ViewRootImpl 是一个视图层次结构的顶部可以理解为一个 Window 中所有 View 的根 View 的管理者但 ViewRootImpl 不是 View只是实现了 ViewParent 接口实现了 View 和 WindowManager 之间的通信协议实现的具体细节在 WindowManagerGlobal 这个类中。 简单来说 ViewRootImpl 是 View 与 WindowManager 之间联系的桥梁作用总结如下 将 DecorView 传递给 WindowManagerSerive 完成 View 的绘制过程包括 measure、layout、draw 过程 向 DecorView 分发收到的用户发起的 event 事件如按键触屏等事件。 其中ViewRootImpl 中包含了两个需要重点关注的内部类 final class ViewRootHandler extends Handler 用于向 DecorView 分发事件 static class W extends IWindow.Stub W 是 ViewRootImp l的一个嵌入类也是一个 Binder 服务。通过 mWindowSession.addToDisplay 函数传入 WMS用来在 WMS 中通过 Binder 回调。 将Window传递给WMS public void setView(View view, WindowManager.LayoutParams attrs,View panelParentView) {synchronized (this) {if (mView null) {mView view;......// Schedule the first layout -before- adding to the window// manager, to make sure we do the relayout before receiving// any other events from the system.requestLayout();//见下节介绍if ((mWindowAttributes.inputFeatures WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) 0) {mInputChannel new InputChannel();//生成InputChannel}......try {......//调用mWindowSession.addToDisplay通过binder调用到WMS//实现对Window的真正的添加这里的mWindow为 W 对象res mWindowSession.addToDisplay(mWindow, mSeq, ......);setFrame(mTmpFrame);} catch (RemoteException e) {......} finally {......}...... if (mInputChannel ! null) {if (mInputQueueCallback ! null) {mInputQueue new InputQueue();mInputQueueCallback.onInputQueueCreated(mInputQueue);}//用于输入事件的接收mInputEventReceiver new WindowInputEventReceiver(mInputChannel, Looper.myLooper());}......}}}四  Window属性 之前我们分析了 Window、WindowManager 和 WMS 之间的关系WMS 是 Window 的最终管理者Window 好比是员工WMS 是老板为了方便老板管理员工则需要定义一些 “协议”这些“协议”就是 Window 的属性被定义在 WindowManager 的内部类 LayoutParams 中了解 Window 的属性能够更好的理解 WMS 的内部原理。 Window 的属性有很多种与应用开发最密切的有三种它们分别是 Type (Window 的类型)、Flag (Window 的标志) 和 SoftInputMode软键盘相关模式下面分别介绍这三种 Window 的属性 4.1 Window类型 Window 的类型有很多种比如应用程序窗口、系统错误窗口、输入法窗口、PopupWindow、Toast、Dialog 等等。总来来说分为三大类分别是Application Window应用程序窗口、Sub Windwow子窗口、System Window系统窗口每个大类又包含了很多种类型它们都定义在 WindowManager 的静态内部类 LayoutParams 中接下来我们分别对这三大类进行讲解。 常见的 Window 类型如下 完整的 Window 类型及解释, 可以参考源码 WindowManager。 当一个进程向 WMS 申请一个窗口时WMS 会为窗口确定显示次序。为了方便窗口显示次序的管理手机屏幕可以虚拟的用 X、Y、Z 轴来表示其中 Z 轴垂直于屏幕从屏幕内指向屏幕外这样确定窗口显示次序也就是确定窗口在 Z 轴上的次序这个次序称为 Z-Oder。Type 值是 Z-Oder 排序的依据我们知道应用程序窗口的 Type 值范围为 1 到 99子窗口 1000 到 1999 系统窗口 2000 到 2999一般情况下Type 值越大则 Z-Oder 排序越靠前就越靠近用户。当然窗口显示次序的逻辑不会这么简单情况会比较多举个常见的情况当多个窗口的 Type 值都是 TYPE_APPLICATION这时 WMS 会结合各种情况给出最终的 Z-Oder我们接下来分析下这个 Z-Oder 的次序是怎么确定的。 4.1.1 Z-Order的确定 在 Client 端WindowManager.LayoutParams 的 x y type 用来确定 Window 的三维坐标位置。 public static class WindowManager.LayoutParams extendsViewGroup.LayoutParams implements Parcelable {public int x;// x坐标 public int y;// y坐标 public int type;// 类型(WMS根据type确定Z-Order)...... }在 WMS 端WindowState 表示一个窗口实例其中的属性 mBaseLayer 和 mSubLayer 用来确定 Z-Order。 frameworks/base/services/core/java/com/android/server/wm/WindowState.java // 计算主序时乘以10000, 目的是为同类型的多个窗口预留空间和Z-Order调整 static final int TYPE_LAYER_MULTIPLIER 10000; // 计算主序时加1000, 目的是确定相同主序的子窗口相对于父窗口的上下位置 static final int TYPE_LAYER_OFFSET 1000; // 表示主序 final int mBaseLayer; // 表示子序 final int mSubLayer; WindowState(WindowManagerService service, Session s, ......) {......// 若当前窗口类型为子窗口if ((mAttrs.type FIRST_SUB_WINDOW mAttrs.type LAST_SUB_WINDOW)) {// 计算主序, 主序与父窗口一致主序大的窗口位于主序小的窗口上面mBaseLayer mPolicy.getWindowLayerLw(parentWindow) *TYPE_LAYER_MULTIPLIER TYPE_LAYER_OFFSET;// 计算子序mSubLayer mPolicy.getSubWindowLayerFromTypeLw(a.type);......} else { // 若当前窗口类型不是子窗口// 计算主序mBaseLayer mPolicy.getWindowLayerLw(this) *TYPE_LAYER_MULTIPLIER TYPE_LAYER_OFFSET;// 子序为0mSubLayer 0;......}...... }4.1.2 确定主序 frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java default int getWindowLayerLw(WindowState win) {return getWindowLayerFromTypeLw(win.getBaseType(),win.canAddInternalSystemWindow()); }default int getWindowLayerFromTypeLw(int type) {if (isSystemAlertWindowType(type)) {throw new IllegalArgumentException(......);}return getWindowLayerFromTypeLw(type, false); }default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {if (type FIRST_APPLICATION_WINDOW type LAST_APPLICATION_WINDOW) {return APPLICATION_LAYER; // 2}switch (type) {case TYPE_WALLPAPER:// wallpaper is at the bottom, though the // window manager may move it.return 1;case TYPE_PRESENTATION:case TYPE_PRIVATE_PRESENTATION:case TYPE_DOCK_DIVIDER:case TYPE_QS_DIALOG:return APPLICATION_LAYER;case TYPE_PHONE:return 3;case TYPE_SEARCH_BAR:case TYPE_VOICE_INTERACTION_STARTING:return 4;case TYPE_VOICE_INTERACTION:// voice interaction layer is almost// immediately above apps.return 5;case TYPE_INPUT_CONSUMER:return 6;case TYPE_SYSTEM_DIALOG:return 7;case TYPE_TOAST:// toasts and the plugged-in battery thingreturn 8;case TYPE_PRIORITY_PHONE:// SIM errors and unlock. Not sure if this // really should be in a high layer.return 9;case TYPE_SYSTEM_ALERT:// like the ANR / app crashed dialogs// Type is deprecated for non-system apps. // For system apps, this type should be// in a higher layer than TYPE_APPLICATION_OVERLAY.return canAddInternalSystemWindow ? 13 : 10;case TYPE_APPLICATION_OVERLAY:return 12;case TYPE_DREAM:// used for Dreams (screensavers with TYPE_DREAM windows)return 14;case TYPE_INPUT_METHOD:// on-screen keyboards and other such input // method user interfaces go here.return 15;case TYPE_INPUT_METHOD_DIALOG:// on-screen keyboards and other such input// method user interfaces go here.return 16;case TYPE_STATUS_BAR:return 17;case TYPE_STATUS_BAR_PANEL:return 18;case TYPE_STATUS_BAR_SUB_PANEL:return 19;case TYPE_KEYGUARD_DIALOG:return 20;case TYPE_VOLUME_OVERLAY:// the on-screen volume indicator and// controller shown when the user// changes the device volumereturn 21;case TYPE_SYSTEM_OVERLAY:// the on-screen volume indicator and // controller shown when the user// changes the device volumereturn canAddInternalSystemWindow ? 22 : 11;case TYPE_NAVIGATION_BAR:// the navigation bar, if available// shows atop most thingsreturn 23;case TYPE_NAVIGATION_BAR_PANEL:// some panels (e.g. search) need to // show on top of the navigation barreturn 24;case TYPE_SCREENSHOT:// screenshot selection layer shouldnt go // above system error, but it should cover// navigation bars at the very least.return 25;case TYPE_SYSTEM_ERROR:// system-level error dialogsreturn canAddInternalSystemWindow ? 26 : 10;case TYPE_MAGNIFICATION_OVERLAY:// used to highlight the magnified portion of a displayreturn 27;case TYPE_DISPLAY_OVERLAY:// used to simulate secondary display devicesreturn 28;case TYPE_DRAG:// the drag layer: input for drag-and-drop is // associated with this window,// which sits above all other focusable windowsreturn 29;case TYPE_ACCESSIBILITY_OVERLAY:// overlay put by accessibility services to// intercept user interactionreturn 30;case TYPE_SECURE_SYSTEM_OVERLAY:return 31;case TYPE_BOOT_PROGRESS:return 32;case TYPE_POINTER:// the (mouse) pointer layerreturn 33;default:return APPLICATION_LAYER;} }从主序的确定过程可知 从大的分类上来说系统窗口 子窗口 应用窗口整体上 type 和主序存在正相关。但是在单个分类里单个窗口的 type 大小和主序大小不存在正相关或负相关。主序越大窗口 Z-Order 越靠上面。 4.1.3 确定子序 default int getSubWindowLayerFromTypeLw(int type) {switch (type) {case TYPE_APPLICATION_PANEL:case TYPE_APPLICATION_ATTACHED_DIALOG:return APPLICATION_PANEL_SUBLAYER; // 1case TYPE_APPLICATION_MEDIA:return APPLICATION_MEDIA_SUBLAYER; // -2case TYPE_APPLICATION_MEDIA_OVERLAY:return APPLICATION_MEDIA_OVERLAY_SUBLAYER; // -1case TYPE_APPLICATION_SUB_PANEL:return APPLICATION_SUB_PANEL_SUBLAYER; // 2case TYPE_APPLICATION_ABOVE_SUB_PANEL:return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER; // 3}return 0; }窗口子序用来描述子窗口相对于父窗口的位置 子序 0 表示位于父窗口上面子序 0 表示位于父窗口下面子序 0 表示不是子窗口。子序越大子窗口相对于父窗口越靠上面。 从子序的确定过程可知 子窗口的 type 大小和子序大小不存在正相关或负相关。视频相关的子窗口类型 ( TYPE_APPLICATION_MEDIA 和 TYPE_APPLICATION_MEDIA_OVERLAY ) 位于父窗口的下面其他类型子窗口位于父窗口上面 确定了主序和子序之后的过程后面再分析此处不细纠。 4.2 Window标志Flag Window 的标志也就是 Flag用于控制 Window 的显示同样被定义在 WindowManager 的内部类 LayoutParams 中一共有 20 多个这里我们给出几个比较常用。 FLAG_ALLOW_LOCK_WHILE_SCREEN_ON 使用该标志后当窗口可见时即使设备处于打开状态但在锁屏状态下仍允许在屏幕上锁屏。这主要是针对一些情况下需要保持屏幕亮着而又不能操作时很有用比如让用户只观看某些特定内容不可操作此时屏幕保持亮着而不会滑入待机状态。 FLAG_NOT_FOCUSABLE 仅当窗口无须获得输入焦点时才应设置此标志。设置该标志意味着当用户触摸并选择该窗口时该窗口不会接收到任何输入事件。 FLAG_NOT_TOUCHABLE 使用该标志后窗口将不会响应任何触摸事件。 FLAG_NOT_TOUCH_MODAL 指定窗口在处理触摸事件时是否限制在当前窗口内。如果使用这个标志则该窗口外的任何触摸事件都将被传递给下面的窗口。 FLAG_KEEP_SCREEN_ON 该标志确保屏幕保持开启状态直到从当前窗口移除或清除FLAG_KEEP_SCREEN_ON标志。 FLAG_LAYOUT_NO_LIMITS 使用该标志可以使窗口超出屏幕尺寸而不会被截断。这个标志通常用于应用程序需要在特殊情况下覆盖全屏幕的场景。 FLAG_FULLSCREEN 指定窗口在全屏模式下呈现隐藏状态栏和导航栏。比如在游戏和视频播放时使用。 FLAG_SHOW_WHEN_LOCKED 使用该标志后即使设备处于锁屏状态该窗口也能显示在锁屏界面之上。这个标志通常使用于闹钟、电话来电等应用场景。 FLAG_IGNORE_CHEEK_PRESSES 当用户在通话过程中将自己的脸靠近屏幕时该标志告知系统不要响应触摸事件。这个标志通常用于防止带有接近检测芯片的设备因触摸而产生额外的误操作。 FLAG_TURN_SCREEN_ON 此标志允许屏幕在显示窗口时点亮以确保接收到最新信息例如来电提醒等。 设置 Window 的 Flag 有三种方法第一种是通过 Window 的 addFlags 方法 Window mWindow getWindow(); mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);第二种通过 Window 的 setFlags 方法 Window mWindow getWindow(); mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,WindowManager.LayoutParams.FLAG_FULLSCREEN);其实 Window 的 addFlags 方法内部会调用 setFlags 方法因此这两种方法区别不大。 第三种则是给 LayoutParams 设置 Flag并通过 WindowManager 的 addView 方法进行添加如下所示 WindowManager.LayoutParams mWindowLayoutParams new WindowManager.LayoutParams();mWindowLayoutParams.flags WindowManager.LayoutParams.FLAG_FULLSCREEN;WindowManager mWindowManager (WindowManager) getSystemService(Context.WINDOW_SERVICE); TextView mTextView new TextView(this);mWindowManager.addView(mTextView,mWindowLayoutParams);4.3 软键盘相关模式 窗口和窗口的叠加是非常常见的场景但如果其中的窗口是软键盘窗口可能就会出现一些问题比如典型的用户登录界面默认的情况弹出的软键盘窗口可能会盖住输入框下方的按钮这样用户体验会非常糟糕。 为了使得软键盘窗口能够按照期望来显示WindowManager 的静态内部类 LayoutParams 中定义了软键盘相关模式这里给出常用的几个 SoftInputMode    描述SOFT_INPUT_STATE_UNSPECIFIED    没有指定状态,系统会选择一个合适的状态或依赖于主题的设置SOFT_INPUT_STATE_UNCHANGED    不会改变软键盘状态SOFT_INPUT_STATE_HIDDEN    当用户进入该窗口时软键盘默认隐藏SOFT_INPUT_STATE_ALWAYS_HIDDEN    当窗口获取焦点时软键盘总是被隐藏SOFT_INPUT_ADJUST_RESIZE    当软键盘弹出时窗口会调整大小SOFT_INPUT_ADJUST_PAN    当软键盘弹出时窗口不需要调整大小要确保输入焦点是可见的 从上面给出的 SoftInputMode可以发现它们与 AndroidManifest 中 Activity 的属性 android:windowSoftInputMode 是对应的。因此除了在 AndroidMainfest 中为 Activity 设置 android:windowSoftInputMode 以外还可以在 Java 代码中为 Window 设置 SoftInputMode getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);4.4 常见Window App 开发中常见的涉及 Window 的地方Activity / Dialog / PopupWindow / Toast / 输入法。 通过查看相关源码得出如下结论 Activity创建 PhoneWindow类型为 TYPE_BASE_APPLICATION Dialog创建 PhoneWindow未指定类型 PopupWindow未创建 Window类型为 TYPE_APPLICATION_PANEL Toast类型为 TYPE_TOAST 输入法(IMM)类型为 TYPE_INPUT_METHOD 4.5 WindowInset 4.5.1 什么是WindowInsets WindowInsets源码解释为Window Content的一系列插值集合可以理解为可以将其理解为不同的窗口装饰区域类型比如一个Activity相对于手机屏幕需要空出的地方以腾给StatusBar、Ime、NavigationBar等系统窗口具体表现为该区域需要的上下左右的宽高。 WindowInsets包括三类SystemWindowInsets、StableInsets、WIndowDecorInsets SystemWindowInsets全窗口下被navigationbar、statusbar、ime或其他系统窗口覆盖的区域StableInsets全窗口下被系统UI覆盖的区域WIndowDecorInsets系统预留属性 4.5.2 监听inset 变化 设置Insetscontroller变化监听 InsetsController.addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener ...);应用WindowInsets变化 getWindow().getDecorView().setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener ...);Overridepublic WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {mImeVisible insets.isVisible(ime());return v.onApplyWindowInsets(insets);} 开发者可以通过在自定义 View 中重写 onApplyWindowInsets() 方法或调用 setOnApplyWindowInsetsListener() 来监听 WindowInsets 的变化通过对 View 添加 margin 或 padding 的方式处理解决冲突。 这两个方法是互斥的当存在 OnApplyWindowInsetsListener 时不会执行 onApplyWindowInsets 不过开发者可以在也可 OnApplyWindowInsetsListener 手动调用 onApplyWindowInsets 使两个方法同时被执行。
http://www.pierceye.com/news/108328/

相关文章:

  • 网站图片动态换名网站充值支付宝收款怎么做
  • 蜘蛛网是个什么网站做特卖的购物网站
  • 从零学做网站古典 网站模板
  • h5网站模板开发网站后台哪些功能需要前端配合
  • 网站建设 宜宾佛山企业网站自助建站
  • 苏宁易购网站建设 的定位手机网站制作招聘
  • 个人网站备案申请360老是提示危险网站
  • 建网站哪个好 优帮云自己怎么注册域名
  • 做3ds磁铁卡网站大连旅顺博物馆
  • 邢台市住房和城乡建设局网站大连网站推广机构
  • 网站建设开标书房地产网页设计
  • 中国建设建设工程造价管理协会网站建设视频网站要求吗
  • 商务网站教程深圳定制纸箱
  • 湖南手机版建站系统哪家好自己做网站地图
  • 天津网站制作报价阿里云需要网站建设方案书
  • 做最好的美食分享网站网站建设客户需求分析
  • 如何重建网站广州市服务好的网站制作排名
  • 做一名优秀网站设计师计划网站描述怎样写
  • 网页二级网站怎么做网监关闭的网站怎么恢复
  • 甘肃省建设监理协会 官方网站国内知名公关公司
  • 如何将网站和域名绑定阿里云1M做网站
  • 南城网站建设公司咨询东莞智通人才网最新招聘
  • app建设网站公司哪家好php网站修改代码
  • 哪些网上订餐的网站做的好地情网站建设
  • 重庆推广网站的方法国内最近的新闻大事
  • 网站需要备案吗网站怎么推广软文
  • 做设计开哪个素材网站的会员好手机免费网站建设哪家公司好
  • 征婚网站认识的男人做定投保做高级电工题的网站
  • 学做饼干的网站汕头建设学校的网站
  • asp.net做网站原理工资卡app下载