Android Builder设计模式之 AlertDialog 源码分析

原文链接:https://blog.csdn.net/qq_34211365/article/details/103833153

主代码 

public class MainActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("Test")
       .setMessage("hello world")
       .setIcon(R.drawable.ic_launcher_background)
       .setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        })
        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                builder.show();
            }
        });

    }
}

AlertDialog 源码分析 

  public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }

public class AlertDialog extends Dialog implements DialogInterface {
		......
		public static class Builder {
        @UnsupportedAppUsage
        private final AlertController.AlertParams P;

        public Builder(Context context) {
            this(context, resolveDialogTheme(context, Resources.ID_NULL));
        }

        public Builder(Context context, int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));
        }

        public Context getContext() {
            return P.mContext;
        }

        public Builder setTitle(@StringRes int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }


        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }
        public Builder setCustomTitle(View customTitleView) {
            P.mCustomTitleView = customTitleView;
            return this;
        }

        public Builder setMessage(@StringRes int messageId) {
            P.mMessage = P.mContext.getText(messageId);
            return this;
        }
        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

        public Builder setIcon(@DrawableRes int iconId) {
            P.mIconId = iconId;
            return this;
        }


        public Builder setIcon(Drawable icon) {
            P.mIcon = icon;
            return this;
        }

        public Builder setIconAttribute(@AttrRes int attrId) {
            TypedValue out = new TypedValue();
            P.mContext.getTheme().resolveAttribute(attrId, out, true);
            P.mIconId = out.resourceId;
            return this;
        }

        public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
            P.mPositiveButtonText = P.mContext.getText(textId);
            P.mPositiveButtonListener = listener;
            return this;
        }

        public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
            P.mPositiveButtonText = text;
            P.mPositiveButtonListener = listener;
            return this;
        }

        public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
            P.mNegativeButtonText = P.mContext.getText(textId);
            P.mNegativeButtonListener = listener;
            return this;
        }


        public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
            P.mNegativeButtonText = text;
            P.mNegativeButtonListener = listener;
            return this;
        }
        public Builder setNeutralButton(@StringRes int textId, final OnClickListener listener) {
            P.mNeutralButtonText = P.mContext.getText(textId);
            P.mNeutralButtonListener = listener;
            return this;
        }
        public Builder setNeutralButton(CharSequence text, final OnClickListener listener) {
            P.mNeutralButtonText = text;
            P.mNeutralButtonListener = listener;
            return this;
        }
        public Builder setCancelable(boolean cancelable) {
            P.mCancelable = cancelable;
            return this;
        }
        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
            P.mOnCancelListener = onCancelListener;
            return this;
        }

        public Builder setOnDismissListener(OnDismissListener onDismissListener) {
            P.mOnDismissListener = onDismissListener;
            return this;
        }
        public Builder setOnKeyListener(OnKeyListener onKeyListener) {
            P.mOnKeyListener = onKeyListener;
            return this;
        }

        public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) {
            P.mItems = P.mContext.getResources().getTextArray(itemsId);
            P.mOnClickListener = listener;
            return this;
        }
		......
}

AlertDialog 源码之create

	public AlertDialog create() {
            final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
            P.apply(dialog.mAlert);【1】
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

AlertDialog构造方法

  AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
       //调用父类Dialog的构造方法
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
                createContextThemeWrapper);
        mWindow.alwaysReadCloseOnTouchAttr();
        //创建AlertController
        mAlert = AlertController.create(getContext(), this, getWindow());
    }

父类Dialog的构造方法

  Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
  		//这里传进来的是false
        if (createContextThemeWrapper) {
            if (themeResId == Resources.ID_NULL) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            //注意,这里的context传的是Activity
            mContext = context;
        }
		【从Activity里获取WindowManagr,获取到的是和Activity同一个WindowManager】
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		//创建PhoneWindow
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        //给窗口设置回调,Dialog会实现Window中的回调方法,
        //window接受到事件之后就可以传递给Dialog处理
        【这点和Activity添加到Window的流程一样,接受activity 分发按键事件,也就是activity与phonewindow联系起来的节点,activity实现了虚拟类window的方法。】
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
        //注意下这个方法,设置WindowManager,后面两个参数为空
        //token为空
        w.setWindowManager(mWindowManager, null, null);
        //调整位置,处于中间
        w.setGravity(Gravity.CENTER);
        //Handler类,处理事件的
        mListenersHandler = new ListenersHandler(this);
    }

