人生不过一场醉 發表於 2019-9-11 11:18:00

Android源码阅读技巧--查找开发者选项中显示触摸操作源码

<p>&nbsp; &nbsp; 在开发者模式下,在开发者选项中,可以勾选“显示触摸操作”,然后只要点击屏幕就会在点击的位置有圈圈显示。如何找到绘制圈圈的代码部分,有什么技巧来阅读代码量这么大的android系统源码呢?以下请跟着小老弟我来一起分析吧。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 1. android设置功能的代码是在packages/apps/Settings/里面的,所以在Settings中搜寻关键的字符串,</p>
<p>在源码目录下终端输入</p>
<div class="cnblogs_code">
<pre>grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">显示触摸操作</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./packages/apps/Settings/</pre>
</div>
<p>&nbsp; &nbsp; 搜到如下:</p>
<div class="cnblogs_code">
<pre>./packages/apps/Settings/res/values-zh-rCN/strings.xml:<span style="color: rgba(128, 0, 128, 1)">2108</span>: &lt;<span style="color: rgba(0, 0, 255, 1)">string</span> name=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">show_touches</span><span style="color: rgba(128, 0, 0, 1)">"</span> msgid=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1356420386500834339</span><span style="color: rgba(128, 0, 0, 1)">"</span>&gt;<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">显示触摸操作</span><span style="color: rgba(128, 0, 0, 1)">"</span>&lt;/<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;</pre>
</div>
<p>&nbsp; &nbsp; 熟悉android应用编程的话就应该知道代码中 show_touches 与“显示触摸操作”是相关联的。</p>
<p><br>&nbsp; &nbsp; 2. 输入&nbsp;</p>
<div class="cnblogs_code">
<pre>grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">show_touches</span><span style="color: rgba(128, 0, 0, 1)">"</span> --include <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*.java</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./packages/apps/Settings/</pre>
</div>
<p>&nbsp; &nbsp; 得到</p>
<div class="cnblogs_code">
<pre>./packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java:<span style="color: rgba(128, 0, 128, 1)">128</span>: <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> final String SHOW_TOUCHES_KEY = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">show_touches</span><span style="color: rgba(128, 0, 0, 1)">"</span>;</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 3. 开始阅读源码,打开 DevelopmentSettings.java 按以下阅读顺序,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> final String SHOW_TOUCHES_KEY = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">show_touches</span><span style="color: rgba(128, 0, 0, 1)">"</span>;</pre>
</div>
<div class="cnblogs_code">
<pre>mShowTouches = findAndInitSwitchPref(SHOW_TOUCHES_KEY);</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> writeShowTouchesOptions() {
    Settings.System.putInt(getActivity().getContentResolver(),
            Settings.System.SHOW_TOUCHES, mShowTouches.isChecked() </span>? <span style="color: rgba(128, 0, 128, 1)">1</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>&nbsp; &nbsp; 猜测 putInt 应该是一个数据传递的功能, 所以在framework里面搜 SHOW_TOUCHES 看看情况如何,</p>
<p>&nbsp; &nbsp; 输入</p>
<div class="cnblogs_code">
<pre>grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SHOW_TOUCHES</span><span style="color: rgba(128, 0, 0, 1)">"</span> frameworks/</pre>
</div>
<p>&nbsp; &nbsp; 搜到好多,比如以下应该和数据处理注册相关,</p>
<div class="cnblogs_code">
<pre>frameworks/<span style="color: rgba(0, 0, 255, 1)">base</span>/core/java/android/provider/Settings.java:<span style="color: rgba(128, 0, 128, 1)">3094</span>: <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> final String SHOW_TOUCHES = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">show_touches</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
frameworks</span>/<span style="color: rgba(0, 0, 255, 1)">base</span>/core/java/android/provider/Settings.java:<span style="color: rgba(128, 0, 128, 1)">3097</span>: <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> final Validator SHOW_TOUCHES_VALIDATOR =<span style="color: rgba(0, 0, 0, 1)"> sBooleanValidator;
frameworks</span>/<span style="color: rgba(0, 0, 255, 1)">base</span>/core/java/android/provider/Settings.java:<span style="color: rgba(128, 0, 128, 1)">3439</span><span style="color: rgba(0, 0, 0, 1)">: PRIVATE_SETTINGS.add(SHOW_TOUCHES);
frameworks</span>/<span style="color: rgba(0, 0, 255, 1)">base</span>/core/java/android/provider/Settings.java:<span style="color: rgba(128, 0, 128, 1)">3519</span>: VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);</pre>
</div>
<p>&nbsp; &nbsp; 因为看不出有什么特殊操作,只是一些声明和 add 操作,所以忽略之。。。。。。</p>
<p>以下才是具体功能</p>
<div class="cnblogs_code">
<pre>frameworks/<span style="color: rgba(0, 0, 255, 1)">base</span>/services/core/java/com/android/server/input/InputManagerService.java:<span style="color: rgba(128, 0, 128, 1)">1600</span>: Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), <span style="color: rgba(0, 0, 255, 1)">true</span>,</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 4. 打开 InputManagerService.java 源码,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> registerShowTouchesSettingObserver() {
    mContext.getContentResolver().registerContentObserver(
            Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ContentObserver(mHandler) {
                @Override
                </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onChange(boolean selfChange) {
                  updateShowTouchesFromSettings();
                }
            }, UserHandle.USER_ALL);
}</span></pre>
</div>
<p>&nbsp; &nbsp; 发现,关键方法 getContentResolver 刚好在DevelopmentSettings.java 中 putInt 里面的参数一致,所以可以肯定是走这里了。</p>
<p>&nbsp; &nbsp; 接下来跟方法 updateShowTouchesFromSettings()</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateShowTouchesFromSettings() {
    </span><span style="color: rgba(0, 0, 255, 1)">int</span> setting = getShowTouchesSetting(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);
    nativeSetShowTouches(mPtr, setting </span>!= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>&nbsp; &nbsp; 看到 native 字样,说明会走到用 cpp 写的 JNI 接口里面。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 3. 因为已经到 JNI 了,所以后续都只需看 cpp 文件了,输入</p>
<div class="cnblogs_code">
<pre>grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">nativeSetShowTouches</span><span style="color: rgba(128, 0, 0, 1)">"</span> --include <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*.cpp</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./frameworks/ </pre>
</div>
<p>&nbsp; &nbsp; 搜到</p>
<div class="cnblogs_code">
<pre>./frameworks/<span style="color: rgba(0, 0, 255, 1)">base</span>/services/core/jni/com_android_server_input_InputManagerService.cpp:<span style="color: rgba(128, 0, 128, 1)">1310</span>:<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> nativeSetShowTouches(JNIEnv* <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> env </span><span style="color: rgba(0, 128, 0, 1)">*/</span>,</pre>
</div>
<p>&nbsp; &nbsp;打开这份 com_android_server_input_InputManagerService.cpp 文件,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> nativeSetShowTouches(JNIEnv* <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> env </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">,
      jclass </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> clazz </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">, jlong ptr, jboolean enabled) {
    NativeInputManager</span>* im = reinterpret_cast&lt;NativeInputManager*&gt;<span style="color: rgba(0, 0, 0, 1)">(ptr);

    im</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">setShowTouches(enabled);
}</span></pre>
</div>
<p>&nbsp; &nbsp; 看看 setShowTouches 里面做了啥,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">void</span> NativeInputManager::setShowTouches(<span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> enabled) {
    { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> acquire lock</span>
<span style="color: rgba(0, 0, 0, 1)">      AutoMutex _l(mLock);

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (mLocked.showTouches ==<span style="color: rgba(0, 0, 0, 1)"> enabled) {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
      }

      ALOGI(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Setting show touches feature to %s.</span><span style="color: rgba(128, 0, 0, 1)">"</span>, enabled ? <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">enabled</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">disabled</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      mLocked.showTouches </span>=<span style="color: rgba(0, 0, 0, 1)"> enabled;
    } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> release lock</span>
<span style="color: rgba(0, 0, 0, 1)">
    mInputManager</span>-&gt;getReader()-&gt;<span style="color: rgba(0, 0, 0, 1)">requestRefreshConfiguration(
            InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}</span></pre>
</div>
<p>&nbsp; &nbsp; 其中 mLocked.showTouches = enabled; 中 showTouches 是关键字,还有 CHANGE_SHOW_TOUCHES 也很关键。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 4. 输入</p>
<div class="cnblogs_code">
<pre> grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">CHANGE_SHOW_TOUCHES</span><span style="color: rgba(128, 0, 0, 1)">"</span> --include <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*.cpp</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./frameworks/ </pre>
</div>
<p>&nbsp; &nbsp; 搜到</p>
<div class="cnblogs_code">
<pre>./frameworks/native/services/inputflinger/InputReader.cpp:<span style="color: rgba(128, 0, 128, 1)">3177</span>: | InputReaderConfiguration::CHANGE_SHOW_TOUCHES</pre>
</div>
<p>&nbsp; &nbsp; 打开&nbsp;InputReader.cpp ,在 CHANGE_SHOW_TOUCHES 中看不出啥东西,太费力了。</p>
<p>这时可以在&nbsp;InputReader.cpp 中搜 showTouches ,</p>
<p>&nbsp; &nbsp; 输入</p>
<div class="cnblogs_code">
<pre> grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">showTouches</span><span style="color: rgba(128, 0, 0, 1)">"</span> --include <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*.cpp</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./frameworks/ </pre>
</div>
<p>&nbsp; &nbsp; 搜到</p>
<div class="cnblogs_code">
<pre>./frameworks/native/services/inputflinger/InputReader.cpp:<span style="color: rgba(128, 0, 128, 1)">3476</span>: (mDeviceMode == DEVICE_MODE_DIRECT &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> mConfig.showTouches)) {
.</span>/frameworks/native/services/inputflinger/InputReader.cpp:<span style="color: rgba(128, 0, 128, 1)">4334</span>: &amp;&amp; mConfig.showTouches &amp;&amp; mPointerController != NULL) {</pre>
</div>
<p>&nbsp; &nbsp; 如何把 CHANGE_SHOW_TOUCHES 与 showTouches 关联起来呢?在 InputReader.cpp 中,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span> (!changes || (changes &amp;<span style="color: rgba(0, 0, 0, 1)"> (InputReaderConfiguration::CHANGE_DISPLAY_INFO
      </span>|<span style="color: rgba(0, 0, 0, 1)"> InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
      </span>|<span style="color: rgba(0, 0, 0, 1)"> InputReaderConfiguration::CHANGE_SHOW_TOUCHES
      </span>|<span style="color: rgba(0, 0, 0, 1)"> InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Configure device sources, surface dimensions, orientation and
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> scaling factors.</span>
    configureSurface(when, &amp;<span style="color: rgba(0, 0, 0, 1)">resetNeeded);
}</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 进入configureSurface 发现以下关键代码</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Create pointer controller if needed.</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (mDeviceMode == DEVICE_MODE_POINTER ||<span style="color: rgba(0, 0, 0, 1)">
            (mDeviceMode </span>== DEVICE_MODE_DIRECT &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> mConfig.showTouches)) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (mPointerController ==<span style="color: rgba(0, 0, 0, 1)"> NULL) {
            mPointerController </span>= getPolicy()-&gt;<span style="color: rgba(0, 0, 0, 1)">obtainPointerController(getDeviceId());
      }
    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      mPointerController.clear();
    }</span></pre>
</div>
<p>&nbsp; &nbsp; 这段注释耐人寻味 // Create pointer controller if needed.</p>
<p>所以可以肯定,后续就在 InputReader.cpp 里面围绕 showTouches 来搞事情,果然&nbsp;showTouches 在另外一出显现它的重要,</p>
<div class="cnblogs_code">
<pre>      <span style="color: rgba(0, 0, 255, 1)">if</span> (mDeviceMode ==<span style="color: rgba(0, 0, 0, 1)"> DEVICE_MODE_DIRECT
                </span>&amp;&amp; mConfig.showTouches &amp;&amp; mPointerController !=<span style="color: rgba(0, 0, 0, 1)"> NULL) {
            mPointerController</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
            mPointerController</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">fade(PointerControllerInterface::TRANSITION_GRADUAL);

            mPointerController</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">setButtonState(mCurrentRawState.buttonState);
            mPointerController</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
                  mCurrentCookedState.cookedPointerData.idToIndex,
                  mCurrentCookedState.cookedPointerData.touchingIdBits);
      }</span></pre>
</div>
<p>&nbsp; &nbsp; 学了多年的英语要发挥它的作用了,可知 setSpots 中 spots的中文意思为“斑点,小圆点”,所以就是走这里了,setSpots传的参数应该就和触摸坐标数据有关了。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 5. 输入</p>
<div class="cnblogs_code">
<pre>grep -rn <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">setSpots</span><span style="color: rgba(128, 0, 0, 1)">"</span> --include <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*.cpp</span><span style="color: rgba(128, 0, 0, 1)">"</span> ./frameworks/</pre>
</div>
<p>&nbsp; &nbsp; 搜到</p>
<div class="cnblogs_code">
<pre>./frameworks/<span style="color: rgba(0, 0, 255, 1)">base</span>/libs/input/PointerController.cpp:<span style="color: rgba(128, 0, 128, 1)">246</span>:<span style="color: rgba(0, 0, 255, 1)">void</span> PointerController::setSpots(<span style="color: rgba(0, 0, 255, 1)">const</span> PointerCoords*<span style="color: rgba(0, 0, 0, 1)"> spotCoords,
.</span>/frameworks/<span style="color: rgba(0, 0, 255, 1)">base</span>/libs/input/PointerController.cpp:<span style="color: rgba(128, 0, 128, 1)">249</span>: ALOGD(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">setSpots: idBits=%08x</span><span style="color: rgba(128, 0, 0, 1)">"</span>, spotIdBits.value);</pre>
</div>
<p>&nbsp; &nbsp; 打开 PointerController.cpp ,在函数 void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits)<br>中可知 spot-&gt;updateSprite(&amp;icon, x, y); 与显示圈圈有关,大胆预测&nbsp;icon 为显示的图形,x和y为显示的坐标。添加 ALOGI 打印,编译导入后发现,每次显示圈圈的时候,这里都会走。猜想变成真理!<br><br></p>
<p>&nbsp; &nbsp; 6.&nbsp;思考,icon 数据来自哪里, 怎么就能在android上显示呢?x,y数据又是怎么传入的呢?以后有空再一起探讨吧。</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/songsongman/p/11504744.html
頁: [1]
查看完整版本: Android源码阅读技巧--查找开发者选项中显示触摸操作源码