你的位置:首页 > 操作系统

[操作系统]android Gui系统之WMS


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_METHODTYPE_VOICE_INTERACTIONTYPE_WALLPAPERTYPE_DREAMTYPE_ACCESSIBILITY_OVERLAY

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

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

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

 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)TYPE_INPUT_METHODTYPE_VOICE_INTERACTIONTYPE_WALLPAPERTYPE_DREAMTYPE_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

\services\core\java\com\android\server\am\ActivityStack.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 内核设计思想》 林学森