Activity.getSystemService

@Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        
        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;//窗口令牌
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //通过Activity的WindowManager创建了WindowManagerImpl
        //mWindowManager是Dialog的WindowManagerImpl和Activity的
        //WindowManagerImpl不是同一个
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
  public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

P.apply方法

public void apply(AlertController dialog) {
            if (mCustomTitleView != null) {
                dialog.setCustomTitle(mCustomTitleView);
            } else {
                if (mTitle != null) {
                    dialog.setTitle(mTitle);
                }
                if (mIcon != null) {
                    dialog.setIcon(mIcon);
                }
                if (mIconId != 0) {
                    dialog.setIcon(mIconId);
                }
                if (mIconAttrId != 0) {
                    dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
                }
            }
            if (mMessage != null) {
                dialog.setMessage(mMessage);
            }
            if (mPositiveButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                        mPositiveButtonListener, null);
            }
            if (mNegativeButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                        mNegativeButtonListener, null);
            }
            if (mNeutralButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
                        mNeutralButtonListener, null);
            }

Dialog的show方法

   public void show() {
   		//mShowing默认值为false
        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;
        //mCreated默认值为false,保证onCreate只调用一次
        if (!mCreated) {
            //这里面就是调用Dialog的onCreate方法
            dispatchOnCreate(null);
        } else {
            final Configuration config = mContext.getResources().getConfiguration();
            mWindow.getDecorView().dispatchConfigurationChanged(config);
        }
        //调用onStart
        onStart();
        //获取DecorView,DecorView就是窗口的顶层布局
        mDecor = mWindow.getDecorView();
       //有ActionBar的情况
        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        WindowManager.LayoutParams l = mWindow.getAttributes();
			......
        mWindowManager.addView(mDecor, l);
      		......
        mShowing = true;

        sendShowMessage();
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }
AlertController.installContent

    public void installContent(AlertParams params) {
    	//给Dailog的布局文件设置数据
        params.apply(this);
        installContent();
    }
    public void installContent() {
        int contentView = selectContentView();
        mWindow.setContentView(contentView);
        setupView();
    }

SelectContentView 加载布局

mAlertDialogLayout,mAlertDialogLayout再AlertController构造方法中赋值为默认值R.layout.alert_dialog,这就是默认Dialog的布局文件,后面会调用setContentView添加到DecorView中。

private int selectContentView() {
        if (mButtonPanelSideLayout == 0) {
            return mAlertDialogLayout;
        }
        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
            return mButtonPanelSideLayout;
        }
        // TODO: use layout hint side for long messages/lists
        return mAlertDialogLayout;
    }

mWindow.setContentView()

@Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
        	//创建DecorView
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            ......
        }
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            ......
        } else {
        	//加载Dialog的默认布局到mContentParent中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
        	//Dialog中的onContentChanged实现为空
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

setupView 填充布局参数

一系列的findViewId获取了布局文件的控件之后调用setXXX设置数据。

private void setupView() {
        final View parentPanel = mWindow.findViewById(R.id.parentPanel);
        final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
        final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
        final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);

        // Install custom content before setting up the title or buttons so
        // that we can handle panel overrides.
        final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
        setupCustomContent(customPanel);

        final View customTopPanel = customPanel.findViewById(R.id.topPanel);
        final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
        final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);

        // Resolve the correct panels and remove the defaults, if needed.
        final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
        final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
        final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);

        setupContent(contentPanel);
        setupButtons(buttonPanel);
        setupTitle(topPanel);
        ......
     .....
  }

mWindowManager.addView

接着调用addView将Dialog窗口显示出来,前面说了Dialog用的是Activity的WindowManager,所以这里调用的是Activity的WindowManager的addView方法。

 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

Dialog和Activity共用同一个WindowManager,此WindowManager在Activity的attach方法中创建。Dialog的token就是当前Activity的mAppToken。

Android窗口分为三种类型,应用窗口,子窗口,系统窗口


每种类型窗口必须对应有一个身份标识Token,Token一般是一个binder对象,type是窗口的类型,FIRST_SUB_WINDOW代表第一个子窗口,LAST_SUB_WINDOW代表最后一个子窗口,FIRST_SYSTEM_WINDOW代表第一个系统窗口,LAST_SYSTEM_WINDOW代表最后一个系统窗口。

