在开发者模式下,在开发者选项中,可以勾选“显示触摸操作”,然后只要点击屏幕就会在点击的位置有圈圈显示。如何找到绘制圈圈的代码部分,有什么技巧来阅读代码量这么大的android系统源码呢?以下请跟着小老弟我来一起分析吧。

1. android设置功能的代码是在packages/apps/Settings/里面的,所以在Settings中搜寻关键的字符串,

在源码目录下终端输入

grep -rn "显示触摸操作" ./packages/apps/Settings/

搜到如下:

./packages/apps/Settings/res/values-zh-rCN/strings.xml:: <string name="show_touches" msgid="">"显示触摸操作"</string>

熟悉android应用编程的话就应该知道代码中 show_touches 与“显示触摸操作”是相关联的。

2. 输入

grep -rn "show_touches" --include "*.java" ./packages/apps/Settings/

得到

./packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java:: private static final String SHOW_TOUCHES_KEY = "show_touches";

3. 开始阅读源码,打开 DevelopmentSettings.java 按以下阅读顺序,

private static final String SHOW_TOUCHES_KEY = "show_touches";
mShowTouches = findAndInitSwitchPref(SHOW_TOUCHES_KEY);
private void writeShowTouchesOptions() {
Settings.System.putInt(getActivity().getContentResolver(),
Settings.System.SHOW_TOUCHES, mShowTouches.isChecked() ? : );
}

猜测 putInt 应该是一个数据传递的功能, 所以在framework里面搜 SHOW_TOUCHES 看看情况如何,

输入

grep -rn "SHOW_TOUCHES" frameworks/

搜到好多,比如以下应该和数据处理注册相关,

frameworks/base/core/java/android/provider/Settings.java:: public static final String SHOW_TOUCHES = "show_touches";
frameworks/base/core/java/android/provider/Settings.java:: public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
frameworks/base/core/java/android/provider/Settings.java:: PRIVATE_SETTINGS.add(SHOW_TOUCHES);
frameworks/base/core/java/android/provider/Settings.java:: VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);

因为看不出有什么特殊操作,只是一些声明和 add 操作,所以忽略之。。。。。。

以下才是具体功能

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java:: Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,

4. 打开 InputManagerService.java 源码,

private void registerShowTouchesSettingObserver() {
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
updateShowTouchesFromSettings();
}
}, UserHandle.USER_ALL);
}

发现,关键方法 getContentResolver 刚好在DevelopmentSettings.java 中 putInt 里面的参数一致,所以可以肯定是走这里了。

接下来跟方法 updateShowTouchesFromSettings()

public void updateShowTouchesFromSettings() {
int setting = getShowTouchesSetting();
nativeSetShowTouches(mPtr, setting != );
}

看到 native 字样,说明会走到用 cpp 写的 JNI 接口里面。

3. 因为已经到 JNI 了,所以后续都只需看 cpp 文件了,输入

grep -rn "nativeSetShowTouches" --include "*.cpp" ./frameworks/ 

搜到

./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp::static void nativeSetShowTouches(JNIEnv* /* env */,

打开这份 com_android_server_input_InputManagerService.cpp 文件,

static void nativeSetShowTouches(JNIEnv* /* env */,
jclass /* clazz */, jlong ptr, jboolean enabled) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setShowTouches(enabled);
}

看看 setShowTouches 里面做了啥,

void NativeInputManager::setShowTouches(bool enabled) {
{ // acquire lock
AutoMutex _l(mLock); if (mLocked.showTouches == enabled) {
return;
} ALOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
mLocked.showTouches = enabled;
} // release lock mInputManager->getReader()->requestRefreshConfiguration(
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}

其中 mLocked.showTouches = enabled; 中 showTouches 是关键字,还有 CHANGE_SHOW_TOUCHES 也很关键。

4. 输入

 grep -rn "CHANGE_SHOW_TOUCHES" --include "*.cpp" ./frameworks/ 

搜到

./frameworks/native/services/inputflinger/InputReader.cpp:: | InputReaderConfiguration::CHANGE_SHOW_TOUCHES

