倉庫地址:http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ActivityThread.java
一、Window的創(chuàng)建以及相關聯類

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
.......
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
......
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
//Actvity和Window綁定在一起
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
if (customIntent != null) {
activity.mIntent = customIntent;
}
........
}
.........
}
- frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 創(chuàng)建Window的實例
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
//Activity和Window綁定在一起后,然后可以收到key的各種點擊事件
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
}
- frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
// 創(chuàng)建WindowManagerImpl對象
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
- frameworks/base/core/java/android/view/WindowManagerImpl
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
二、Window的屬性介紹
1、介紹Window常見屬性
Window的屬性有很多種,與應用開發(fā)最密切的有三種,它們分別是Type(Window的類型)、Flag(Window的標志)和SoftInputMode(軟鍵盤相關模式),下面分別介紹這三種Window的屬性。
2、Window的類型
Application Window(應用程序窗口)、Sub Windwow(子窗口)、System Window(系統(tǒng)窗口)三種類型,每種窗口又包含了很多種類型,它們都定義在WindowManager的靜態(tài)內部類LayoutParams中,接下來我們分別對這三大類進行講解。
-
應用程序窗口
Activity就是一個典型的應用程序窗口,應用程序窗口的Type值范圍為1到99。
frameworks/base/core/java/android/view/WindowManager.java
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION = 1;//窗口的基礎值,其他的窗口值要大于這個值
public static final int TYPE_APPLICATION = 2;//普通的應用程序窗口類型
public static final int TYPE_APPLICATION_STARTING = 3;//應用程序啟動窗口類型,用于系統(tǒng)在應用程序窗口啟動前顯示的窗口。
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;
-
子窗口
它不能獨立的存在,需要附著在其他窗口才可以,子窗口的Type值范圍為1000到1999。
frameworks/base/core/java/android/view/WindowManager.java
public static final int FIRST_SUB_WINDOW = 1000;//子窗口類型初始值
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
public static final int LAST_SUB_WINDOW = 1999;//子窗口類型結束值
-
系統(tǒng)窗口
Toast、輸入法窗口、系統(tǒng)音量條窗口、系統(tǒng)錯誤窗口都屬于系統(tǒng)窗口,系統(tǒng)窗口的Type值范圍為2000到2999。
frameworks/base/core/java/android/view/WindowManager.java
public static final int FIRST_SYSTEM_WINDOW = 2000;//系統(tǒng)窗口類型初始值
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;//系統(tǒng)狀態(tài)欄窗口
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;//搜索條窗口
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;//通話窗口
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;//系統(tǒng)ALERT窗口
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;//鎖屏窗口
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;//TOAST窗口
...
public static final int LAST_SYSTEM_WINDOW = 2999;//系統(tǒng)窗口類型結束值
3、Window的標志
Window的標志也就是Flag,用于控制Window的顯示,同樣被定義在WindowManager的內部類LayoutParams中,一共有20多個,這里我們給出幾個比較常用。

- 第一種是通過Window的addFlags方法
Window mWindow =getWindow();
mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- 第二種通過Window的setFlags方法
Window mWindow =getWindow();
mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
,WindowManager.LayoutParams.FLAG_FULLSCREEN);
- 第三種則是給LayoutParams設置Flag,并通過WindowManager的addView方法進行添加
WindowManager.LayoutParams mWindowLayoutParams =
new WindowManager.LayoutParams();
mWindowLayoutParams.flags=WindowManager.LayoutParams.FLAG_FULLSCREEN;
WindowManager mWindowManager =(WindowManager) getSystemService(Context.WINDOW_SERVICE);
TextView mTextView=new TextView(this);
mWindowManager.addView(mTextView,mWindowLayoutParams);
4、軟鍵盤相關模式
WindowManager的靜態(tài)內部類LayoutParams中定義了軟鍵盤相關模式,這里給出常用的幾個:

從上面給出的SoftInputMode ,可以發(fā)現,它們與AndroidManifest中Activity的屬性android:windowSoftInputMode是對應的。因此,除了在AndroidMainfest中為Activity設置android:windowSoftInputMode以外還可以在Java代碼中為Window設置SoftInputMode:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
三、系統(tǒng)添加View的流程
-
系統(tǒng)添加view的流程
image.png
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
public void add(View statusBarView, int barHeight) {
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
barHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR,//1
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;
//添加當前系統(tǒng)view到WindowManagerImpl中
mWindowManager.addView(mStatusBarView, mLp);//2
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
}
frameworks/base/core/java/android/WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...//參數檢查
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
//如果當前窗口要作為子窗口,就會根據父窗口對子窗口的WindowManager.LayoutParams類型的wparams對象進行相應調整
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
...
}
ViewRootImpl root;
View panelParentView = null;
...
//創(chuàng)建ViewRootImpl對象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//mViews存儲窗口的view對象
mViews.add(view);
//mRoots存儲ViewRootImpl所有元素
mRoots.add(root);
//WindowManager.LayoutParams類型的wparams對象
mParams.add(wparams);
}
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}
frameworks/base/core/java/android/view/ViewRootImpl.java
- ViewRootImpl身負了很多職責:
- View樹的根并管理View樹
- 觸發(fā)View的測量、布局和繪制
- 輸入事件的中轉站
- 管理Surface
- 負責與WMS進行進程間通信
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//mWindowSession是IWindowSession類型的,它是一個Binder對象,用于進行進程間通信,IWindowSession是Client端的代理,
//它的Server端的實現為Session
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
...
}
frameworks/base/services/core/java/com/android/server/wm/Session.java
addToDisplay方法中會調用了WMS的addWindow方法,并將自身也就是Session,作為參數傳了進去,每個應用程序進程都會對應一個Session,WMS會用ArrayList來保存這些Session。這樣剩下的工作就交給WMS來處理,在WMS中會為這個添加的窗口分配Surface,并確定窗口顯示次序,可見負責顯示界面的是畫布Surface,而不是窗口本身。WMS會將它所管理的Surface交由SurfaceFlinger處理,SurfaceFlinger會將這些Surface混合并繪制到屏幕上,后續(xù)會接著分析WMS的addWindow方法
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