子窗口分支:子窗口通过的token通过getWindowToken赋值

void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
        ......
        //子窗口
        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            if (wp.token == null) {
                View decor = peekDecorView();
                if (decor != null) {
                    wp.token = decor.getWindowToken();【子窗口】
                }
            }
            ......
            //系统窗口
        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
            // We don't set the app token to this system window because the life cycles should be
            // independent. If an app creates a system window and then the app goes to the stopped
            // state, the system window should not be affected (can still show and receive input
            // events)
            ......
        } else {
           //应用窗口
            if (wp.token == null) {
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
            }
            ....
        }
    }
/frameworks/base/core/java/android/view/View.java

public IBinder getWindowToken() {
        return mAttachInfo != null ? mAttachInfo.mWindowToken : null;
    }

AttachInfo构造函数
public AttachInfo(IWindowSession session, IWindow window, Display display,
                ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
                Context context) {
            ......
            mWindow = window;
            mWindowToken = window.asBinder();
            ......
        }
    }


mAttachInfo.mWindowToken是在ViewRootImpl的构造方法中赋值的
/frameworks/base/core/java/android/view/ViewRootImpl.java

public ViewRootImpl(Context context, Display display) {
     ......
     mWindow = new W(this);
     mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
     ......
}

子窗口的token就是父窗口的W对象,并且从开始addView方法中看到,ViewRootImpl的创建是在给窗口设置token之后,所以如果一开始创建的窗口就是一个子窗口是不行的,没有token。

系统窗口分支:

部分系统窗口的token不会在这里设置,也不需要开发者干预,系统会自动创建,注释直译:
系统窗口生命周期应该是独立的,因此我们没有将应用令牌设置给系统窗口。 如果某个应用创建了系统窗口,然后该应用进入停止状态,则该系统窗口不应受到影响(仍可以显示和接收输入事件)

mContainer是Window类型的,mAppToken和mContainer.mAppToken都一样都是Window中的mAppToken

setWindowManager

  public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

setWindowManager方法是由Activity创建时调用自身attach方法中调用的

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	......
	activity.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);
	......
}
 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
	......
	mToken = token;
	mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
	......

}

总结:子窗口用的父窗口的W对象,应用窗口由应用内部创建的token对象,部分系统窗口由系统自动创建专属token

有几种Context 他们有什么区别


看到Dialog自己是没有token的,所以Dialog的token哪来的呢?这里的mContainer为空,所以Dialog的token就是当前Activity的mAppToken。Application或者service类型的context是无法创建Dialog的,原因是这两种context没有token。

DecorView addWindow 添加到Window与activity建立联系

WindowManagerService.addWindow
mWindowSession在ViewRootImpl构造方法中创建,用来和WMS通信,同时ViewRootImpl构造方法中还创建了一个W对象,这也是个Binder对象,通过addToDisplay传递给WMS,供WMS和应用端通信,类似与AMS和ActivityThread之间,双向通信

root.setView
 

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ......
            //绘制流程,measure,layout,draw
            requestLayout();
        ......
            //将Window添加到WMS
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
 
}
 
 
 @Override
    public 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);
    }

addWindow checkAddPermission

  public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);【窗口权限检查】
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }
                ......
        ......
    }

