最近大半個月一直在折騰Firefly-RK3399開發板實現雙屏異顯和異觸的功能。在這裏不得不吐槽一下螢火蟲的售後服務支持!額???所謂的官方羣和論壇形同擺設,在裏面10我的的問題中有一我的能獲得回答就是不錯了。本身可以實現雙屏異觸要感謝公司、經理和公司同事,給予了不少幫助和支持才得以解決。廢話很少說了,如今進入正題。本篇文章涉及到的解決方式均在RK3399的開發版上進行了測試,至於其餘版子理論上來講解決的方式都是同樣的。另外這邊文章只是給出簡單的解決方法,至於具體的原理不會解釋(有些地方我也是隻知其一;不知其二嘿嘿)文章末尾有相關的鏈接讀者能夠自行閱讀。html
本篇文章android雙屏的實現方式是Google提供的Presentation類實現的。下面參考中有相關的鏈接可已查看。之因此在此強調說是Presentation的實現方式,是由於我在作雙屏異顯,閱相關讀資料的時候發現雙屏異顯是有兩種實現方式。咱們經常使用的是Presentation這種方式,網上大多介紹的也是這種方式。另一種實現方式是RK DualScreen方式,這種方式網上的資料不多,須要對android系統源碼進行多出修改才能實現。linux
實現異觸具有的條件:android
我在經過Presentation實現雙屏異觸的時候發現,兩個屏幕顯示相同的畫面,主屏和副屏的觸摸都是沒有問題的。可是若是開啓雙屏異顯功能,主屏幕點擊沒有反應,點擊副屏是沒有問題的。這個問題是由於Presentation自己就是一個Dialog,它窗口的優先級要高於Activity(能夠查看window窗口方面的資料),所以全部的事件都會就給副屏。bash
因爲本身是第一作Android系統源碼的開發,在處理C++的時候遇到不知道如何打印日誌的問題。其實Android系統的源碼中已經使用了日誌打印的功能,只不過是關閉的。咱們只須要在要修改的文件中將Loge打開便可使用。網絡
如InputDispatcher.cpp文件日誌未開啓前函數
#define LOG_TAG "InputDispatcher"
//#define LOG_NDEBUG 0
複製代碼
修改成:工具
#define LOG_TAG "InputDispatcher"
#define LOG_NDEBUG 1
複製代碼
去掉LOG_NDEBUG
的註解將值改成1就可使用Loge日誌功能。在查看日誌的時候,手機鏈接電腦在AndroidStudio中的Logcat工具中搜索InputDispatcher
快速查看到本身在C++中打印的日誌信息。測試
Firefly-RK3399只有一個是Type-c接口,在雙屏狀況下因爲Type-c作了副屏的輸入口了,因此我使用了網絡ADB調試的方式來調試和安裝App。spa
若是想要實現主屏能夠觸摸,副屏不用觸摸的功能。有兩種解決方式:第一種是在App應用代碼中實現。第二種須要修改framework層的源碼。.net
第一種方式
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
複製代碼
第二種方式:
在/frameworks/native/services/inputflinger/EventHub.cpp
中屏蔽掉device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
屬性。
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
//device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
}
複製代碼
雙屏異觸指的是,在開啓異顯以後主屏和副屏均可以觸摸,而且各自處理各自的點擊事件。這種方式須要在/frameworks/native/services/inputflinger/InputDispatcher.cpp
文件dispatchMotionLocked()函數中增長以下代碼:
//主屏幕設備id
int mainDviece=0;
//獲取一次設備id
bool isFirstMainDisplay = false;
//主屏幕displayId
int mainDisplayId = 0;
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
ALOGD("old將displayid賦值爲:entry->displayId=%d entry->deviceId=%d", entry->displayId, entry->deviceId);
//獲取主屏幕的設備id和displayId
if (!isFirstMainDisplay && isMainDisplay(entry->displayId))
{
mainDviece = entry->deviceId;
mainDisplayId = entry->displayId;
isFirstMainDisplay = true;
}
//只有entry->deviceId是主屏幕設備id的時候纔將 entry->displayId修改成主屏幕id
if (mainDviece == entry->deviceId)
{
entry->displayId = mainDisplayId;
}
ALOGD("new將displayid賦值爲:entry->displayId=%d entry->deviceId=%d", entry->displayId, entry->deviceId);
...
}
複製代碼
displayId能夠決定那個窗口來處理該事件,若是displayId爲主屏幕id那麼該事件將會傳遞主屏的Activity的window來處。若是displayId是副屏的id那麼該事件將會交給副屏的Presentation也就是Dialog窗口處理。而Dialog窗口優先級高於Activity窗口,所以系統默認是將事件傳給副屏的Dialog窗口處理的。上面咱們定義了三個全局變量mainDviece
、isFirstMainDisplay
、mainDisplayId
,設備idmainDviece
可用於判斷是主屏幕仍是副屏幕,mainDisplayId
是主屏的id。之因此使用設備id來作屏幕的判斷是由於,默認狀況entry->displayId
函數在異顯模式下,無論點擊主屏仍是副屏獲取的displayid都是相同值。所以咱們須要在dispatchMotionLocked()
第一次執行的時候就要經過系統的isMainDisplay()
函數獲取一次主屏幕的設備id和displayid。而且經過設備id來判斷是否爲主屏。若是entry->deviceId
爲主屏幕id那麼就將entry->displayId
改成主屏幕的displayid,從而使事件傳遞給主屏Activity的窗口來處理。
本身很近沒有寫文章了,感受寫做水平都降低了不少。上面不少可能寫的有些亂,讀者遇到不懂得能夠搜索相關文章來理解。文章的最後感謝QQ羣546270670的一位羣友SharryChoo,由於他的共享一篇筆記是本身在解決上面問題中有了思考的方向。
文件下載地址:嘿嘿!賺點CSDN積分
Android應用程序輸入事件分發和處理機制_老羅android之旅總結