日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android中的add方法,Android入门之addWindow

發布時間:2023/12/1 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android中的add方法,Android入门之addWindow 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面說到,應用程序添加窗口時,會在本地創建一個ViewRoot,然后通過IPC(進程間通信)調用WmS的Session的addWindow請求WmS創建窗口,下面來看看addWindow方法。

addWindow方法定義在frameworks/base/services/java/com.android.server.WindowManagerService.java中,其代碼如下所示:

public int addWindow(Session session, IWindow client,

WindowManager.LayoutParams attrs, int viewVisibility,

Rect outContentInsets, InputChannel outInputChannel) {

// 是否有添加權限

int res = mPolicy.checkAddPermission(attrs);

if (res != WindowManagerImpl.ADD_OKAY) {

return res;

}

boolean reportNewConfig = false;

WindowState attachedWindow = null;

WindowState win = null;

synchronized(mWindowMap) {

// Instantiating a Display requires talking with the simulator,

// so don't do it until we know the system is mostly up and

// running.

// 是否存在顯示設置

if (mDisplay == null) {

// 若不存在,則獲取系統設置

WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

mDisplay = wm.getDefaultDisplay();

mInitialDisplayWidth = mDisplay.getWidth();

mInitialDisplayHeight = mDisplay.getHeight();

// 將Display存放到InputManager中

mInputManager.setDisplaySize(0, mInitialDisplayWidth, mInitialDisplayHeight);

reportNewConfig = true;

}

// 是否重復添加

if (mWindowMap.containsKey(client.asBinder())) {

Slog.w(TAG, "Window " + client + " is already added");

return WindowManagerImpl.ADD_DUPLICATE_ADD;

}

// 是否子窗口

if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {

// 若為子窗口

// 返回WmS中存在的對應父窗口,若不存在則返回null

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 WindowManagerImpl.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 WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;

}

}

boolean addToken = false;

// 在WmS中尋找對應的WindowToken

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

if (token == null) {

if (attrs.type >= FIRST_APPLICATION_WINDOW

&& attrs.type <= LAST_APPLICATION_WINDOW) {

// 對于子窗口來說,WmS中必須有對應的Token才能添加

Slog.w(TAG, "Attempted to add application window with unknown token "

+ attrs.token + ". Aborting.");

return WindowManagerImpl.ADD_BAD_APP_TOKEN;

}

if (attrs.type == TYPE_INPUT_METHOD) {

// 如果是內置的輸入方法窗口,WmS中必須有對應的Token才能添加

Slog.w(TAG, "Attempted to add input method window with unknown token "

+ attrs.token + ". Aborting.");

return WindowManagerImpl.ADD_BAD_APP_TOKEN;

}

if (attrs.type == TYPE_WALLPAPER) {

// 墻紙窗口,WmS中必須有對應的Token才能添加

Slog.w(TAG, "Attempted to add wallpaper window with unknown token "

+ attrs.token + ". Aborting.");

return WindowManagerImpl.ADD_BAD_APP_TOKEN;

}

// 創建窗口

token = new WindowToken(attrs.token, -1, false);

addToken = true;

} else if (attrs.type >= FIRST_APPLICATION_WINDOW

&& attrs.type <= LAST_APPLICATION_WINDOW) {

// token不為null且是應用窗口

AppWindowToken atoken = token.appWindowToken;

if (atoken == null) {

// appWindowToken值不能為空

Slog.w(TAG, "Attempted to add window with non-application token "

+ token + ". Aborting.");

return WindowManagerImpl.ADD_NOT_APP_TOKEN;

} else if (atoken.removed) {

// 試圖使用存在的應用token添加窗口

Slog.w(TAG, "Attempted to add window with exiting application token "

+ token + ". Aborting.");

return WindowManagerImpl.ADD_APP_EXITING;

}

if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {

// No need for this guy!

// 窗口類型不能是應用啟動時顯示的窗口

if (localLOGV) Slog.v(

TAG, "**** NO NEED TO START: " + attrs.getTitle());

return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;

}

} else if (attrs.type == TYPE_INPUT_METHOD) {

// 對于內置的輸入方法窗口,token的windowType值要等于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 WindowManagerImpl.ADD_BAD_APP_TOKEN;

}

} else if (attrs.type == TYPE_WALLPAPER) {

// 對于墻紙窗口,token的windowType值要等于TYPE_WALLPAPER

if (token.windowType != TYPE_WALLPAPER) {

Slog.w(TAG, "Attempted to add wallpaper window with bad token "

+ attrs.token + ". Aborting.");

return WindowManagerImpl.ADD_BAD_APP_TOKEN;

}

}