@Override
    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
        //获取窗口的类型
        int type = attrs.type;
        outAppOp[0] = AppOpsManager.OP_NONE;
        //如果不是应用窗口,子窗口,系统窗口的一种
        //直接返回无效的类型,Andoird只有三种窗口类型
        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
            return WindowManagerGlobal.ADD_INVALID_TYPE;
        }
       //如果不是系统窗口则返回OK,不需要检查权限
        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
            // Window manager will make sure these are okay.
            return ADD_OKAY;
        }
         //如果不是SystemAlert类型的窗口,下面这几种属于Alert窗口
         /*
         TYPE_PHONE
         TYPE_PRIORITY_PHONE
         TYPE_SYSTEM_ALERT
         TYPE_SYSTEM_ERROR
         TYPE_SYSTEM_OVERLAY
         TYPE_APPLICATION_OVERLAY
        */
        if (!isSystemAlertWindowType(type)) {
            //这几种系统窗口也不需要检查权限
            switch (type) {
                case TYPE_TOAST:
                    // Only apps that target older than O SDK can add window without a token, after
                    // that we require a token so apps cannot add toasts directly as the token is
                    // added by the notification system.
                    // Window manager does the checking for this.
                    outAppOp[0] = OP_TOAST_WINDOW;
                    return ADD_OKAY;
                case TYPE_DREAM:
                case TYPE_INPUT_METHOD:
                case TYPE_WALLPAPER:
                case TYPE_PRESENTATION:
                case TYPE_PRIVATE_PRESENTATION:
                case TYPE_VOICE_INTERACTION:
                case TYPE_ACCESSIBILITY_OVERLAY:
                case TYPE_QS_DIALOG:
                    return ADD_OKAY;
            }
            //非上面几种类型的窗口需要检查是否具有
            //android.Manifest.permission.INTERNAL_SYSTEM_WINDOW的权限
            //该权限只有系统应用才能获取
            return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                    == PERMISSION_GRANTED ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }
 
        // 走到这里说明添加的窗口是SystemAlert的
        outAppOp[0] = OP_SYSTEM_ALERT_WINDOW;
 
        final int callingUid = Binder.getCallingUid();
        // 如果是系统应用进程则返回OK,自动授予权限
        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
            return ADD_OKAY;
        }
 
        ApplicationInfo appInfo;
        try {
            //获取当前窗口的应用信息
            appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
                            attrs.packageName,
                            0 /* flags */,
                            UserHandle.getUserId(callingUid));
        } catch (PackageManager.NameNotFoundException e) {
            appInfo = null;
        }
        //如果当前窗口不需要应用或者Android O版本以上并且不是TYPE_APPLICATION_OVERLAY 
        //则也需要检查android.Manifest.permission.INTERNAL_SYSTEM_WINDOW权限
        if (appInfo == null || (type != TYPE_APPLICATION_OVERLAY && appInfo.targetSdkVersion >= O)) {
            return (mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                    == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }
 
        //添加的SystemAlert窗口是否被应用允许
        final int mode = mAppOpsManager.checkOpNoThrow(outAppOp[0], callingUid, attrs.packageName);
        switch (mode) {
            case AppOpsManager.MODE_ALLOWED:
            case AppOpsManager.MODE_IGNORED:
                //代表允许
                return ADD_OKAY;
            case AppOpsManager.MODE_ERRORED:
                // 小于Android M的版本则允许否则拒绝
                if (appInfo.targetSdkVersion < M) {
                    return ADD_OKAY;
                }
                return ADD_PERMISSION_DENIED;
            default:
            //检查是否具有android.Manifest.permission.SYSTEM_ALERT_WINDOW权限
                return (mContext.checkCallingOrSelfPermission(SYSTEM_ALERT_WINDOW)
                        == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }
    }

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }
 
        boolean reportNewConfig = false;
        WindowState parentWindow = null;
        long origId;
        final int callingUid = Binder.getCallingUid();
        //窗口类型
        final int type = attrs.type;
        synchronized(mWindowMap) {
            //Display没准备好
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }
 
            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
            //Display不存在
            if (displayContent == null) {
                Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                        + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            //Display不能访问
            if (!displayContent.hasAccess(session.mUid)
                    && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
                Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
                        + "does not have access: " + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            //添加的窗口已经存在
            if (mWindowMap.containsKey(client.asBinder())) {
                Slog.w(TAG_WM, "Window " + client + " is already added");
                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
            }
            //如果是子窗口
            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                //找到其父窗口
                parentWindow = windowForClientLocked(null, attrs.token, false);            
                //如果父窗口为空则添加失败
                if (parentWindow == null) {
                    Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                //如果父窗口也是子窗口则添加失败
                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                    Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
            }
            //如果是虚拟Private显示器窗口并且Display不是Private的则添加失败
            if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
                Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display.  Aborting.");
                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
            }
 
            AppWindowToken atoken = null;
            //是否有父窗口,我们添加的Dialog不是子窗口没有父窗口
            final boolean hasParent = parentWindow != null;
             //获取token,如果有父窗口则使用父窗口的token
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            //如果有父窗口则使用父窗口的类型
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;
            
            boolean addToastWindowRequiresToken = false;
            if (token == null) {
                //如果token为空并且是应用类型窗口则添加失败
                if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是输入法类型窗口则添加失败
                if (rootType == TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是语音交互类型窗口则添加失败
                if (rootType == TYPE_VOICE_INTERACTION) {
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是壁纸类型窗口则添加失败
                if (rootType == TYPE_WALLPAPER) {
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是屏保类型窗口则添加失败
                if (rootType == TYPE_DREAM) {
                    Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是TYPE_QS_DIALOG类型窗口则添加失败
                if (rootType == TYPE_QS_DIALOG) {
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                 //如果token为空并且是辅助功能覆盖类型窗口则添加失败
                if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果token为空并且是TOAST类型窗口
                if (type == TYPE_TOAST) {
                       //如果版本大于N MR1,则不能随意添加TOAST了
                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
                            parentWindow)) {
                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                }
                //如果token为空则等于窗口的W对象
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                //根据token或者W创建WindowToken
                token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow);
                        //token不为空并且是应用类型窗口
            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                //获取应用的AppWindowToken,AppWindowToken是
                //WindowToken的子类标识一个Activity窗口
                atoken = token.asAppWindowToken();
                //如果AppWindowToken为空则添加失败
                if (atoken == null) {
                    Slog.w(TAG_WM, "Attempted to add window with non-application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                } else if (atoken.removed) {
                    Slog.w(TAG_WM, "Attempted to add window with exiting application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                }
                //如果是输入法类型窗口
            } else if (rootType == TYPE_INPUT_METHOD) {
                //但是token类型不是输入法则添加失败
                if (token.windowType != TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是语音交互类型窗口
            } else if (rootType == TYPE_VOICE_INTERACTION) {
                //但是token类型不是语音交互类型则添加失败
                if (token.windowType != TYPE_VOICE_INTERACTION) {
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是壁纸类型窗口
            } else if (rootType == TYPE_WALLPAPER) {
                //但是token类型不是壁纸则添加失败
                if (token.windowType != TYPE_WALLPAPER) {
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是屏保类型窗口
            } else if (rootType == TYPE_DREAM) {
                //但是token类型不是屏保则添加失败
                if (token.windowType != TYPE_DREAM) {
                    Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是辅助功能覆盖类型窗口
            } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                //但是token类型不是辅助功能覆盖类型则添加失败
                if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是TOAST类型窗口
            } else if (type == TYPE_TOAST) {
                //如果是Android N MR1版本以上则不能随意添加,
                //需要检查token
                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
                        callingUid, parentWindow);
                        //并且token不为TOAST类型则添加失败
                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是Qs Dialog类型窗口
            } else if (type == TYPE_QS_DIALOG) {
                //但是token类型不是Qs Dialog则添加失败
                if (token.windowType != TYPE_QS_DIALOG) {
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果AppWindowToken不为空
            } else if (token.asAppWindowToken() != null) {
                Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
                //系统类型窗口但是AppWindowToken不为空
                //将token置为空
                attrs.token = null;
                //重新创建一个新的token
                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
                        session.mCanAddInternalSystemWindow);
            }
            //创建WindowState对象,每一个成功添加的窗口都会
            //在WMS对应一个WindowState,WindowState封装了窗口的信息
            //WindowState里面有个很重要的步骤是调整窗口的Z轴排列顺序
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }
 
            if (win.getDisplayContent() == null) {
                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            //会根据一些特殊窗口设置Flag,如截屏窗口设置不能获取事件,
            //状态栏窗口在锁屏被隐藏时需要移除壁纸和键盘保护程序等
            mPolicy.adjustWindowParamsLw(win.mAttrs);
            //设置是否可以显示在当前uid之外的屏幕
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
            //检查特殊窗口如StatusBar,NavigationBar的
            //android.Manifest.permission.STATUS_BAR_SERVICE权限
            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                //创建InputChannel,InputChannel用来给WMS和InputDispatcher通信
                //InputChannel创建同时创建了一对socket,InputDispatch监听
                //一个socket一端来获取事件处理结果,应用程序监听一个socket一端
                //来接收InputDispatch发送的事件
                win.openInputChannel(outInputChannel);
            }
 
           //对TOAST继续进行检查
            if (type == TYPE_TOAST) {
                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
                if (addToastWindowRequiresToken
                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
                        || mCurrentFocus == null
                        || mCurrentFocus.mOwnerUid != callingUid) {
                    mH.sendMessageDelayed(
                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
                            win.mAttrs.hideTimeoutMilliseconds);
                }
            }
            //到这里说明窗口是合法的可以添加
            res = WindowManagerGlobal.ADD_OKAY;
            if (mCurrentFocus == null) {
                mWinAddedSinceNullFocus.add(win);
            }
 
            if (excludeWindowTypeFromTapOutTask(type)) {
                displayContent.mTapExcludedWindows.add(win);
            }
 
            origId = Binder.clearCallingIdentity();
            //此方法里会创建SurfaceComposerClient建立应用层
            //和SurfaceFlinger的连接
            win.attach();
            //将窗口存入mWindowMap
            mWindowMap.put(client.asBinder(), win);
            if (win.mAppOp != AppOpsManager.OP_NONE) {
                int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
                        win.getOwningPackage());
                if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
                        (startOpResult != AppOpsManager.MODE_DEFAULT)) {
                    win.setAppOpVisibilityLw(false);
                }
            }
 
            final AppWindowToken aToken = token.asAppWindowToken();
            //如果窗口类型是启动窗口
            if (type == TYPE_APPLICATION_STARTING && aToken != null) {
                //将窗口赋值给token的startwindow
                aToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
                        + " startingWindow=" + win);
            }
 
            boolean imMayMove = true;
            //将窗口添加到WindowContainer的WindowList中
            win.mToken.addWindow(win);
            //后面还会处理一些特殊窗口
            ......
        return res;
    }

WindowState规则 Z轴排列顺序 new WindowState

Android窗口的Z轴计算规则以及根据Z轴对WindowState的排列规则,Z轴越大越靠前。

public int addWindow(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,
            InsetsState outInsetsState) {
			......
				//每个窗口在WMS都会对应一个WindowState,描述了窗口相关信息
				final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
			......
				//将窗口添加到WindowContainer的WindowList中,并进行排序
				//这里的WindowContainer有两种类型:AppWindowToken和WindowToken
				win.mToken.addWindow(win);
			......
}

mBaseLayer描述窗口的Z轴数

WindowState中用mBaseLayer描述窗口的Z轴数,这个值只会和窗口的类型有关,mSubLayer描述子窗口的Z轴数。

public WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
        super(service);
        //省略赋值代码
        ......
        //如果是子窗口
        if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
            //计算窗口mBaseLayer,传入的是父窗口
            mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
           //计算窗口mSubLayer,传入的是当前窗口的类型
            mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
            mIsChildWindow = true;
            //根据自定义的比较器sWindowSubLayerComparator对子窗口排序
            parentWindow.addChild(this, sWindowSubLayerComparator);
			....
        } else {
            //计算窗口mBaseLayer
            mBaseLayer = mPolicy.getWindowLayerLw(this)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            //非子窗口mSubLayer为0
            mSubLayer = 0;
            mIsChildWindow = false;
			.....
        }
		//如果是应用窗口并且mShowForAllUsers为true
        if (mAppToken != null && mAppToken.mShowForAllUsers) {
            //添加FLAG_SHOW_WHEN_LOCKED,代表可以显示在锁屏上
            mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
        }

        mWinAnimator = new WindowStateAnimator(this);
        mWinAnimator.mAlpha = a.alpha;

        mRequestedWidth = 0;
        mRequestedHeight = 0;
        mLastRequestedWidth = 0;
        mLastRequestedHeight = 0;
        mLayer = 0;
    }
子窗口的分支  添加到WindowList
计算mBaseLayer

WindowManagerPolicy 计算mBaseLayer,有三十多种类型,根据不同类型返回不同的值,例如壁纸为1,Toast为8,屏保为14等等,很好理解,mBaseLayer的计算还是很简单的。

default int getWindowLayerLw(WindowState win) {
        return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
    }
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:
                return  1;
            case TYPE_PRESENTATION:
            case TYPE_PRIVATE_PRESENTATION:
                return  APPLICATION_LAYER;
            case TYPE_DOCK_DIVIDER:
                return  APPLICATION_LAYER;
            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:
                return  5;
            case TYPE_INPUT_CONSUMER:
                return  6;
            case TYPE_SYSTEM_DIALOG:
                return  7;
            case TYPE_TOAST:
                return  8;
            case TYPE_PRIORITY_PHONE:
                return  9;
            case TYPE_SYSTEM_ALERT:
                return  canAddInternalSystemWindow ? 13 : 10;
            case TYPE_APPLICATION_OVERLAY:
                return  12;
            case TYPE_DREAM:
                return  14;
    			......
            default:
                Slog.e("WindowManager", "Unknown window type: " + type);
                return APPLICATION_LAYER;  //2
        }
    }

