zoukankan      html  css  js  c++  java
  • android Gui系统之WMS(2)----窗口的添加

    Android系统很多,但是最常用的就两类,一类是有系统进场管理的,系统窗口。还有一类就是由应用程序产生的,应用窗口。

    1.系统窗口的添加流程

    1.1 addStatusBarWindow

    PhoneStatus.java中

        private void addStatusBarWindow() {
            makeStatusBarView();
            mStatusBarWindowManager = new StatusBarWindowManager(mContext);
            mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
        }

    getStatusBarHeight() 获取状态栏的高度

        public int getStatusBarHeight() {
            if (mNaturalBarHeight < 0) {
                final Resources res = mContext.getResources();
                mNaturalBarHeight =
                        res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
            }
            return mNaturalBarHeight;
        }

    可以看到,高度是固定的,在dimen里面配置。

    看看add方法

        public void add(View statusBarView, int barHeight) {
    
            // Now that the status bar window encompasses the sliding panel and its
            // translucent backdrop, the entire thing is made TRANSLUCENT and is
            // hardware-accelerated.
            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.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            mLp.gravity = Gravity.TOP;
            mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
            mLp.setTitle("StatusBar");
            mLp.packageName = mContext.getPackageName();
            mStatusBarView = statusBarView;
            mBarHeight = barHeight;
            mWindowManager.addView(mStatusBarView, mLp);
            mLpChanged = new WindowManager.LayoutParams();
            mLpChanged.copyFrom(mLp);
        }

    layoutparams属性,还有设置在顶部。

    mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;

    软键盘被覆盖,绝大多数情况下,statusbar的显示不会影响到软件盘的位置,如果有,软键盘调整,statusbar优先显示。

    最后是将statusbar加入到WMS里面。

    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    所以mWindowManager就是WMS的一个bind代理。

    然后在看makeStatusBarView:

     protected PhoneStatusBarView makeStatusBarView() {
            final Context context = mContext;
    
            Resources res = context.getResources();
    
            updateDisplaySize(); // populates mDisplayMetrics
            updateResources();
    
            mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                    R.layout.super_status_bar, null);
            mStatusBarWindow.setService(this);
            mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    checkUserAutohide(v, event);
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        if (mExpandedVisible) {
                            animateCollapsePanels();
                        }
                    }
                    return mStatusBarWindow.onTouchEvent(event);
                }
            });
    
            mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
            mStatusBarView.setBar(this);
    
            PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
            mStatusBarView.setPanelHolder(holder);
    
            mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                    R.id.notification_panel);
            mNotificationPanel.setStatusBar(this);
    
            if (!ActivityManager.isHighEndGfx()) {
                mStatusBarWindow.setBackground(null);
                mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                        R.color.notification_panel_solid_background)));
            }
    
            mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
            mHeadsUpManager.setBar(this);
            mHeadsUpManager.addListener(this);
            mHeadsUpManager.addListener(mNotificationPanel);
            mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
            mNotificationData.setHeadsUpManager(mHeadsUpManager);
    
            if (MULTIUSER_DEBUG) {
                mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                        R.id.header_debug_info);
                mNotificationPanelDebugText.setVisibility(View.VISIBLE);
            }
    
            try {
                boolean showNav = mWindowManagerService.hasNavigationBar();
                if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
                if (showNav) {
                    mNavigationBarView =
                        (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
    
                    mNavigationBarView.setDisabledFlags(mDisabled1);
                    mNavigationBarView.setBar(this);
                    mNavigationBarView.setOnVerticalChangedListener(
                            new NavigationBarView.OnVerticalChangedListener() {
                        @Override
                        public void onVerticalChanged(boolean isVertical) {
                            if (mAssistManager != null) {
                                mAssistManager.onConfigurationChanged();
                            }
                            mNotificationPanel.setQsScrimEnabled(!isVertical);
                        }
                    });
                    mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            checkUserAutohide(v, event);
                            return false;
                        }});
                }
            } catch (RemoteException ex) {
                // no window manager? good luck with that
            }
    
            mAssistManager = new AssistManager(this, context);
    
            // figure out which pixel-format to use for the status bar.
            mPixelFormat = PixelFormat.OPAQUE;
    
            mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                    R.id.notification_stack_scroller);
            mStackScroller.setLongPressListener(getNotificationLongClicker());
            mStackScroller.setPhoneStatusBar(this);
            mStackScroller.setGroupManager(mGroupManager);
            mStackScroller.setHeadsUpManager(mHeadsUpManager);
            mGroupManager.setOnGroupChangeListener(mStackScroller);
    
            mKeyguardIconOverflowContainer =
                    (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                            R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
            mKeyguardIconOverflowContainer.setOnActivatedListener(this);
            mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
            mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
    
            SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                            R.layout.status_bar_notification_speed_bump, mStackScroller, false);
            mStackScroller.setSpeedBumpView(speedBump);
            mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_no_notifications, mStackScroller, false);
            mStackScroller.setEmptyShadeView(mEmptyShadeView);
            mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
            mDismissView.setOnButtonClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
                    clearAllNotifications();
                }
            });
            mStackScroller.setDismissView(mDismissView);
            mExpandedContents = mStackScroller;
    
            mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
            mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
            mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
    
            ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
            ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
            View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
            mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
                    mScrimSrcModeEnabled);
            mHeadsUpManager.addListener(mScrimController);
            mStackScroller.setScrimController(mScrimController);
            mScrimController.setBackDropView(mBackdrop);
            mStatusBarView.setScrimController(mScrimController);
            mDozeScrimController = new DozeScrimController(mScrimController, context);
    
            mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
            mHeader.setActivityStarter(this);
            mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
            mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
            mKeyguardBottomArea =
                    (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
            mKeyguardBottomArea.setActivityStarter(this);
            mKeyguardBottomArea.setAssistManager(mAssistManager);
            mKeyguardIndicationController = new KeyguardIndicationController(mContext,
                    (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                            R.id.keyguard_indication_text),
                    mKeyguardBottomArea.getLockIcon());
            mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
    
            // set the inital view visibility
            setAreThereNotifications();
    
            mIconController = new StatusBarIconController(
                    mContext, mStatusBarView, mKeyguardStatusBar, this);
    
            // Background thread for any controllers that need it.
            mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
            mHandlerThread.start();
    
            // Other icons
            mLocationController = new LocationControllerImpl(mContext,
                    mHandlerThread.getLooper()); // will post a notification
            mBatteryController = new BatteryController(mContext);
            mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
                @Override
                public void onPowerSaveChanged() {
                    mHandler.post(mCheckBarModes);
                    if (mDozeServiceHost != null) {
                        mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
                    }
                }
                @Override
                public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                    // noop
                }
            });
            mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
            mHotspotController = new HotspotControllerImpl(mContext);
            mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
            mSecurityController = new SecurityControllerImpl(mContext);
            if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
                mRotationLockController = new RotationLockControllerImpl(mContext);
            }
            mUserInfoController = new UserInfoController(mContext);
            mVolumeComponent = getComponent(VolumeComponent.class);
            if (mVolumeComponent != null) {
                mZenModeController = mVolumeComponent.getZenController();
            }
            mCastController = new CastControllerImpl(mContext);
            final SignalClusterView signalCluster =
                    (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
            final SignalClusterView signalClusterKeyguard =
                    (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
            final SignalClusterView signalClusterQs =
                    (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
            mNetworkController.addSignalCallback(signalCluster);
            mNetworkController.addSignalCallback(signalClusterKeyguard);
            mNetworkController.addSignalCallback(signalClusterQs);
            signalCluster.setSecurityController(mSecurityController);
            signalCluster.setNetworkController(mNetworkController);
            signalClusterKeyguard.setSecurityController(mSecurityController);
            signalClusterKeyguard.setNetworkController(mNetworkController);
            signalClusterQs.setSecurityController(mSecurityController);
            signalClusterQs.setNetworkController(mNetworkController);
            final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
            if (isAPhone) {
                mNetworkController.addEmergencyListener(mHeader);
            }
    
            mFlashlightController = new FlashlightController(mContext);
            mKeyguardBottomArea.setFlashlightController(mFlashlightController);
            mKeyguardBottomArea.setPhoneStatusBar(this);
            mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
            mAccessibilityController = new AccessibilityController(mContext);
            mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
            mNextAlarmController = new NextAlarmController(mContext);
            mKeyguardMonitor = new KeyguardMonitor(mContext);
            if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
                mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
                        mHandler);
            }
            mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
                    (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
                    mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
    
    
            // Set up the quick settings tile panel
            mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
            if (mQSPanel != null) {
                final QSTileHost qsh = new QSTileHost(mContext, this,
                        mBluetoothController, mLocationController, mRotationLockController,
                        mNetworkController, mZenModeController, mHotspotController,
                        mCastController, mFlashlightController,
                        mUserSwitcherController, mKeyguardMonitor,
                        mSecurityController);
                mQSPanel.setHost(qsh);
                mQSPanel.setTiles(qsh.getTiles());
                mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
                mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
                mHeader.setQSPanel(mQSPanel);
                qsh.setCallback(new QSTileHost.Callback() {
                    @Override
                    public void onTilesChanged() {
                        mQSPanel.setTiles(qsh.getTiles());
                    }
                });
            }
    
            // User info. Trigger first load.
            mHeader.setUserInfoController(mUserInfoController);
            mKeyguardStatusBar.setUserInfoController(mUserInfoController);
            mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
            mUserInfoController.reloadUserInfo();
    
            mHeader.setBatteryController(mBatteryController);
            ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
                    mBatteryController);
            mKeyguardStatusBar.setBatteryController(mBatteryController);
            mHeader.setNextAlarmController(mNextAlarmController);
    
            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
            mBroadcastReceiver.onReceive(mContext,
                    new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
            mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                    "GestureWakeLock");
            mVibrator = mContext.getSystemService(Vibrator.class);
    
            // receive broadcasts
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            filter.addAction(Intent.ACTION_SCREEN_ON);
            context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
    
            IntentFilter demoFilter = new IntentFilter();
            if (DEBUG_MEDIA_FAKE_ARTWORK) {
                demoFilter.addAction(ACTION_FAKE_ARTWORK);
            }
            demoFilter.addAction(ACTION_DEMO);
            context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
                    android.Manifest.permission.DUMP, null);
    
            // listen for USER_SETUP_COMPLETE setting (per-user)
            resetUserSetupObserver();
    
            // disable profiling bars, since they overlap and clutter the output on app windows
            ThreadedRenderer.overrideProperty("disableProfileBars", "true");
    
            // Private API call to make the shadows look better for Recents
            ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
    
            return mStatusBarView;
        }
    makeStatusBarView

    看着代码很多,很复杂。其实总的来说很简单,就是new了一个view,然后设置一些属性。

    1.2 WMS addwindow

    WMS并不关心View的Tree的具体内容,它只要知道个应用进程的显示界面大小,“层级值”(这些信息包含在windowmanager.layoutparams)

     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 attachedWindow = null;
            long origId;
            final int type = attrs.type;
    
            synchronized(mWindowMap) {
                if (!mDisplayReady) {
                    throw new IllegalStateException("Display has not been initialialized");
                }
    
                final DisplayContent displayContent = getDisplayContentLocked(displayId);
                if (displayContent == null) {
                    Slog.w(TAG, "Attempted to add window to a display that does not exist: "
                            + displayId + ".  Aborting.");
                    return WindowManagerGlobal.ADD_INVALID_DISPLAY;
                }
                if (!displayContent.hasAccess(session.mUid)) {
                    Slog.w(TAG, "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, "Window " + client + " is already added");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
    
                if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                    attachedWindow = windowForClientLocked(null, attrs.token, false);
                    if (attachedWindow == null) {
                        Slog.w(TAG, "Attempted to add window with token that is not a window: "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }
                    if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
                            && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                        Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }
                }
    
                if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
                    Slog.w(TAG, "Attempted to add private presentation window to a non-private display.  Aborting.");
                    return WindowManagerGlobal.ADD_PERMISSION_DENIED;
                }
    
                boolean addToken = false;
                WindowToken token = mTokenMap.get(attrs.token);
                if (token == null) {
                    if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                        Slog.w(TAG, "Attempted to add application window with unknown token "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    if (type == TYPE_INPUT_METHOD) {
                        Slog.w(TAG, "Attempted to add input method window with unknown token "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    if (type == TYPE_VOICE_INTERACTION) {
                        Slog.w(TAG, "Attempted to add voice interaction window with unknown token "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    if (type == TYPE_WALLPAPER) {
                        Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    if (type == TYPE_DREAM) {
                        Slog.w(TAG, "Attempted to add Dream window with unknown token "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    if (type == TYPE_ACCESSIBILITY_OVERLAY) {
                        Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                    token = new WindowToken(this, attrs.token, -1, false);
                    addToken = true;
                } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                    AppWindowToken atoken = token.appWindowToken;
                    if (atoken == null) {
                        Slog.w(TAG, "Attempted to add window with non-application token "
                              + token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                    } else if (atoken.removed) {
                        Slog.w(TAG, "Attempted to add window with exiting application token "
                              + token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_APP_EXITING;
                    }
                    if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                        // No need for this guy!
                        if (localLOGV) Slog.v(
                                TAG, "**** NO NEED TO START: " + attrs.getTitle());
                        return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                    }
                } else if (type == TYPE_INPUT_METHOD) {
                    if (token.windowType != TYPE_INPUT_METHOD) {
                        Slog.w(TAG, "Attempted to add input method window with bad token "
                                + attrs.token + ".  Aborting.");
                          return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                } else if (type == TYPE_VOICE_INTERACTION) {
                    if (token.windowType != TYPE_VOICE_INTERACTION) {
                        Slog.w(TAG, "Attempted to add voice interaction window with bad token "
                                + attrs.token + ".  Aborting.");
                          return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                } else if (type == TYPE_WALLPAPER) {
                    if (token.windowType != TYPE_WALLPAPER) {
                        Slog.w(TAG, "Attempted to add wallpaper window with bad token "
                                + attrs.token + ".  Aborting.");
                          return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                } else if (type == TYPE_DREAM) {
                    if (token.windowType != TYPE_DREAM) {
                        Slog.w(TAG, "Attempted to add Dream window with bad token "
                                + attrs.token + ".  Aborting.");
                          return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
                    if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
                        Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                } else if (token.appWindowToken != null) {
                    Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
                    // It is not valid to use an app token with other system types; we will
                    // instead make a new token for it (as if null had been passed in for the token).
                    attrs.token = null;
                    token = new WindowToken(this, null, -1, false);
                    addToken = true;
                }
    
                WindowState win = new WindowState(this, session, client, token,
                        attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
                if (win.mDeathRecipient == null) {
                    // Client has apparently died, so there is no reason to
                    // continue.
                    Slog.w(TAG, "Adding window client " + client.asBinder()
                            + " that is dead, aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                }
    
                if (win.getDisplayContent() == null) {
                    Slog.w(TAG, "Adding window to Display that has been removed.");
                    return WindowManagerGlobal.ADD_INVALID_DISPLAY;
                }
    
                mPolicy.adjustWindowParamsLw(win.mAttrs);
                win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
    
                res = mPolicy.prepareAddWindowLw(win, attrs);
                if (res != WindowManagerGlobal.ADD_OKAY) {
                    return res;
                }
    
                if (outInputChannel != null && (attrs.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    String name = win.makeInputChannelName();
                    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                    win.setInputChannel(inputChannels[0]);
                    inputChannels[1].transferTo(outInputChannel);
    
                    mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
                }
    
                // From now on, no exceptions or errors allowed!
    
                res = WindowManagerGlobal.ADD_OKAY;
    
                origId = Binder.clearCallingIdentity();
    
                if (addToken) {
                    mTokenMap.put(attrs.token, token);
                }
                win.attach();
                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);
                    }
                }
    
                if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
                    token.appWindowToken.startingWindow = win;
                    if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
                            + " startingWindow=" + win);
                }
    
                boolean imMayMove = true;
    
                if (type == TYPE_INPUT_METHOD) {
                    win.mGivenInsetsPending = true;
                    mInputMethodWindow = win;
                    addInputMethodWindowToListLocked(win);
                    imMayMove = false;
                } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                    mInputMethodDialogs.add(win);
                    addWindowToListInOrderLocked(win, true);
                    moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
                    imMayMove = false;
                } else {
                    addWindowToListInOrderLocked(win, true);
                    if (type == TYPE_WALLPAPER) {
                        mLastWallpaperTimeoutTime = 0;
                        displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                    } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                        displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                    } else if (mWallpaperTarget != null
                            && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                        // If there is currently a wallpaper being shown, and
                        // the base layer of the new window is below the current
                        // layer of the target window, then adjust the wallpaper.
                        // This is to avoid a new window being placed between the
                        // wallpaper and its target.
                        displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                }
    
                final WindowStateAnimator winAnimator = win.mWinAnimator;
                winAnimator.mEnterAnimationPending = true;
                winAnimator.mEnteringAnimation = true;
    
                if (displayContent.isDefaultDisplay) {
                    mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
                            outOutsets);
                } else {
                    outContentInsets.setEmpty();
                    outStableInsets.setEmpty();
                }
    
                if (mInTouchMode) {
                    res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
                }
                if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                    res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
                }
    
                mInputMonitor.setUpdateInputWindowsNeededLw();
    
                boolean focusChanged = false;
                if (win.canReceiveKeys()) {
                    focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                            false /*updateInputWindows*/);
                    if (focusChanged) {
                        imMayMove = false;
                    }
                }
    
                if (imMayMove) {
                    moveInputMethodWindowsIfNeededLocked(false);
                }
    
                assignLayersLocked(displayContent.getWindowList());
                // Don't do layout here, the window must call
                // relayout to be displayed, so we'll do it there.
    
                if (focusChanged) {
                    mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
                }
                mInputMonitor.updateInputWindowsLw(false /*force*/);
    
                if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client "
                        + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
    
                if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                    reportNewConfig = true;
                }
            }
    
            if (reportNewConfig) {
                sendNewConfiguration();
            }
    
            Binder.restoreCallingIdentity(origId);
    
            return res;
        }
    addWindow

    step1. 检查权限

    如果窗口类型是

            if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
                // Window manager will make sure these are okay.
                return WindowManagerGlobal.ADD_OKAY;
            }

    非系统窗口,任何app 都可以添加,就没有什么问题。

    step2.避免重复添加

                if (mWindowMap.containsKey(client.asBinder())) {
                    Slog.w(TAG, "Window " + client + " is already added");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }

    step3.子窗口

                if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                    attachedWindow = windowForClientLocked(null, attrs.token, false);
                    if (attachedWindow == null) {
                        Slog.w(TAG, "Attempted to add window with token that is not a window: "
                              + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }
                    if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
                            && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                        Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                    }
                }

    通过token,寻找client   windowForClientLocked

    Step4. token 检查

    根据type的类型,检查token的有效性。

    这里有好几个token相关的变量

    WindowToken token = mTokenMap.get(attrs.token);
    attrs.token

    attrs.token 类型为IBinder。它代表这个窗口的“主人”.AMS 为每一个activity对象都创建一个ActivityRecord对象,本质就是IBinder。

    boolean addToken = false;

    用以表述新的token有没有被添加

    这是几个token之间的关系图。

    1)如果attrs.token在mTokenMap中找不到的话,说明AMS没有对应的记录

         if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
    TYPE_INPUT_METHOD
    TYPE_VOICE_INTERACTION
    TYPE_WALLPAPER
    TYPE_DREAM
    TYPE_ACCESSIBILITY_OVERLAY

    这些是由AMS记录的,不会找不到,如果没有,说明出现不可预知的错误。返回

    2)除了上述type之外,WMS允许AMS没有记录的情况,则为这个窗口创建一个token

    attrs.token在mTokenMap可以找到的话,此时只有上面检查的那些

     if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
    TYPE_INPUT_METHOD
    TYPE_VOICE_INTERACTION
    TYPE_WALLPAPER
    TYPE_DREAM
    TYPE_ACCESSIBILITY_OVERLAY

    才有可能被找到。所以,需要做一些判断和比较。

    Step5. WindowState

    如果一切顺利,new 一个WindowState

                WindowState win = new WindowState(this, session, client, token,
                        attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

    this代表WMS自身

    session 是WMS给窗口使用者的IWindowSession

    client是IWindow,即窗口给WMS的一个访问通道

    step6

    if (win.mDeathRecipient == null)

    如果窗口已经dead,就不需要进行下去。

    step6

    mPolicy.adjustWindowParamsLw(win.mAttrs);

    step7

    通过Policy进行调整。

                if (addToken) {
                    mTokenMap.put(attrs.token, token);
                }

    step8  添加新创建的token

                if (addToken) {
                    mTokenMap.put(attrs.token, token);
                }

    step9 重新排列layer值。

    因为我们新增加了一个窗口,很可能需要插入,所以需要进行排序。

    step10. getInsetHintLw

                if (displayContent.isDefaultDisplay) {
                    mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
                            outOutsets);

    计算窗口的tContentInset

    step11.给排好序列的窗口,最终赋一个layer值

    1.3 addAppWindowToListLocked

    private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
            if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
                    " Callers=" + Debug.getCallers(4));
            if (win.mAttachedWindow == null) {
                final WindowToken token = win.mToken;
                int tokenWindowsPos = 0;
                if (token.appWindowToken != null) {
                    tokenWindowsPos = addAppWindowToListLocked(win);
                } else {
                    addFreeWindowToListLocked(win);
                }
                if (addToToken) {
                    if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                    token.windows.add(tokenWindowsPos, win);
                }
            } else {
                addAttachedWindowToListLocked(win, addToToken);
            }
    
            if (win.mAppToken != null && addToToken) {
                win.mAppToken.allAppWindows.add(win);
            }
        }

    1)win.mAttachedWindow == null

    最外围的if,判断的是,是不是子类窗口,我们这里分析的是statusbar是系统窗口,所以考虑==null的情况

    2)token.appWindowToken != null 

    当前窗口是不是activity相关的,因为appWindowToken 是activity相关的。

    2 Activity窗口的添加

    WMS添加窗口是不区分系统还是应用的窗口,只是他们的权限还有层级不一样。

    AMS在启动Activity的时候,会把必要的信息传递给WMS

    servicescorejavacomandroidserveramActivityStack.java

     final void startActivityLocked(ActivityRecord r, boolean newTask,
                boolean doResume, boolean keepCurTransition, Bundle options) {
                mWindowManager.addAppToken(task.mActivities.indexOf(r),
                        r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
    
    }

    WMS 会把token记录到我们之前看到的mTokenMap中

    Activity什么时候会经历Add view 进而通过WMS addwindow 把窗口添加到系统中呢?

    我们看下ActivityThread中的handleResumeActivity

    ActivityClientRecord r = performResumeActivity(token, clearHide);

    首先Resume的启动,就是在这里执行的

    DecorView是每个Activity的最外面的一层布局。

    if (r.window == null && !a.mFinished && willBeVisible) {
                    r.window = r.activity.getWindow();
                    View decor = r.window.getDecorView();//DecorView
                    decor.setVisibility(View.INVISIBLE);//可见性
                    ViewManager wm = a.getWindowManager();//WindowManagerImpl
                    WindowManager.LayoutParams l = r.window.getAttributes();//窗口参数
                    a.mDecor = decor;
                    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//窗口类型
             l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; wm.addView(decor, l);
    }

    将窗口添加wm.addView(decor, l)

    在WMS添加窗口的过程基本与上面statusbar类似。

    在WMS中:

    private int addAppWindowToListLocked(final WindowState win) 

    这里分2中情况

    1)application已经含有窗口的情况下

    if (!tokenWindowList.isEmpty()) {
                // If this application has existing windows, we
                // simply place the new window on top of them... but
                // keep the starting window on top.

    2)如果没有窗口,情况就复杂一点

    WMS将部分token的数据放到了  

    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;

    在所有apptoken中,寻找当前token适合的位子。

    // We now know the index into the apps.  If we found
            // an app window above, that gives us the position; else
            // we need to look some more.
            if (pos != null) {

    如果找到了合适的位置,pos就有值。

    check WindowToken的位置,如果有对应的,就直接返回对应的pos

                        WindowState bottom = tokenWindowList.get(0);
                        if (bottom.mSubLayer < 0) {
                            pos = bottom;
                        }
                    }

    如果参考窗口没有,就直接选中最后一个。

    如果pos == null,也就是没有找到对应的参考值。

    这时候就寻找下一个token对应的值。如果找到就用pos

    如果还没有找到,那只能对应BaseLayer的值,找到一个合适的位置。

    参考:

    《深入理解Android 内核设计思想》 林学森

  • 相关阅读:
    R 包安装问题
    特征值分解与奇异值分解
    向量内积&外积
    hdu_3449(有依赖背包)
    Gene co-expression analysis for functional classification and gene–disease predictions
    MCMC & 贝叶斯
    继承(来自视频)
    面向对象 创建对象
    mongodb笔记(三)
    mongodb笔记(二)
  • 原文地址:https://www.cnblogs.com/deman/p/5702257.html
Copyright © 2011-2022 走看看