打开 InputReader.cpp ,在 CHANGE_SHOW_TOUCHES 中看不出啥东西,太费力了。

这时可以在 InputReader.cpp 中搜 showTouches ,

输入

 grep -rn "showTouches" --include "*.cpp" ./frameworks/ 

搜到

./frameworks/native/services/inputflinger/InputReader.cpp:: (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
./frameworks/native/services/inputflinger/InputReader.cpp:: && mConfig.showTouches && mPointerController != NULL) {

如何把 CHANGE_SHOW_TOUCHES 与 showTouches 关联起来呢?在 InputReader.cpp 中,

if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
| InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
| InputReaderConfiguration::CHANGE_SHOW_TOUCHES
| InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
// Configure device sources, surface dimensions, orientation and
// scaling factors.
configureSurface(when, &resetNeeded);
}

进入configureSurface 发现以下关键代码

    // Create pointer controller if needed.
if (mDeviceMode == DEVICE_MODE_POINTER ||
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == NULL) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
}
} else {
mPointerController.clear();
}

这段注释耐人寻味 // Create pointer controller if needed.

所以可以肯定,后续就在 InputReader.cpp 里面围绕 showTouches 来搞事情,果然 showTouches 在另外一出显现它的重要,

        if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mCurrentCookedState.cookedPointerData.touchingIdBits);
}

学了多年的英语要发挥它的作用了,可知 setSpots 中 spots的中文意思为“斑点,小圆点”,所以就是走这里了,setSpots传的参数应该就和触摸坐标数据有关了。

5. 输入

grep -rn "setSpots" --include "*.cpp" ./frameworks/

搜到

./frameworks/base/libs/input/PointerController.cpp::void PointerController::setSpots(const PointerCoords* spotCoords,
./frameworks/base/libs/input/PointerController.cpp:: ALOGD("setSpots: idBits=%08x", spotIdBits.value);

打开 PointerController.cpp ,在函数 void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits)
中可知 spot->updateSprite(&icon, x, y); 与显示圈圈有关,大胆预测 icon 为显示的图形,x和y为显示的坐标。添加 ALOGI 打印,编译导入后发现,每次显示圈圈的时候,这里都会走。猜想变成真理!

6. 思考,icon 数据来自哪里, 怎么就能在android上显示呢?x,y数据又是怎么传入的呢?以后有空再一起探讨吧。

Android源码阅读技巧--查找开发者选项中显示触摸操作源码的更多相关文章

  1. JDK源码阅读-------自学笔记(一)(java.lang.Object重写toString源码)

    一.前景提要 Object类中定义有public String toString()方法,其返回值是 String 类型. 二.默认返回组成 类名+@+16进制的hashcode,当使用打印方法打印的 ...

  2. Apache Spark源码走读之23 -- Spark MLLib中拟牛顿法L-BFGS的源码实现

    欢迎转载,转载请注明出处,徽沪一郎. 概要 本文就拟牛顿法L-BFGS的由来做一个简要的回顾,然后就其在spark mllib中的实现进行源码走读. 拟牛顿法 数学原理 代码实现 L-BFGS算法中使 ...

  3. Android随笔之——用shell脚本模拟用户按键、触摸操作

    之前写过两篇关于Android中模拟用户操作的博客(其实用一篇是转载的),现在就来讲讲用shell脚本来模拟用户按键操作.本次的目标是用shell脚本打开微信并在其搜索框中搜索相关内容. 本文的模拟功 ...

  4. Android怎样改动app不在多任务列表中显示

    在实际开发中,我们希望某些activity或者应用程序不在多任务列表中显示,即长按Home键或者多任务button键不显示近期执行的程序,我们能够在对应应用程序的AndroidManifest.xml ...

  5. Android的缓存图片不在系统图库中显示的解决办法

    Android的图库会在开机的时候扫描SD卡中的图片,视频等文件,有很多App的私有图片不想在图库中显示,就需要另外处理了. 解决办法:在缓存图片的文件夹中创建 .nomedia 文件. 1. &qu ...

  6. Hadoop 源码阅读技巧

    http://www.cnblogs.com/xuxm2007/category/388607.html     个人谈谈阅读hadoop源代码的经验.首先,不得不说,hadoop发展到现在这个阶段, ...

  7. linux 小技巧(查找替换文件中的ascii编码字符)

    这里纪录一些linux下用到的小技巧,以免遗忘 在linux中经常碰见各种文件处理.最常用的就是替换文件中的某些字符.常见字符替换还是很容易完成.但是有些不可见字符以及ascii编码字符等等都无法直接 ...

  8. jQuery中使用 .html() function在IE8和9中显示不正常源码中多出sizset和sizcache

    错误原因:在引入jquery的时候,使用了html function,在IE8和IE9下面有可能会出现不兼容 解决办法:在html头部加一句 <meta http-equiv="X-U ...

  9. Android 使用pl.droidsonroids.gif.GifImageView在安卓中显示动图遇到的问题

    在做一款聊天软件,其中聊天界面需要发送表情,而表情都是动图,在安卓中想要显示动图,就要借助第三方框架,我选的是pl.droidsonroids.gif.GifImageView. 使用方法如下:你在g ...