最后计算出来的mBaseLayer还会乘上一个乘数因子
TYPE_LAYER_MULTIPLIER等于10000,TYPE_LAYER_OFFSET等于1000,例如普通的应用Activity计算下来 mBaseLayer = 2 * 10000 + 1000.

mSubLayer的计算

接着看mSubLayer的计算,同样是根据不同子窗口的类型返回不同的值,比如APPLICATION_PANEL_SUBLAYER等于FIRST_SUB_WINDOW + 3,FIRST_SUB_WINDOW等于1000

mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);

default int getSubWindowLayerFromTypeLw(int type) {
        switch (type) {
            case TYPE_APPLICATION_PANEL:
            case TYPE_APPLICATION_ATTACHED_DIALOG:
                return APPLICATION_PANEL_SUBLAYER; //1003
            case TYPE_APPLICATION_MEDIA:
                return APPLICATION_MEDIA_SUBLAYER; //-2
            case TYPE_APPLICATION_MEDIA_OVERLAY:
                return APPLICATION_MEDIA_OVERLAY_SUBLAYER; //-1
            case TYPE_APPLICATION_SUB_PANEL:
                return APPLICATION_SUB_PANEL_SUBLAYER; //2
            case TYPE_APPLICATION_ABOVE_SUB_PANEL:
                return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER; //3
        }
        Slog.e("WindowManager", "Unknown sub-window type: " + type);
        return 0;
    }
