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,下文分析。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370108.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370108.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370108.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSS屬性速查表

前面的話 本文將按照布局類屬性、盒模型屬性、文本類屬性、修飾類屬性這四個分類&#xff0c;對CSS常用屬性進行重新排列&#xff0c;并最終設置為一份stylelintrc文件 布局類 1、定位 positionz-indextopbottomleftright 2、浮動 floatclear 3、多列布局 columnscolumns-width…

我應該使用32位還是64位JVM?

這是我在企業軟件開發生涯中多次遇到的問題。 我不得不每隔一段時間就提供有關配置特定新環境的建議。 而且&#xff0c;很多時候&#xff0c;手頭的問題與“我應該使用32位或64位JVM”有關。 老實說&#xff0c;一開始我只是擲硬幣。 而不是給出合理的答案。 &#xff08;對不…

python安裝pyecharts清華_基于Python安裝pyecharts所遇的問題及解決方法

最近學習到數據可視化內容&#xff0c;老師推薦安裝pyecharts&#xff0c;于是pip install 了一下&#xff0c;結果...掉坑了&#xff0c;下面是我的跳坑經驗&#xff0c;如果你有類似問題&#xff0c;希望對你有所幫助。第一個坑:這個不難理解&#xff0c;缺少pyecharts-jupyt…

C語言內存分配

C語言內存分配 C語言的內存分配主要有5個區域&#xff1a; 1、棧區&#xff1a;在運行函數時&#xff0c;函數內的局部變量&#xff08;不包含static變量&#xff09;、函數返回值的存儲單元在棧區上創建。函數運行結束時這些存儲單元自己主動被釋放。棧區內存分配運算內置于處…

在Ajax方式產生的浮動框中,點擊選項包含某個關鍵字的選項

#!usr/bin/env python #-*- coding:utf-8 -*- """ author: sleeping_cat Contact : zwy24zwy163.com """ #在Ajax方式產生的浮動框中&#xff0c;點擊選項包含某個關鍵字的選項 #通過模擬鍵盤下箭頭進行選擇懸浮框選項from selenium imp…

android studio點擊圖片,如何在Android Studio中的模擬器圖庫中添加圖像?

如何在Android Studio中的模擬器圖庫中添加圖像&#xff1f;我正在開發圖像過濾器應用程序。 但是&#xff0c;如果我沒有任何圖像&#xff0c;就無法真正嘗試。我知道我可以在電話中對其進行測試&#xff0c;但這并不相同&#xff0c;因為我需要錯誤消息和其他內容。我只想從A…

移動端學習目錄

前面的話 iphone4發布是幾年前的事情&#xff0c;而如今早已是移動互聯網的時代。人們不再正襟危坐在電腦前&#xff0c;而更愿意把時間耗費在手機上&#xff0c;隨時隨地地享受互聯網。在移動端可以使用最新最炫的前端技術&#xff0c;而不用再考慮老版本IE的兼容性。當前&…

實踐中的構建者模式

我將不深入討論該模式&#xff0c;因為已經有大量的帖子和書籍對此進行了詳細的解釋。 相反&#xff0c;我將告訴您為什么以及何時應該考慮使用它。 但是&#xff0c;值得一提的是&#xff0c;這種模式與《 四人幫》一書中介紹的模式有些不同。 雖然原始模式著重于抽象化構造步…

python計算汽車的平均油耗_用python對汽車油耗進行數據分析

原標題&#xff1a;用python對汽車油耗進行數據分析- 從http://fueleconomy.gov/geg/epadata/vehicles.csv.zip下載汽車油耗數據集并解壓- 進入jupyter notebook(ipython notebook)并新建一個New Notebook- 輸入命令[python]view plaincopyimportpandas as pdimportnumpy as np…

git常用命令2

##一、git常用命令 ###1、 push文件 * 打開cmd窗口 * 輸入f:&#xff0c;進入f:&#xff08;自己隨便在自己的電腦上找個位置就行了&#xff0c;這里的f:&#xff0c;表示的是f盤&#xff09; * 然后輸入mkdir workSpace&#xff0c;會自動在f盤下生成一個workSpace文件夾 * 然…

android移動應用基礎教程源代碼,Android移動應用基礎教程 【程序活動單元Activity】...

本章目錄一、Activity的生命周期1、生命周期狀態2 、生命周期方法3、橫豎屏切換時的生命周期二、Activity的創建配置和關閉1、Activity的創建2、配置Activity3、開啟和關閉Activity三、Intent與IntentFilter1、Intent介紹1.1 意圖的概念1.2 顯式意圖1.3 隱式意圖2、IntentFilte…

elasticsearch中cluster和transport知識

elasticsearch cluster 概述 elasticsearch節點間通信的基礎transport轉載于:https://www.cnblogs.com/wzj4858/p/8126033.html

Python中使用subplot在一張畫布上顯示多張圖

subplot(arg1, arg2, arg3) arg1: 在垂直方向同時畫幾張圖arg2: 在水平方向同時畫幾張圖arg3: 當前命令修改的是第幾張圖 t np.arange(0,5,0.1) y1 np.sin(2*np.pi*t) y2 np.sin(2*np.pi*t) plt.subplot(211) plt.plot(t,y1,b-.) plt.subplot(212) plt.plot(t,y2,r--) plt.s…

Java 8:從PermGen到元空間

您可能已經知道&#xff0c;現在可以下載JDK 8 Early Access 。 這使Java開發人員可以嘗試Java 8的一些新語言和運行時功能。這些功能之一是完全刪除自Oracle自JDK 7發行以來就宣布的Permanent Generation&#xff08;PermGen&#xff09;空間。例如&#xff0c;自JDK 7起&…

oracle symonym_ORACLE SYNONYM詳解

以下內容整理自Oracle 官方文檔一 概念A synonym is an alias for any table, view,materialized view, sequence, procedure, function, package, type, Java classschema object, user-defined object type, or another synonym. Because a synonymis simply an alias, it re…

瀏覽器緩存問題原理以及解決方案

瀏覽器緩存問題&#xff1a; 簡單來說&#xff0c;瀏覽器緩存就是把一個已經請求過的Web資源&#xff08;如html頁面&#xff0c;圖片&#xff0c;js&#xff0c;數據等&#xff09;拷貝一份副本儲存在瀏覽器中。緩存會根據進來的請求保存輸出內容的副本。當下一個請求來到的時…

Scikit-Learn機器學習入門

現在最常用的數據分析的編程語言為R和Python。每種語言都有自己的特點&#xff0c;Python因為Scikit-Learn庫贏得了優勢。Scikit-Learn有完整的文檔&#xff0c;并實現很多機器學習算法&#xff0c;而每種算法使用的接口幾乎相同&#xff0c;可以非常快的測試其它學習算法。 Pa…

hdu1542 Atlantis(掃描線+線段樹+離散)矩形相交面積

題目鏈接&#xff1a;點擊打開鏈接 題目描寫敘述&#xff1a;給定一些矩形&#xff0c;求這些矩形的總面積。假設有重疊。僅僅算一次 解題思路&#xff1a;掃描線線段樹離散&#xff08;代碼從上往下掃描&#xff09; 代碼&#xff1a; #include<cstdio> #include <al…

瀏覽器滾動條 --- 自定義“衣裳”

由于種種原因&#xff0c;瀏覽器的默認滾動條“衣裳”實在是 (ˉ▽&#xffe3;&#xff5e;)~~&#xff0c;為了“美”&#xff0c;本人結合萬維網各大神給的經驗和自己的實踐&#xff0c;做了此篇總結。若有錯誤&#xff0c;請在評論里給出&#xff0c;我會及時更改。 我在電…

電腦調分辨率黑屏了怎么辦_調顯示器分辨率黑屏怎么辦

調顯示器分辨率黑屏怎么辦調顯示器分辨率黑屏解決方法&#xff1a;1&#xff0c;開機&#xff0c;當快要進入系統選項時&#xff0c;立即按f8鍵進入“高級模式”&#xff0c;因為系統選項界面顯示的時間非常短&#xff0c;可以提早按f8鍵&#xff0c;否則錯過時機就得重來。2&a…