// 創建窗口

win = new WindowState(session, client, token,

attachedWindow, attrs, viewVisibility);

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 WindowManagerImpl.ADD_APP_EXITING;

}

// 如果是Toast,則此窗口不能夠接收input事件

mPolicy.adjustWindowParamsLw(win.mAttrs);

// 判斷添加的窗口是單例還是多例

res = mPolicy.prepareAddWindowLw(win, attrs);

if (res != WindowManagerImpl.ADD_OKAY) {

// 是多例則直接返回

return res;

}

// 如果輸出的Channel,也即Pipe中的讀通道為空

if (outInputChannel != null) {

// 創建通道

String name = win.makeInputChannelName();

InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

win.mInputChannel = inputChannels[0];

inputChannels[1].transferToBinderOutParameter(outInputChannel);

// 在InputManager中注冊通道

mInputManager.registerInputChannel(win.mInputChannel);

}

// From now on, no exceptions or errors allowed!

res = WindowManagerImpl.ADD_OKAY;

// 重置當前線程的IPC的ID

final long origId = Binder.clearCallingIdentity();

// 從上述代碼中得出是否要添加Token,若是則添加Token添加到WmS中

if (addToken) {

mTokenMap.put(attrs.token, token);

mTokenList.add(token);

}

// 將窗口添加到Session中

win.attach();

// 窗口信息添加到WmS中

mWindowMap.put(client.asBinder(), win);

if (attrs.type == TYPE_APPLICATION_STARTING &&

token.appWindowToken != null) {

// 對于應用啟動時顯示的窗口,設置token

token.appWindowToken.startingWindow = win;

}

boolean imMayMove = true;

if (attrs.type == TYPE_INPUT_METHOD) {

// 內置的輸入方法窗口

mInputMethodWindow = win;

addInputMethodWindowToListLocked(win);

imMayMove = false;

} else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {

// 內置的輸入方法對話框窗口

mInputMethodDialogs.add(win);

addWindowToListInOrderLocked(win, true);

adjustInputMethodDialogsLocked();

imMayMove = false;

} else {

// 其他窗口

addWindowToListInOrderLocked(win, true);

if (attrs.type == TYPE_WALLPAPER) {

mLastWallpaperTimeoutTime = 0;

adjustWallpaperWindowsLocked();

} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {

adjustWallpaperWindowsLocked();

}

}

win.mEnterAnimationPending = true;

// 獲取系統窗口區域的insets

mPolicy.getContentInsetHintLw(attrs, outContentInsets);

if (mInTouchMode) {

// 用戶直接觸摸的窗口

res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;

}

if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {

// 應用窗口

res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;

}

boolean focusChanged = false;

if (win.canReceiveKeys()) {

// 窗口需要按鍵事件

// 更新焦點,將窗口信息寫入了InputDispatcher

focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS);

if (focusChanged) {

imMayMove = false;

}

}

if (imMayMove) {

// 若需要鎖定的話,移動輸入方法窗口

moveInputMethodWindowsIfNeededLocked(false);

}

assignLayersLocked();

// Don't do layout here, the window must call

// relayout to be displayed, so we'll do it there.

//dump();

if (focusChanged) {

finishUpdateFocusedWindowAfterAssignLayersLocked();

}

if (localLOGV) Slog.v(

TAG, "New client " + client.asBinder()

+ ": window=" + win);

if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {

reportNewConfig = true;

}

}

// sendNewConfiguration() checks caller permissions so we must call it with

// privilege. updateOrientationFromAppTokens() clears and resets the caller

// identity anyway, so it's safe to just clear & restore around this whole

// block.

final long origId = Binder.clearCallingIdentity();

if (reportNewConfig) {

sendNewConfiguration();

}

Binder.restoreCallingIdentity(origId);

return res;

}

有些東西還沒摸明白,后面深入學習后再補一下。

上文還說到,addWindow會將窗口信息寫入InputDispatcher,其實在addWindow代碼中有體現:

if (win.canReceiveKeys()) {

// 窗口需要按鍵事件

// 更新焦點,在這里,將窗口信息寫入了InputDispatcher

focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS);

if (focusChanged) {

imMayMove = false;

}

} ? ? ? ? 至于如何寫入InputDispatcher,下文分析。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的android中的add方法,Android入门之addWindow的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。