自定义排序规则

接着看子窗口的添加规则
parentWindow.addChild(this, sWindowSubLayerComparator),通过自定义的比较器对子窗口进行排序,哪两个窗口排序?当前添加的窗口会和WindowList中的所有窗口比较,这里的所有窗口指的是同一父窗口下的所有窗口。

private static final Comparator<WindowState> sWindowSubLayerComparator =
            new Comparator<WindowState>() {
                @Override
                public int compare(WindowState w1, WindowState w2) {
                    final int layer1 = w1.mSubLayer;
                    final int layer2 = w2.mSubLayer;
         
                    if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
                      /*
					  对两个窗口的计算出来的mSubLayer进行比较
                      w1代表当前添加的窗口,w2代表已存在的窗口
                      当前窗口的mSubLayer小于已存在的窗口的mSubLayer或者
                      两者相等且都小于0则返回-1
					  */
                        return -1;
                    }
                    return 1;
                };
            };


 

WindowContainer.addChild 

WindowState并没有覆盖父类的addChild方法,mChildren是WindowList类型容器,继承自ArrayList

protected void addChild(E child, Comparator<E> comparator) {
        //如果getParent()不为空代表已经添加过了
        if (child.getParent() != null) {
            throw new IllegalArgumentException("addChild: container=" + child.getName()
                    + " is already a child of container=" + child.getParent().getName()
                    + " can't add to container=" + getName());
        }
		//初始化positionToAdd为-1
        int positionToAdd = -1;
        if (comparator != null) {
            final int count = mChildren.size();
            for (int i = 0; i < count; i++) {
            	//把当前窗口的mSubLayer与mChildren里的所有窗口比较,只要mChildren中
            	//有一个窗口的mSubLayer大于当前窗口就可以结束比较了
            	//因为mChildren里总是按照mSubLayer大小顺序排列的
                if (comparator.compare(child, mChildren.get(i)) < 0) {
                    positionToAdd = i;
                    break;
                }
            }
        }
        //positionToAdd等于-1说明当前添加的窗口的mSubLayer大于等于
        //所有mChildren里的窗口
        if (positionToAdd == -1) {
        	//则直接添加到mChildren的尾部
            mChildren.add(child);
        } else {
        	//否则将当前子窗口插入比较的那个窗口所在的位置
            mChildren.add(positionToAdd, child);
        }
        //回调
        onChildAdded(child);
        //这个方法最终会通过SurfaceControl的Transaction类的setLayer
        //方法,再通过JNI调用SurfaceFlinger的客户端代理SurfaceComposerClient
        //将窗口Z轴设置到SurfaceFlinger中去
        child.setParent(this);
    }

