릴랏 멘토링 관련 URL : http://kr.rellat.com/2017/05/blog-post.html
이 문서는 프로그래밍을 공부하고 개발하는 과정을 쓰는 일지다. 일지는 일기와 같은 뜻이다. 여기에는 날마다 나에게 주어진 과제를 풀고, 프로그래밍 관련 리서치를 하고, 코딩을 한 것을 기록한다. 왜 이런 생각을 하게 되었는지, 어떻게 하게 되었는지를 기록해서 사고방식을 개발한다.
- 프로그래밍 공부한 내용을 쓴다.
- 프로그래밍 개발한 내용을 쓴다.
- 웹 검색, 리서치한 내용을 쓴다.
- 왜 이런 생각을 하게 되었는지, 어떻게 하게 되었는지를 기록한다.
다른 사람들이 쓴 과제 일지를 읽어 보고 내 입장에서 배울점, 개선할 점을 생각해 본다. 릴랏 개발 가이드와 이기준이 쓴 릴랏 강의 시리즈가 과제 일지의 예시다. 이것들을 읽어보고 참고해서 비슷하게 써본다.
과제 지도는 이기준, 이기환님에게 받는다. 남이 쓴 일지를 읽어보고 자기 입장에서 댓글을 달고 수정제안을 할 수 있다.
자기 페이스북 링크를 넣는다.
예: 이기준 페이스북2017년 9월 29일
작은 오픈 소스 분석 작업 : Google TalkBack
Google TalkBack 의 간단한 소개
TalkBack Git : https://github.com/google/talkback
안드로이드 폰을 사용하는 사람일지라도 TalkBack 이라는 프로그램은 생소할 것이다.
주로 시각 장애인들이 안드로이드 폰을 사용하기 위해서 Google 에서 제작한 프로그램이다.
TalkBack 은 현재 삼성 갤력시 기종에서는 볼 수가 없다. 이를 삼성에서 보이스 어시스턴트로 대체했기 때문이다.
IOS 를 사용하시는 분들은 Voice Over 를 켜시면 어떻게 동작하는지 알 수 있습니다.
TalkBack 에 대한 자세한 사용 방법은 아래 사이트에서 알 수 있습니다.
http://nuli.navercorp.com/sharing/blog/post/1132564
2017년 10월 01일
Google Talkback 오픈 소스 분석을 할 때 사용자가 이벤트를 발생을 시키면 어디부터 실행이 될까?
에서 부터 오픈 소스 분석을 시작했다.
먼저, TalkBack은 서비스 형태로 동작하고 있다.
사용자가 왼쪽에서 오른쪽으로 슬라이드를 하던지 아니면, 포커스가 된 어플이나 버튼에서 클릭을 하던
반드시 그 시작점이 어디일까 생각해보았다.
TalkBack을 받아서 폰에서 디버깅을 한 후에 설치하고 이벤트를 발생시켰을 때, TalkBack 메인 소스 중에
onAccessibilityEvent 라는 함수에서 시작이 되는 것이 파악이 되었다. onAccessibilityEvent 함수가 무엇인지
확인이 필요해서 Androide Developer 사이트를 이용해서 검색을 했다.
아래는 검색된 사이트 : https://developer.android.com/reference/android/app/UiAutomation.OnAccessibilityEventListener.html
찾고자 하는 onAccessibilityEvent 함수가 OnAccessibilityEventListener에 정의되어 있는 함수이고,
기능을 확인해보니 AccessibilityEvent 를 받기 위한 CallBack 이라고 한다.
그러면, AccessibilityEvent 가 무엇인지 확인이 필요하다. 그래서 검색을 한 사이트가 아래에 있다.
요약하자면, AccessibilityEvent 는 사용자가 버튼을 클릭하거나 뷰에 포커스를 하는 등 이벤트를 발생시키면,
그 이벤트에 해당되는 피드백을 사용자에게 주도록 하는 클래스이다.
즉 TalkBack을 켜서 슬라이드를 하거나 클릭을 하면 그에 해당하는 폰에서의 반응을 사용자에게 피드백 해주는 기능을 하고 있다.
AccessibilityEvent 를 확인하던 중에 AccessibilityRecord 라는 클래스를 상속받아서 사용한다.
AccessibilityRecord 설명이 나온 사이트 아래와 같다.
요약하면, 뷰의 상태 변화를 포함하고, AccessibilityEvent가 어떤 것이 발생했는지 기록하는 것을 나타낸다고 한다.
2017년 10월 10일
Google TalkBack에서 사용자 인터페이스로 인한 이벤트가 발생되면, 가장 처음 실행되는 곳이
onAccessibilityEvent함수라는 것이 앞에서 확인되었다.
이제 onAccessibilityEvent 발생을 위해서 TalkBack을 사용할 수 있는 가이드라인은 아래 사이트를 참조하면
간단한 사용법을 알 수가 있다.
위 사이트에서 TalkBack에서 자주사용하는 이전/다음 콘텐츠 이동인 한손가락을 위 또는 왼쪽으로 동작하거나
한손가락을 아래 또는 오른쪽으로 동작하는 기능을 사용자가 실행하면, onAccessibilityEvent 함수에서 이것을
확인하여 그에 해당하는 이벤트를 발생시켜주는데 이벤트 발생 전에 onAccessibilityEvent 에서 Break 포인트를
걸면, 실행되기 전 상태로 멈춰있게 된다.
그러나, 현재 가리키고 있는 콘텐츠를 실행하기 위해서 한 손가락으로 두번 탭을 하게 되면, 실행되기 전에 onAccessibilityEvent 함수에서 멈춰있지 않고, 실행한 다음에 onAccessibilityEvent 함수에 멈춰있게 된다.
그러면 실행을 하기 전에 동작이 되는 부분이 있다라는 결론에 도달하게 된다.
지금 실행을 하기 전에 어디에서 동작이 되고 있는지 찾고 있는 중이다.
2017년 10월 11일
한 손가락으로 두 번 탭을 하게 되면, onAccessibilityEvent 함수가 실행되기 전에 실행을 하는 곳이 어디인지
찾아 보았지만, 도저히 실행되기 전에 찍히는 곳이 없어서, Android Framework 소스를 보게 되었다.
구글에 Framework 소스를 쳤을 때 안나오면 어쩌나 걱정했지만, 다행히 Github에 올라와 있었다.
Framework 소스는 아래 링크에서 볼 수 있다.
일단 보고 있는 부분이 Accessibility 부분이였는데 Framework 부분에서 검색을 했을 때
AccessibilityManagerService 가 나와서 Accessiblity 를 어떻게 관리하는지 확인했다.
경로는 아래와 같다.
AccessibilityManagerService 의 역할은 안드로이드 장비에서 발생된 AccessibilityEvent 들을 AccessibilityService
를 구현한 곳에 모두 보내주는 역할을 한다.
위 내용으로 확인을 하면, 안드로이드 장비에서 AccessibilityEvent가 발생하면, AccessibilityManagerService에서
확인하여 AccessibilityService로 보내주는 역할을 하는 것으로 분석이 된다.
한 손가락으로 한 번 탭을 하던, 두 번 탭을 하던, 슬라이드 왼쪽 또는 오른쪽으로 하는 이벤트가 발생이 되면,
먼저, AccessibilityManagerService 에서 확인이 되어, 다른 AccessibilityService 들에게 이벤트를 넘겨주는 것으로
분석이 되었다.
2017년 10월 12일
AccessibilityManagerService 를 분석하는 중에 앞에서 보았던 AccessibilityService와 AccessibilityEvent가 나와서
Framework 내에 정의 된 곳이 있는지 확인해보았고, 두 클래스가 정의된 부분을 찾았다.
먼저, AccessibilityService는 아래와 같다.
AccessibilityService는 서비스의 형태로 백그라운드에서 동작되고, AccessibilityEvent들이 발생되면,시스템에게
Callback으로 받아서 처리한다. 이러한 Event들은 사용자 인터페이스로 제공되며, 버튼을 클릭한다거나
포커스의 변경이 일어나는 등의 상태변화를 다룬다.
그리고, AccessibilityEvent는 아래와 같다.
AccessibilityEvent는 버튼이 클릭되거나 특정 뷰에 포커스 하는 등의 사용자 인터페이스 내에서 일어났을 때,
시스템에서 받은 Accessibility Event들을 표현하는 역할을 한다. 그래서 AccessibilityService에서
어떤 AccessibilityEvent 가 발생했는지 확인하여 그에 해당하는 동작을 할 수 있도록 onAccessibilityEvent 함수를
추상화하여 상속받는 모든 클래스에서 처리할 수 있는 구조로 되어있다.
그런데 아직 근본적으로 알고 싶은 한 손가락으로 두 번 탭을 해서 실행하는 것에 대해서는 아직 명확하게 밝혀진
것이 없다.
그러면, AccessibilityEvent가 발생되기 전에 일어나는 이벤트가 따로 존재하는지 찾아야겠다.
2017년 10월 16일
Android Framework 내에 있는 클래스들을 더 이해를 하기 위해서 Framework 소스만 보지말고, 직접
AccessibilityService 샘플을 만들어서 어떻게 동작하는지 알아보고자 시작했다.
처음에 서비스를 어떻게 실행하고 연결하는지 알아보고자 Google을 보기 시작했고,
아래 사이트를 참고로 진행을 하였다.
서비스 구현 방법 예제 : http://bitsoul.tistory.com/147
서비스 바인드 방법 예제 : http://bitsoul.tistory.com/149
AccessibilityService 도 Service를 확장하여 구성되어 있으므로 동일하게 진행을 했다.
그러나 일반 서비스와 다르게 onBind 함수를 쓰지 않았고, 그 대신 onServiceConnected 라는 함수를 사용했다.
AccessibilityService의 추상클래스인 onAccessibilityEvent와 onInterrupt함수를 무조건 구현을 해야했다.
일반 서비스와 동일한 방법으로 시도를 했으나 AccessibilityService를 확장한 서비스와 연결이 되지 않는 이슈가
계속해서 발생했다.
그래서 어떤 것이 문제인지 확인을 위해서 AccessibilityService를 바인딩하는 방법을 찾다가 Android Developers
사이트에서 그 해답을 찾을 수 있었다. 아래 사이트를 참고하면 된다.
위 사이트의 Declaration 부분을 보면, permission을 android.accessibilityservice.AccessibilityService 를 연결하라는
부분이 있다. 이걸 불러오지 않으면, Accessibility services는 시스템에서 무시당한다는 내용이 있다.
위 부분을 AndroidManifest.xml 파일에 AccessibilityService에 해당하는 service에 퍼미션을 추가했다.
그 후에 샘플로 만든 Activity에 있는 버튼으로 서비스를 켜고, 끄고가 되는 것으로 생각이 되었다.
그러나 이상하게 onAccessibilityEvent가 잡히지 않는 것이였다.
이유를 찾지 못하다가 Google 검색 중에 아래 사이트를 읽어서 수정하던 중에 문제가 해결되었다.
설정에서 접근성에 들어가서 옵션을 켜라는데 무슨의미인지 알 수 없었지만,
아래 부분에 액티비티 실행하는 곳을 보니 설정의 접근성 항목을 계속 실행하는 것을 보다가
TalkBack을 설치하는 곳 아래부분에 해당 프로젝트 명의 항목이 추가로 발견되어 켜보니 그 후에는
onAccessibilityEvent에서 이벤트가 잡히는 것이 확인이되었다.
2017년 10월 17일
샘플로 AccessibilityService를 연결한 후에 View에선 MotionEvent가 보낸 이벤트를 어떻게 처리하고, 감지하는지 확인이 필요했다.
그래서 View에 대한 내용을 읽었다.
View는 Control로 동작하고, text 또는 image 등의 콘텐츠를 출력하는 기능을 한다.
우리가 안드로이드 프로젝트를 만들어서 layout 폴더에 만들었던 화면 출력내용과 화면에 생성한 인터페이스들을 조작하는 일을 한다.
가장 알고 싶었던 내용은 MotionEvent에서 발생한 이벤트가 어떻게 View에서 받을 수 있을까? 였는데
그 해답이 View 클래스 내에 있었다. View에서는 이벤트를 처리하는 함수가 있는데 onKeyDown, onKeyUp,
onTrackballEvent, onTouchEvent 이렇게 있으며, 터치관련 이벤트는 onTouchEvent 함수에서 처리하느데 여기서
MotionEvent를 받아와서 AccessibilityEvent를 알 수 있게 보내주는 역활을 한다.
뷰에 대한 내용은 다음 사이트에 나와있다. -> https://developer.android.com/reference/android/view/View.html
MotionEvent 관련 내용은 다음 사이트에 나와있다.
지금까지 조사한 내용을 정리하면서 TalkBack이 어떻게 동작이 되고 어떤 것을 기반으로 하고 있는지
분석한 내용을 정리해보려고 한다.
TalkBack 조사 내용
- TalkBack은 AcessibilityService를 확장하는 서비스이다.
- AccessiblityServie를 연결하려면 아래 사이트에서 설정 관련 사항을 AndroidManifest.xml 파일에 추가해 주어야한다. -> https://developer.android.com/guide/topics/ui/accessibility/services.html
- “android.permission.BIND_ACCESSIBILITY_SERVICE”를 서비스 퍼미션에 추가
- Intent-filter 내에 action 태그에 “android.accessibilityservice.AccessibilityService”를 추가
- res 폴더 내에 xml 폴더를 생성하여 accessiblity_service_config 파일을 생성
- 접근성에 가서 생성한 샘플 프로젝트 명으로 된 항목을 찾아서 실행 후 켜면 서비스가 동작
- AccessibilityService가 제대로 연결되었는지 확인 방법
- onServiceConnected 함수가 호출되는지 확인
- Android 장비에서 이벤트가 발생했을 때 onAccessibilityEvent 함수가 호출되는지 확인
- TalkBack 동작원리
- 사용자가 Android 장비에 이벤트를 발생 시키면, 시스템의 MotionEvent 가 감지
- MotionEvent에서 좌표 값과 액션 코드를 이용해서 어떤 이벤트가 발생했는지 알림
- View에서 Event를 감지하는 onKeyDown, onKeyUp, onTrackballEvent, onTouchEvent 에서 확인
- 그 후에 중간 과정을 거치는데 확인 필요
- GetureDetector 클래스에서 TouchExplorer 쪽으로 어떤 이벤트가 발생했는지 전달
- TouchExplorer에서 AccessibilityService가 켜져 있으면, AccessiblityGestureDetector로 전달
- AccessibilityGestureDetector에서 AccessibilityManager의 sendAccessibilityEvent를 발생
- sendAccessibilityEvent에서 AccessibilityService와 연결된 객체들에게 onAccessibilityEvent 함수를 동작하게 하여 어떤 AccessibilityEvent가 발생했는지 감지
- TalkBack에선 Double-Tab을 제외한 포커스 이동, 포커스 맞춤 등을 동작
- TalkBack에서 AccessibilityEvent 처리 방법은 이벤트를 처리하는 곳에 AccessibilityService를 상속하여 onAccessibilityEvent함수를 받게 한 후에 이벤트를 연결된 클래스에 모두 보내서 처리
MotionEvent에서 발생된 이벤트를 View에서 확인하여 알려주는데 AccessibilityService 가 켜져있을 때, 꺼져있을 때 어떻게 동작해서 GestureDetector 클래스까지 오는지 확인이 필요하다.
해당 사항은 Framework에서 AccessibilityService와 관련된 부분과 View를 보면서 차차 분석해 나가기로했다.
그래서 이벤트 중에 TalkBack에서 KeyEvent는 어디에서 받는지 확인을 해보기로 했다.
TouchEvent는 AccessibilityEvent 형태로 onAccessibilityEvent에서 감지가 되고 있는데 Key에 대한 사항이 분석이
되지 않은 것 같아 확인해보았다.
먼저 아래는 강제로 KeyEvent를 발생시키는 방법이다.
MotionEvent에서도 확인이 되었지만, Android 내에선 일단 Down로 이벤트 발생을 시작하고, Up으로 이벤트
발생을 종료하는데 KeyEvent도 확인을 해봤다.
Instrumentation 클래스의 sendKeySync에 KeyEvent를 정의하여 보내면, Key이벤트가 발생되는 것으로 분석되었고,
해당 사항대로 확인을 했더니, TalkBack 내에 onKeyEvent라는 함수를 발견했고, KeyDown으로 시작해서
KeyUp으로 끝나는 것이 확인되었고, 이벤트 발생 시 처리하는 부분도 알아내었다.
아래 사이트들은 AccessibilityServie 에 대한 내용과 빌드 방법을 찾던 중에 발견한 사이트로 AccessibilityService와
연결한 서비스를 빌드할 때와 AccessibilityService를 이해하는데 도움될 것으로 생각되어 남겼다.
2017년 10월 18일
TalkBack 동작 원리를 Android Framework의View를 분석하도록 하였다.
View의 Framework 소스는 아래 사이트에 있다.
-> https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/view/View.java
View에 대한 내용이 너무 길다. 그래서 필요한 부분이 TalkBack을 켜고 두 번 탭했을 떄 동작이 어떻게 되는지
알아보기 위해서 Event 부분을 먼저보고, 그 후에 Swipe 이벤트가 어떻게 동작하는지 확인을 위해서 Position
부분을 보려고 한다.
Event 처리 부분을 보면 4가지 함수가 나온다. onKeyDown, onKeyUp, onTrackballEvent, onTouchEvent
Event 처리 부분을 보기 전에 스마트 폰을 사용할 때, 어떤 이벤트가 발생을 하려면, 키보드로 이벤트를 발생하던
TouchScreen으로 이벤트를 발생하던, 이벤트를 발생시키려면, 일단 먼저 눌러야한다. 즉 Down Event가 먼저
발생하고, 그 후에 Up 이벤트가 발생이 된다. 해당 내용은 AccessibilityEvent를 디버깅했을 때도 동일하게
발생을 했다. 일단 이 사항을 기억하고 분석에 들어갔다.
onKeyDown 이벤트는 키보드에서 KeyEvent가 발생을 하면, 불려진다. onKeyUp 이벤트는 눌려진 키를 떼려고
할 때 발생을 한다. 이 두 함수가 호출이 되면, 시스템에서 KeyEvent가 발생을 했다라는 것을 알 수있다.
그리고, onTrackballEvent는 지금은 컴퓨터 마우스에는 없지만, 예전에 마우스 안에 공 모양으로 마우스를 움직일
수 있었다. 이것을 Trackball 이라고 한다. 혹시 모르거나 생소하다면, 아래 사이트를 확인해보면 된다.
글은 영어로 되어 있어서 보기 어렵지만, 그림으로 보면 어떤 느낌인지 알 수 있을 것이다.
다시 넘어와서 onTrackballEvent 가 발생을 했을 때, 마우스나 인터페이스 제공하는 장비에서 이벤트가 발생을
했을 때 발생한다. onToucheEvent는 우리가 스마트 폰에서 Touch Screen을 눌렀을 때 발생하는 이벤트이다.
onTrackballEvent와 onTouchEvent는 MotionEvent가 발생을 하면 동작한다.
봐야할 부분이 Touch Screen 을 두 번 탭했을 때 동작을 확인해야 하므로 onTouchEvent 함수를 보도록 했다.
View에 터치 이벤트가 발생했다는 전제 조건으로 시작해서 분석을 했다.
View에서 터치 이벤트가 발생을 하면, onTouchEvent 함수가 호출된다.분석 시에 Touch Screen 을 누르고 있는
상태라고 생각하고 시작했다.
MotionEvent 클래스를 보면 View에서 이벤트가 발생되어 알려줄 때, 좌표 값과 액션 코드를 이용하여 알려준다고
나와있는데 보자마자 위치 값과 액션 코드를 가져와서 시작된다.
MotionEvent에서 ACTION_DOWN 이 발생되는 중으로 가정하고분석했다. 위치 값과 액션 코드 값 다음으로
클릭여부를 확인하는데 일단 넘어가면, 두 갈래로 분석이 된다. mTouchDelegate 객체가 할당된 상태와 아닌
상태로 나뉜다. 먼저 할당된 상태면 mTouchDelegate 객체 내의 onTouchEvent 가 발생된다.
일단 TouchDelegate 객체부터 확인을 하며 아래 사이트에서 확인한다.
먼저 설명을 보면, View의 지정된 위치보다 넓은 범위를 원하는 상황을 다루는데 사용한다.
그래서 실행 전에 대표 View의 사용할 수 있는 한계를 먼저 만든다. 즉 화면 내에 버튼이나 텍스트 등의 뷰의
크기가 넘은 이벤트를 다룰 때 이용한다. 일단 잘 이해는 되지 않지만, onTouchEvent 함수가 동작되므로 분석을
하면, 좌표 값과 액션 코드로 확인해서 위치가 선택한 객체의 범위 안에 있는지 확인해서 ACTION_DOWN, ACTION_UP이나 ACTION_MOVE 가 발생했을 때 지정된 뷰의 범위 내에 있으면, 선택된 View의 범위를 줄이고,
대표 View에 dispathTouchEvent를 설정한 상태로 동작하도록 넘겨준다.
ACTION_DOWN 시에는 범위 내에 있었다가 ACTION_UP 이나 ACTION_MOVE가 발생 시에 범위를 벗어나면,
위치 값을 마이너스로 변경하여 대표 View에 dispathTouchEvent로 넘겨준다. 그리고, ACTION_DOWN이
발생할 때부터 범위가 벗어나면, 아무것도 발생하지 않는다.