로지난번에 AccessibilityService를 이용해 앱이 상단에 있는 상태가 아니여도,
KeyEvent 를 받는 방법에 대해 알아보았다.
https://codingstorywithme.tistory.com/42
근데!
위의 서비스를 이용하거나 app에서 keyEvent를 받을 때, 모든 Key에 대한 이벤트를 받을 수 있는 것은 아니다.
어떻게 알 수 있을까?
그래서 이번에는 KeyEvent 에 대해 좀 더 정리하려고 한다.
#1. KeyEvent 전달 순서
KeyEvent 가 발생 했을 때, 사용자가 확인 가능하도록 앱, 앱 서비스 등 어플리케이션으로 올라오기까지 여러 단계를 거치게 된다.
이에 대한 내용은 안드로이드 개발자 페이지에도 잘 나와있지만, 내가 한 번 더 정리하려고 한다.!
https://source.android.com/devices/input?hl=ko#input-pipeline
-1. [Kernel] 키 이벤트 발생
제일 먼저 커널에서 키 이벤트가 발생한다.
이때 KeyEvent는 adb 로 확인이 가능하다.
- cmd 실행
- $adb shell getevent
를 이용해 실시간 event를 확인 할 수 있다.
아래는 터치 및 뒤로가기 버튼 클릭한 화면이다.
adb shell getevent에 대한 내용은 아래 문서에서 자세히 확인 가능하다.
https://source.android.com/devices/input/getevent?hl=ko
커널에서 올려주는 keyCode는 kl파일에 정의 되어 있다.
파일에 대한 설명은
https://source.android.com/devices/input/key-layout-files?hl=ko 를 참고하면 좋다.
-2. [Native Service] 키 이벤트 Eventhub로 전달
* 위치 : frameworks/native/services/inputflinger/EventHub.cpp
커널에서 input_event를 얻어오기 위해서는 디바이스 파일을 읽어내야 한다. 디바이스 파일 경로는 “/dev/input/*” 형태로 되어있다. 안드로이드에서 이를 읽어내서 처리하는 부분을 담당한다.
각 입력 기기에 연결된 evdev 드라이버를 열어 커널의 입력 이벤트를 읽은 후, 입력장치별 Key Layout 에 따라 Kernel keycode 를 Android Keycode로 변환한다. 다시말하면 struct input_event 타입으로 Kernel keycode 를 읽어와서 RawEvent로 변환시켜 Android Keycode를 InputReader에 전달하는 것이다.
-3. [Native Service] 키 이벤트 InputReader로 전달
* 위치 : frameworks/native/services/inputflinger/InputReader.cpp
Input device의 데이터를 읽고 처리하는 class로 입력 이벤트를 InputDispatcher로 전송한다.
-4. [Native Service] 키 이벤트 InputDispatcher로 전달
* 위치 : frameworks/native/services/inputflinger/InputDispatcher.cpp
InputReader 클래스에서 처리된 데이터를 내부의 큐에 저장 한 뒤, input event를 보낼 input target을 찾아 event를 dispatch한다.
-5. [System Service] 키 이벤트 PhoneWindowManager로 전달
* 위치 : frameworks/./base/services/core/java/com/android/server/policy/PhoneWindowManager.java
키 이벤트를 내부적으로 처리할지, USER (APP단) 에게 올려 사용 가능하게 할지 등을 포함한 키 이벤트의 동작을 결정한다.
소스에서 확인을 해보자.
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) 부분을 확인해 보면 아래 쪽에
여기에서 result = ACTION_PASS_TO_USER; 이 부분이 중요하다.
result 에 ACTION_PASS_TO_USER 이 있으면 USER 즉 App 에서 해당 key event를 확인 할 수 있고, 없으면 app 에서 getKeyEvent 등으로 확인이 불가능하다.
하나 더 확인을 해보면,
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) 함수에서
위에 표시 되어 있는 부분처럼
result &= ~ACTION_PASS_TO_USER; 라고 표시하면, 현재 result 에서 ACTION_PASS_TO_USER 표시를 없애는 것이 되므로 해당 key event는 User 즉 app 에서 확인이 불가하게 된다.
ACTION_PASS_TO_USER 와 같은 result 값들은
./base/services/core/java/com/android/server/policy/WindowManagerPolicy.java 에서 확인 할 수 있다.
/**
* Pass this event to the user / app. To be returned from
* {@link #interceptKeyBeforeQueueing}.
*/
int ACTION_PASS_TO_USER = 0x00000001;
/** Layout state may have changed (so another layout will be performed) */
int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
/** Configuration state may have changed */
int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
/** Wallpaper may need to move */
int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
/** Need to recompute animations */
int FINISH_LAYOUT_REDO_ANIM = 0x0008;
/** Layer for the screen off animation */
int COLOR_FADE_LAYER = 0x40000001;
끄읐!
'WORK > Android' 카테고리의 다른 글
[Android][Framework] Key 추가 2단계 | KeyLayout 추가 | KeyCode 추가 | KeyLayout 생성 (0) | 2022.04.28 |
---|---|
[Android][Framework] Key 추가 1단계 | Kernel keycode 확인 | adb shell getevent 정보 | Keyevent 확인 (0) | 2022.04.26 |
[Android] 화면 OFF 상태에서 Key Event 받기 | AcessibilityService 상속 서비스 | KeyEvent 서비스 | 접근성 서비스 (0) | 2022.04.01 |
[Android] Jack server 빌드 에러 (2) | 2021.05.11 |
[Android] storage 접근 권한 요청, 처리 (0) | 2021.04.13 |