子窗口的Z轴计算和窗口排列规则:
 

Z轴计算:

子窗口的mBaseLayer由父窗口的type决定,根据对应type获取一个值然后乘上一个因子1000再加上1000,常见的应用Activity的窗口就是21000,子窗口还有一个mSubLayer,这个值根据子窗口自己的类型来获取的


窗口排列:

子窗口添加到WindowContainer中的WindowList规则是根据mSubLayer的大小进行排序,大于或等于会依次排列在WindowList尾部,小于则插入对应比较的窗口所在的位置,所以WindowList是按顺序从小到大排列的。

再回到WindowState构造方法看下非子窗口的分支,非子窗口很简单,根据自己窗口的type计算mBaseLayer,并将mSubLayer赋值为0

非子窗口的分支  添加到WindowList

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
        super(service);
        //省略赋值代码
        ......
        //如果是子窗口
        if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
            //计算窗口mBaseLayer,传入的是父窗口
            mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
           //计算窗口mSubLayer,传入的是当前窗口的类型
            mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
            mIsChildWindow = true;
            //根据自定义的比较器sWindowSubLayerComparator对子窗口排序
            parentWindow.addChild(this, sWindowSubLayerComparator);
			....
        } else {
            //计算窗口mBaseLayer
            mBaseLayer = mPolicy.getWindowLayerLw(this)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            //非子窗口mSubLayer为0
            mSubLayer = 0;
            mIsChildWindow = false;
			.....
        }
		//如果是应用窗口并且mShowForAllUsers为true
        if (mAppToken != null && mAppToken.mShowForAllUsers) {
            //添加FLAG_SHOW_WHEN_LOCKED,代表可以显示在锁屏上
            mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
        }

        mWinAnimator = new WindowStateAnimator(this);
        mWinAnimator.mAlpha = a.alpha;

        mRequestedWidth = 0;
        mRequestedHeight = 0;
        mLastRequestedWidth = 0;
        mLastRequestedHeight = 0;
        mLayer = 0;
    }
