Android源碼閱讀技巧--查找開發者選項中顯示觸摸操作源碼


    在開發者模式下,在開發者選項中,可以勾選“顯示觸摸操作”,然后只要點擊屏幕就會在點擊的位置有圈圈顯示。如何找到繪制圈圈的代碼部分,有什么技巧來閱讀代碼量這么大的android系統源碼呢?以下請跟着小老弟我來一起分析吧。

 

    1. android設置功能的代碼是在packages/apps/Settings/里面的,所以在Settings中搜尋關鍵的字符串,

在源碼目錄下終端輸入

grep -rn "顯示觸摸操作" ./packages/apps/Settings/

    搜到如下:

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

    熟悉android應用編程的話就應該知道代碼中 show_touches 與“顯示觸摸操作”是相關聯的。


    2. 輸入 

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

    得到

./packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java:128: 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() ? 1 : 0);
}

    猜測 putInt 應該是一個數據傳遞的功能, 所以在framework里面搜 SHOW_TOUCHES 看看情況如何,

    輸入

grep -rn "SHOW_TOUCHES" frameworks/

    搜到好多,比如以下應該和數據處理注冊相關,

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

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

以下才是具體功能

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java:1600: 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(0);
    nativeSetShowTouches(mPtr, setting != 0);
}

    看到 native 字樣,說明會走到用 cpp 寫的 JNI 接口里面。

 

    3. 因為已經到 JNI 了,所以后續都只需看 cpp 文件了,輸入

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

    搜到

./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp:1310: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:3177: | InputReaderConfiguration::CHANGE_SHOW_TOUCHES

    打開 InputReader.cpp ,在 CHANGE_SHOW_TOUCHES 中看不出啥東西,太費力了。

這時可以在 InputReader.cpp 中搜 showTouches ,

    輸入

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

    搜到

./frameworks/native/services/inputflinger/InputReader.cpp:3476: (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
./frameworks/native/services/inputflinger/InputReader.cpp:4334: && 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:246:void PointerController::setSpots(const PointerCoords* spotCoords,
./frameworks/base/libs/input/PointerController.cpp:249: 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數據又是怎么傳入的呢?以后有空再一起探討吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM