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.mzph.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…