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

\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 内核设计思想》 林学森

android Gui系统之WMS(2)----窗口的添加的更多相关文章

  1. android Gui系统之WMS(1)----window flags & view flags

    SurfaceFlinger 前面说的,就是一个surface的合成.SurfaceFlinger就是一个默默的记录着,它不会对surface的内容有什么改动. WMS(WindowsManagerS ...

  2. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  3. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  4. Android GUI系统

    图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...

  5. 图解Android - Android GUI 系统 (1) - 概论

    Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...

  6. 图解Android - System Service 概论 和 Android GUI 系统

    通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...

  7. android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论

    GUI 是任何系统都很重要的一块. android GUI大体分为4大块. 1)SurfaceFlinger 2)WMS 3)View机制 4)InputMethod 这块内容非常之多,但是理解后,可 ...

  8. android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】

    转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...

  9. android Gui系统之SurfaceFlinger(3)---SurfaceFlinger

    7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...

随机推荐

  1. 代码实现SQL Server动态行转列,不用存储过程

    分两步查询,第一步查询出动态列,第二步使用PIVOT函数. 代码: List<DataTable> dataTableList = new List<DataTable>(); ...

  2. 使用Json.NET来序列化所需的数据

    我们在做开发的时候,很多时候需要和Json数据格式打交道,如Web开发里面,很多时候,数据通过Json进行传递到页面上,然后在进行处理的.而使用Json的时候,我们很多时候会涉及到几个序列化对象的使用 ...

  3. 只用CSS实现容器内图片上下左右居中

    一直以来,大家都知道,DIV容器内设置 text-align:center 即可让图片居中,但是DIV内默认的图片是上对齐,不会上下居中,如果想要实现这样的效果,JS判断是比较麻烦的,因为DIV容器内 ...

  4. IN31志愿者“孝行天下,感恩父母”晚会

    IN31是一群志愿者,为社会倾力奉献与引发爱的公益组织.成功举办第一场孝行天下的大型公益活动

  5. SQL Server2000导出数据时包含主键、字段默认值、描述等信息

    时经常用SQL Server2000自带的导出数据向导将数据从一台数据库服务器导出到另一台数据库服务器: 结果数据导出了,但表的主键.字段默认值.描述等信息却未能导出,一直没想出什么方法,今天又尝试了 ...

  6. iOS阶段学习第17天笔记(NSFileManager-NSFileHandle-文件操作)

    iOS学习(OC语言)知识点整理 一.单例模式 1)单例是一种编程思想,一个设计模式,与语言无关在采用了单例对象的应用程序中,需要单例类自行提供实例化单例对象, 不管实例化单例对象多少次,只有一个对象 ...

  7. PHP中用GD绘制饼图

    PHP中用GD绘制饼图,绘制的类见代码: Class Chart{ private $image; // 定义图像 private $title; // 定义标题 private $ydata; // ...

  8. CRC编码

    一.循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC. 它是利用除法及余数的原理来作错误侦测(Error Detecting)的.实际应用时,发送装置计算出CRC ...

  9. HDU 1141---Brackets Sequence(区间DP)

    题目链接 http://poj.org/problem?id=1141 Description Let us define a regular brackets sequence in the fol ...

  10. CentOS6.5下安装PostgreSQL

    一.配置 YUM 仓库 修改原始的 yum 仓库配置: vim /etc/yum.repos.d/CentOS-Base.repo 在[base]和[updates] 节(section)部分的尾部插 ...