原計(jì)劃 input 輸入事件的學(xué)習(xí)分為兩節(jié)內(nèi)容學(xué)習(xí)并記錄毅舆,經(jīng)學(xué)習(xí)發(fā)現(xiàn)并遠(yuǎn)不止這些內(nèi)容,所以決定重新寫(xiě) input 輸入事件番外篇端逼,如需參考朗兵,請(qǐng)閱讀 input 輸入事件番外篇;造成的不便顶滩,深表抱歉余掖。
1. Window 的創(chuàng)建和 WMS的綁定
上一節(jié)中講到 dispatchMotionLocked() 向目標(biāo)窗口分發(fā)事件,這里簡(jiǎn)單介紹一下目標(biāo)窗口是如何獲取和綁定的;在 Activity 的啟動(dòng)流程中(具體可以參考 筆記14):
(1)handleLaunchActivity() 調(diào)用了 performLaunchActivity() ->
(2)performLaunchActivity() 中調(diào)用了 activity.attach()方法盐欺,之前就說(shuō)過(guò)這個(gè)是對(duì) activity進(jìn)行綁定赁豆,完成這一步activity才成為四大組件之一,未完成時(shí)都只能算一個(gè)對(duì)象(創(chuàng)建activity的第一步) ->
(3)handleLaunchActivity() 調(diào)用了 handleResumeActivity() 方法(第二步:onResume()并渲染)冗美;
窗口的獲取和綁定就在 performLaunchActivity() 調(diào)用的 activity.attach() 中完成的魔种,進(jìn)入源碼中看看:
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, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
// 創(chuàng)建 Window
// 這里的 mWindow 時(shí) PhoneWindow,后續(xù)版本的 mWindow 初始化如下粉洼,更加直觀:
// mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
// ...
// 在window中創(chuàng)建時(shí) mWindowManager 其實(shí)是 WindowManagerImpl节预,代碼不復(fù)雜,可以跟進(jìn)去看看
mWindow.setWindowManager( // 設(shè)置 WindowManager
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager(); // 這里就可以獲取 WindowManager 了
mCurrentConfig = config;
}
在這里記住三個(gè)知識(shí)點(diǎn)(后續(xù)講setContentView時(shí)再詳細(xì)分析):
a. Window 類是一個(gè)抽象類属韧,它的唯一實(shí)現(xiàn)類是 PhoneWindow安拟;
b. PhoneWindow 有一個(gè)內(nèi)部類 DecorView,DecorView 是 Activity 的根 View宵喂;
c. DecorView 繼承自 FramLayout糠赦;
關(guān)于創(chuàng)建Window對(duì)象:
PolicyManager為策略類,其實(shí)現(xiàn)類Policy 的makeNewWindow內(nèi)部創(chuàng)建了window對(duì)象锅棕;
// mWindow = PolicyManager.makeNewWindow(this):
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static { // 通過(guò)反射創(chuàng)建 sPolicy
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
} catch (ClassNotFoundException ex) {
// ...
}
}
private PolicyManager() {}
// 創(chuàng)建PhoneWindow
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
public static LayoutInflater makeNewLayoutInflater(Context context) {
return sPolicy.makeNewLayoutInflater(context);
}
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
return sPolicy.makeNewFallbackEventHandler(context);
}
}
// Policy.java 類中的 makeNewWindow() 方法:
public window makeNewWindow(Context context){
return new PhoneWindow(context);
}
2. ViewRootImpl 與 WMS 的通信
// 第二步:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// 主要作用是調(diào)用performResumeActivity()到activity的onResume狀態(tài)拙泽,然后獲取
// DecorView,創(chuàng)建一個(gè)關(guān)聯(lián)的ViewRootImpl對(duì)象,用來(lái)配合WindowManagerService
// 服務(wù)來(lái)管理該Activity組件的窗口狀態(tài)裸燎,最后addView
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
// ...
//activity創(chuàng)建成功顾瞻,window此時(shí)為空,進(jìn)入此分支德绿;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
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;
// 一層層的看最終調(diào)用的是:WindowManagerGlobal.java -> addView()
wm.addView(decor, l); // 這里就是測(cè)量朋其,擺放,繪制
}
} else if (!willBeVisible) {
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r);
// ...
}
}
2.1 wm.addView(decor, l):這里的 wm 是 WindowManagerImpl脆炎,查看一下 addView() 方法:
// WindowManagerImpl.addView():
// 單例獲取 WindowManagerGlobal
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
//WindowManagerGlobal.addView():
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// ... 省略部分代碼:參數(shù)的校驗(yàn)
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
// ...
ViewRootImpl root;
View panelParentView = null;
//...
// 實(shí)例化ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
// 添加 view 到全局集合中
// 如果想 hook 全部的 view 時(shí),可以通過(guò)反射獲取 WindowManagerGlobal -> mViews氓辣;
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try { //將view添加到ViewRootImpl中去
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// ...
}
}
ViewRootImpl.setView():
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
// 這里先將 mView 保存了 DecorView 的實(shí)例秒裕,
// 然后調(diào)用 requestLayout() 方法,以完成應(yīng)用程序用戶界面的初次布局钞啸。
if (mView == null) {
mView = view;
// mWindowAttributes保存了窗口所對(duì)應(yīng)的LayoutParams
mWindowAttributes.copyFrom(attrs);
/**
* 在添加窗口之前几蜻,先通過(guò)requestLayout方法在主線程上安排一次“遍歷”。
* 所謂“遍歷”是指ViewRootImpl中的核心方法performTraversal()体斩。
* 這個(gè)方法實(shí)現(xiàn)對(duì)控件樹(shù)進(jìn)行測(cè)量梭稚、布局、向WMS申請(qǐng)修改窗口屬性以及重繪的所有工作絮吵。
*/
requestLayout();
/***初始化mInputChannel弧烤。InputChannel是窗口接受來(lái)自InputDispatcher 的輸入事件的管道。
注意蹬敲,僅當(dāng)窗口的屬性inputFeatures不含有 INPUT_FEATURE_NO_INPUT_CHANNEL時(shí)才
會(huì)創(chuàng)建 InputChannel暇昂,否則mInputChannel 為空莺戒,從而導(dǎo)致此窗口無(wú)法接受任何輸入事件 */
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel(); // 見(jiàn) 2.2
}
try {
// ...
/* 將窗口添加到WMS中。完成這個(gè)操作之后急波,mWindow已經(jīng)被添加到指定的Display中去
而且mInputChannel(如果不為空)已經(jīng)準(zhǔn)備好接受事件了从铲。只是由于這個(gè)窗口沒(méi)有進(jìn)行
過(guò)relayout(),因此它還沒(méi)有有效的Surface可以進(jìn)行繪制 */
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel); // 見(jiàn)2.3
// 這里的 mWindowSession 是向WMS跨進(jìn)程請(qǐng)求獲取的
} catch (RemoteException e) {
// ...
} finally {
// ...
}
}
}
2.2 InputChannel的構(gòu)造函數(shù):此時(shí) mInputChannel = new InputChannel() 這里還是一個(gè) Java 的對(duì)象澄暮;
public final class InputChannel implements Parcelable {
private static final String TAG = "InputChannel";
@SuppressWarnings("unused")
private long mPtr; // used by native code
private static native InputChannel[] nativeOpenInputChannelPair(String name);
private native void nativeDispose(boolean finalized);
private native void nativeTransferTo(InputChannel other);
private native void nativeReadFromParcel(Parcel parcel);
private native void nativeWriteToParcel(Parcel parcel);
private native void nativeDup(InputChannel target);
private native String nativeGetName();
// 構(gòu)造函數(shù)中沒(méi)有任何操作名段,此時(shí) mInputChannel = new InputChannel() 只是一個(gè)普通的java對(duì)象;
// 那么要想具有 c++ 的屬性泣懊,唯一的方法就是持有c++對(duì)象的指針伸辟,也就是將 mPtr 賦值;
public InputChannel() {
}
// ...
}
2.3 mWindowSession.addToDisplay():
首先嗅定,mWindowSession 是如何獲取到的:
// mWindowSession 的初始化:ViewRootImpl 的構(gòu)造函數(shù)中進(jìn)行初始化的自娩;
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession(); // 通過(guò) WMS 獲取
}
// 通過(guò) WMS 獲取 mWindowSession:WindowManagerGlobal類中的 getWindowSession() 方法
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}
// WMS 中openSession():
//IWindowSession :一個(gè)aidl接口,它的真的實(shí)現(xiàn)類是Session渠退,它是一個(gè)Binder對(duì)象忙迁,用來(lái)和
//WindowManagerService建立連接,在ViewRootImpl的setView中最終也是通過(guò)它和WindowManagerService
//通信完成了Window的添加的碎乃。這個(gè)Session是應(yīng)用唯一的姊扔,它的創(chuàng)建時(shí)在WindowManagerGloable中通過(guò)getWindowSession獲取的
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
這里創(chuàng)建了 Session 對(duì)象,其參數(shù) this 就是 WMS梅誓;
mWindowSession.addToDisplay() 就是 調(diào)用了Session的 addToDisplay() 方法:
// Session 的 addToDisplay() 方法:又是跨進(jìn)程通訊
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
// outInputChannel 是 2.2 中 mInputChannel = new InputChannel()恰梢,此時(shí)的指針還未賦值
// mService 就是 new Session 時(shí)傳入的 WMS
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
WMS的addWindow() 方法:
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, 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;
WindowState win = null; // window 對(duì)象的信息
long origId;
final int type = attrs.type;
synchronized(mWindowMap) {
// ...
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
// ...
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
// 關(guān)鍵代碼,打開(kāi)一對(duì) InputChannel梗掰,客戶端和服務(wù)端 見(jiàn) 2.3.1
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
// WMS 設(shè)置 Channel 為 inputChannels[0]
win.setInputChannel(inputChannels[0]);
// 客戶端設(shè)置 Channel 為 inputChannels[1]嵌言,此時(shí)給上面 Java層的 mInputChannel 中 mPtr 賦值
// 經(jīng)過(guò)賦值后,Java 層 mInputChannel 才具有 c++ 的對(duì)象
inputChannels[1].transferTo(outInputChannel);
// 將服務(wù)端的socket注冊(cè)到InputDispatcher中 見(jiàn) 2.3.2
// 這里的 win.mInputWindowHandle 是在 win 初始化的時(shí)候 new 出來(lái)的及穗;
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
// ...
// 每次添加都會(huì)更新摧茴,見(jiàn) 2.3.3
mInputMonitor.updateInputWindowsLw(false /*force*/);
// ...
}
// ...
}
2.3.1 建立socket 通信:
InputChannel.openInputChannelPair(name) 是一個(gè)native方法,在 frameworks/base/core/jni/
android_view_InputChannel.cpp中:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
// 創(chuàng)建一對(duì) socket 通信
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result) {
String8 message;
message.appendFormat("Could not open input channel pair. status=%d", result);
jniThrowRuntimeException(env, message.string());
return NULL;
}
// 封裝成java對(duì)象
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
InputChannel.cpp中:
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
// ...
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
socketpair()函數(shù)用于創(chuàng)建一對(duì)無(wú)名的埂陆、相互連接的套接字苛白。
如果函數(shù)成功,則返回0焚虱,創(chuàng)建好的套接字分別是sv[0]和sv[1]购裙;否則返回-1,錯(cuò)誤碼保存于errno中鹃栽。
用法:
(1) 這對(duì)套接字可以用于全雙工通信躏率,每一個(gè)套接字既可以讀也可以寫(xiě)。例如,可以往sv[0]中寫(xiě)禾锤,從sv[1]中讀私股;或者從sv[1]中寫(xiě),從sv[0]中讀恩掷;
(2) 如果往一個(gè)套接字(如sv[0])中寫(xiě)入后倡鲸,再?gòu)脑撎捉幼肿x時(shí)會(huì)阻塞,只能在另一個(gè)套接字中(sv[1])上讀成功黄娘;
(3)讀峭状、寫(xiě)操作可以位于同一個(gè)進(jìn)程,也可以分別位于不同的進(jìn)程逼争,如父子進(jìn)程优床。如果是父子進(jìn)程時(shí),一般會(huì)功能分離誓焦,一個(gè)進(jìn)程用來(lái)讀胆敞,一個(gè)用來(lái)寫(xiě)。因?yàn)槲募枋龇鹲v[0]和sv[1]是進(jìn)程共享的杂伟,所以讀的進(jìn)程要關(guān)閉寫(xiě)描述符, 反之移层,寫(xiě)的進(jìn)程關(guān)閉讀描述符。
2.3.2 注冊(cè):frameworks/base/services/core/jni/
com_android_server_input_InputManagerService.cpp 中:
// nativeRegisterInputChannel():
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
throwInputChannelNotInitialized(env);
return;
}
// window 的一些信息
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel( // 注冊(cè)的方法赫粥,如下 registerInputChannel()方法:
env, inputChannel, inputWindowHandle, monitor);
if (status) {
String8 message;
message.appendFormat("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.string());
return;
}
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
// registerInputChannel()方法:
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
// 終于看到我們 InputDispatcher 了
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
InputDispatcher.cpp 中的注冊(cè)方法:registerInputChannel()
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
// 連接的媒介观话,只是一個(gè)對(duì)象,沒(méi)有跨進(jìn)程等操作越平;
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
// 傳入 fd 和 connection频蛔,關(guān)聯(lián) fd 和 connection;
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
2.3.3 InputMonitor
簡(jiǎn)介:實(shí)現(xiàn)了 WindowManagerCallbacks接口秦叛,在 WindowManagerService 的構(gòu)造函數(shù)中創(chuàng)建了InputMonitor 對(duì)象晦溪,并以 mInputMonitor 作為參數(shù)創(chuàng)建 InputManagerService 的對(duì)象,在 InputManagerService 構(gòu)造函數(shù)中挣跋,將 mInputMonitor 作為參數(shù)調(diào)用了 JNI 函數(shù) nativeInit() 尼变,將回調(diào)接口傳到JNI層,在需要的時(shí)候浆劲,JNI 再回調(diào) mInputMonitor中 的函數(shù),實(shí)現(xiàn)數(shù)據(jù)才傳遞哀澈。
public interface WindowManagerCallbacks {
public void notifyConfigurationChanged();
// 輸入設(shè)備的配置變更
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
// 連接InputDispatcher 與應(yīng)用程序的 socket 通道
public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
// ANR
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason);
// 以下三個(gè)回調(diào)牌借,是WMS在消息處理中有優(yōu)先權(quán)處理
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
// 按鍵事件在整個(gè)事件處理過(guò)程中沒(méi)有任何處理時(shí),發(fā)送給 WMS
public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
KeyEvent event, int policyFlags);
public int getPointerLayer();
}
// 簡(jiǎn)化代碼:
final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
private final WindowManagerService mService;
private WindowState mInputFocus;
private boolean mUpdateInputWindowsNeeded = true;
private InputWindowHandle[] mInputWindowHandles;
private final Object mInputDevicesReadyMonitor = new Object();
private boolean mInputDevicesReady;
Rect mTmpRect = new Rect();
public InputMonitor(WindowManagerService service) {
mService = service;
}
public void updateInputWindowsLw(boolean force) {
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
// ...
// 加入到 mInputWindowHandles 數(shù)組中
if (child.mWinAnimator != universeBackground) {
addInputWindowHandleLw(inputWindowHandle, child, flags, privateFlags, type,
isVisible, hasFocus, hasWallpaper);
}
}
// 發(fā)送窗口到本地方法割按;
mService.mInputManager.setInputWindows(mInputWindowHandles);
// Clear the list in preparation for the next round.
clearInputWindowHandlesLw();
}
}
// InputServiceManager.java中:調(diào)用的是 native 方法膨报;
public void setInputWindows(InputWindowHandle[] windowHandles) {
nativeSetInputWindows(mPtr, windowHandles);
}
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp 中 nativeSetInputWindows() 方法:
// com_android_server_input_InputManagerService.cpp 中:
static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
jlong ptr, jobjectArray windowHandleObjArray) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
im->setInputWindows(env, windowHandleObjArray);
}
// com_android_server_input_InputManagerService.cpp 中:
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
// ...
// 調(diào)用InputDispatcher 中 setInputWindows()
mInputManager->getDispatcher()->setInputWindows(windowHandles);
// ...
}
// InputDispatcher.cpp 中的 setInputWindows():
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
{ // acquire lock
Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
// 把 inputWindowHandles 賦值給 mWindowHandles,這里就知道分發(fā)的目標(biāo)窗口是哪個(gè)窗口了;
// input 事件就是根據(jù)匹配 InputWindowHandle 來(lái)進(jìn)行分發(fā)的现柠;
mWindowHandles = inputWindowHandles;
}
// ... 一些窗口的更新等操作
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}