@Override publicvoidsetContentView(int layoutResID){ // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } elseif (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { // 将View添加到DecorView的mContentParent中 // 调用LayoutInflater的inflate方法解析布局文件,并生成View树,mContentParent为View树的根节点 mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); //回调Activity的onContentChanged方法通知视图发生改变 final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } mContentParentExplicitlySet = true; }
protected DecorView generateDecor(int featureId){ // System process doesn't have application context and in that case we need to directly use // the context we have. Otherwise we want the application context, so we don't cling to the // activity. 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(); } returnnew DecorView(context, featureId, this, getAttributes()); } protected ViewGroup generateLayout(DecorView decor){ ....
publicvoidhandleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason){ // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration //调用了performResumeActivity方法执行生命周期中的onResume过程 //通过token返回之前创建的ActivityClientRecord对象 final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); ··· final Activity a = r.activity; ··· boolean willBeVisible = !a.mStartedActivity; if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { //获取activity的window对象 r.window = r.activity.getWindow(); //获取decorView View decor = r.window.getDecorView(); //decorView设置为不可见状态 decor.setVisibility(View.INVISIBLE); //获取WindowManager对象 ViewManager wm = a.getWindowManager(); 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; // Normally the ViewRoot sets up callbacks with the Activity // in addView->ViewRootImpl#setView. If we are instead reusing // the decor view we have to notify the view root that the // callbacks may have changed. ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //WindowManager的adView方法添加decorView wm.addView(decor, l); } else { // The activity will get a callback for this {@link LayoutParams} change // earlier. However, at that time the decor will not be set (this is set // in this method), so no action will be taken. This call ensures the // callback occurs with the decor set. //如果decorview被设置过了的话,那么Window状态改变就调用回调方法 a.onWindowAttributesChanged(l); } }
// If the window has already been added, but during resume // we started another activity, then don't yet make the // window visible. } elseif (!willBeVisible) { if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } ··· WindowManager.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); } }
publicvoidaddView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow){ //检查参数是否合法 if (view == null) { thrownew IllegalArgumentException("view must not be null"); } if (display == null) { thrownew IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { thrownew IllegalArgumentException("Params must be WindowManager.LayoutParams"); } //如果是子Window还需要调整参数 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { // If there's no parent, then hardware acceleration for this view is // set from the application's hardware acceleration setting. final Context context = view.getContext(); if (context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } }
ViewRootImpl root; View panelParentView = null;
··· root = new ViewRootImpl(view.getContext(), display);
// do this last because it fires off messages to start doing things //调用ViewRootImpl来更新界面 try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
看到注释1处,首先需要介绍几个WindowManagerGlobal中比较重要的成员变量:
privatefinal ArrayList<View> mViews = new ArrayList<View>(); privatefinal ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); privatefinal ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); privatefinal ArraySet<View> mDyingViews = new ArraySet<View>();
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java publicintaddWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel){ int[] appOp = newint[1]; int res = mPolicy.checkAddPermission(attrs, appOp); if (res != WindowManagerGlobal.ADD_OKAY) { return res; }
boolean reportNewConfig = false; WindowState parentWindow = null; long origId; finalint callingUid = Binder.getCallingUid(); finalint type = attrs.type;
synchronized(mWindowMap) { if (!mDisplayReady) { thrownew IllegalStateException("Display has not been initialialized"); } // 获取DisplayContent final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
....
AppWindowToken atoken = null; finalboolean hasParent = parentWindow != null; // 调用displayContent的getWindowToken函数创建WindowToken // WindowToken保存在displayContent的mTokenMap哈希表中 // Use existing parent window token for child windows since they go in the same token // as there parent window so we can apply the same policy on them. WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); // If this is a child window, we want to apply the same type checking rules as the // parent window type. finalint rootType = hasParent ? parentWindow.mAttrs.type : type;