非子窗口添加

非子窗口并没有在WindowState构造方法中将自己添加到WindowList中,那在哪里添加的呢?我们回到WMS的addWindow方法。

public int addWindow(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,
            InsetsState outInsetsState) {
			......
				//每个窗口在WMS都会对应一个WindowState,描述了窗口相关信息
				final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
			......
				//将窗口添加到WindowContainer的WindowList中,并进行排序
				win.mToken.addWindow(win);
			......
}

win.mToken.addWindow(win)

mToken分为两种,应用类型窗口对应AppWindowToken,系统类型窗口对应WindowToken,AppWindowToken是WindowToken的子类,AppWindowToken的addWindow方法其实也会调到父类WindowToken的addWindow方法,我们就直接看WindowToken的addWindow方法。

 void addWindow(final WindowState win) {
        if (DEBUG_FOCUS) Slog.d(TAG_WM,
                "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
		//此窗口是子窗口直接return,子窗口已经在WindowState构造方法中添加了
        if (win.isChildWindow()) {
            return;
        }
        //此窗口没有向WindowList添加过
        if (!mChildren.contains(win)) {
        	//通过自定义比较器mWindowComparator对窗口进行排序
            addChild(win, mWindowComparator);
            //窗口添加之后代表窗口已经发生变化
            mWmService.mWindowsChanged = true;
        }
    }

非子窗口的添加和子窗口添加最终流程都一样,都会调到WindowContainer的addChild方法,只是比较器不同对应的窗口排序规则不同。

与IMS通信,接受事件和返回处理结果

WindowState里面有个很重要的步骤是调整窗口的Z轴排列顺序。

//创建InputChannel,InputChannel用来给WMS和InputDispatcher通信
//InputChannel创建同时创建了一对socket,InputDispatch监听
//一个socket一端来获取事件处理结果,应用程序监听一个socket一端
//来接收InputDispatch发送的事件
win.openInputChannel(outInputChannel);
 

win.openInputChannel(outInputChannel);

与SurfaceFlinger建立连接

//此方法里会创建SurfaceComposerClient建立应用层 //和SurfaceFlinger的连接

win.attach();


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值