随机推荐

  1. 【游记】NOIP2018初赛

    声明 本文最初的版本创建之时,本人甚至只是个电脑的小白,因而不太会用电脑编辑文字,最初的版本写在一个Word文档里,被随意的丢弃在我杂乱无比的网盘的某一个角落,直到我决定整理自己的成长历程,将散落的游 ...

  2. Tunnel Warfare HDU - 1540 (线段树不同子树的合并)

    在抗日战争期间,华北平原广大地区进行了大规模的隧道战. 一般来说,通过隧道连接的村庄排成一列. 除了两端,每个村庄都与两个相邻的村庄直接相连. 入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道. 八路 ...

  3. Java——类型信息

    1.Class对象 Class对象是一个特殊的对象,它包含了与类有关的信息.Class对象就是用来创建类的所有常规对象的. 类是程序的一部分,每个类都有一个Class对象,每当编写并且编译一个新类,就 ...

  4. kpm字符串匹配算法

    首先是简单的朴素匹配算法 /* * 返回子串t在主串s的位置,若不存在则返回0 */ public static int index(String s, String t) { int i = 0;/ ...

  5. 【POJ - 3280】Cheapest Palindrome(区间dp)

    Cheapest Palindrome 直接翻译了 Descriptions 给定一个字符串S,字符串S的长度为M(M≤2000),字符串S所含有的字符的种类的数量为N(N≤26),然后给定这N种字符 ...

  6. javaScript基础-0 javascript概述

    一.简介 javaScript一种面向web的编程语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早 ...

  7. java高并发系列 - 第27天:实战篇,接口性能成倍提升,让同事刮目相看,现学现用

    这是java高并发系列第27篇文章. 开发环境:jdk1.8. 案例讲解 电商app都有用过吧,商品详情页,需要给他们提供一个接口获取商品相关信息: 商品基本信息(名称.价格.库存.会员价格等) 商品 ...

  8. 纯数据结构Java实现(2/11)(栈与队列)

    栈和队列的应用非常多,但是起实现嘛,其实很少人关心. 但问题是,虽然苹果一直宣传什么最小年龄的编程者,它试图把编程大众化,弱智化,但真正的复杂问题,需要抽丝剥茧的时候,还是要 PRO 人士出场,所以知 ...

  9. 数据库系统原理之SQL(三)

    数据库系统原理之SQL(三) 1. SQL的组成 1. 数据查询 2. 数据定义 3. 数据操作 4. 数据控制 2. 数据定义语言 CREATE创建数据库或数据库对象 创建数据库 ~~~ CREAT ...

  10. Docker系列之AspNetCore Runtime VS .NetCore Runtime VS .NET Core SDK(四)

    前言 接下来我们就要慢慢步入在.NET Core中使用Docker的殿堂了,在开始之前如题,我们需要搞清楚一些概念,要不然看到官方提供如下一系列镜像,我们会一脸懵逼,不知道到底要使用哪一个. AspN ...