안드로이드 단말에는 다양한 키들이 존재한다.
볼륨 Up/Down, 전원 등등의 키가 있고 이 키들이 press/release 되는 이벤트를 앱에서 받아 처리 할 수 있다.
아래 링크에서 안드로이드가 제공해주는 기본 키들에 대한 정보를 알 수 있다.
https://developer.android.com/reference/android/view/KeyEvent
안드로이드 앱에서는 기본적으로 onKeyUp / onKeyDown 을 받아서 처리가 가능하다.
public class KeyEventActivity extends AppCompatActivity {
private static final String TAG = "KeyEventActivity";
private static final boolean Debug = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_keyevent);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event){
if(Debug) Log.d(TAG, "onKeyUp - keyCode : "+keyCode);
return false;
}
}
다만 화면이 꺼지면, 앱은 Pause 상태에 빠지기 때문에 onKeyUp / onKeyDown 이벤트를 받는 것이 어렵다.
(참고 : 안드로이드 생명 주기 https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ko#onpause )
이럴 경우 어떤 방법으로 처리를 해야 화면 ON/OFF 상태에 상관 없이 Key 이벤트를 처리 할 수 있을까?
바로바로
Accessibility Service 를 활용하는 방법이다.
안드로이드 개발자 홈페이지에 아주 잘 나와있어서 내가 만든 예제와 참고해서 보면 좋을 것 같다.
https://developer.android.com/guide/topics/ui/accessibility/service
내가 만든 예제는 다음과 같이 이루어져 있다.
Step1. 사용자로부터 Accessibility 권한 받기
나는 이 기능을 맨 처음 실행되는 Activity에 넣어 구현하였다.
어디에 넣어도 상관 없을 것 같긴한데,
KeyEvent 가 필요한 시점에는 무조건 권한이 필요하기 때문에 맨 처음 받는 것이 좋을 것 같다.
(보통 앱 설치 후 첫 실행에 모든 퍼미션을 요청하니까..)
Step1에 넣은 것과 달리.. 나는 이 작업을 안해줘서 계속 헤맸다..
달리 에러도 안나고 잘 실행되는 것 처럼 보여서 찾기가 정말 힘들었다.!
그래서 Step1..!!!
-1. 현재 앱 권한 확인
Accessibility 권한이 있는 리스트 중 현재 실행되고 있는 앱이 있는지 확인하는 방식
/**
* Check for accessibility permission of current app.
*
* @return - true : permission exist.
* - false : permission not exist.
*
*/
public boolean checkAccessibilityPermissions() {
AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(this.ACCESSIBILITY_SERVICE);
// getEnabledAccessibilityServiceList use for getting a list of apps that have accessibility permission.
List<AccessibilityServiceInfo> list = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.DEFAULT);
for (int i = 0; i < list.size(); i++) {
AccessibilityServiceInfo info = list.get(i);
// Check current app exist in the list.
// Compare with package name of app.
if (info.getResolveInfo().serviceInfo.packageName.equals(getApplication().getPackageName())) {
return true;
}
}
return false;
}
-2. 권한 설정 Activity 실행
권한이 없다면 권한 설정을 받을 수 있는 Acitivity 를 실행.
/**
* Execute to permission settings.
*/
public void setAccessibilityPermissions() {
AlertDialog.Builder gsDialog = new AlertDialog.Builder(this);
gsDialog.setTitle("Setting Accessibility Permission");
gsDialog.setMessage("Need Accessibility Permission");
gsDialog.setPositiveButton("Check", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start setting permission activity
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
return;
}
}).create().show();
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final boolean Debug = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// After check accessibility permission, execute setting permission activity.
if(!checkAccessibilityPermissions()) {
setAccessibilityPermissions();
}
}
/**
* Check for accessibility permission of current app.
*
* @return - true : permission exist.
* - false : permission not exist.
*
*/
public boolean checkAccessibilityPermissions() {
AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(this.ACCESSIBILITY_SERVICE);
// getEnabledAccessibilityServiceList use for getting a list of apps that have accessibility permission.
List<AccessibilityServiceInfo> list = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.DEFAULT);
for (int i = 0; i < list.size(); i++) {
AccessibilityServiceInfo info = list.get(i);
// Check current app exist in the list.
// Compare with package name of app.
if (info.getResolveInfo().serviceInfo.packageName.equals(getApplication().getPackageName())) {
return true;
}
}
return false;
}
/**
* Execute to permission settings.
*/
public void setAccessibilityPermissions() {
AlertDialog.Builder gsDialog = new AlertDialog.Builder(this);
gsDialog.setTitle("Setting Accessibility Permission");
gsDialog.setMessage("Need Accessibility Permission");
gsDialog.setPositiveButton("Check", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start setting permission activity
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
return;
}
}).create().show();
}
}
Step2. Accessibility 상속 받은 서비스 생성
대망의 서비스 등장!
서비스 코드는 사실 별게 없는 것 같고..
Manifest가 중요하다!
- KeyEventServiceAccessibility.java
public class KeyEventServiceAccessibility extends AccessibilityService {
private static final String TAG = "KeyEventServiceAccessibility";
private static final boolean Debug = true;
public KeyEventServiceAccessibility() {
Log.d(TAG, "KeyEventServiceAccessibility");
}
@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
Log.d(TAG, "onAccessibiltyEvent" + accessibilityEvent.toString());
}
@Override
public void onInterrupt() {
}
@Override
protected boolean onKeyEvent(KeyEvent event) {
Log.d(TAG, "onKeyEvent - keyCode = " + event.getKeyCode());
return handleKeyEvent(event);
}
private boolean handleKeyEvent(KeyEvent event) {
Log.d(TAG, "handleKeyEvent - keyCode = " + event.getKeyCode());
int action = event.getAction();
int keyCode = event.getKeyCode();
if (action == KeyEvent.ACTION_DOWN) {
// Key press
} else if(action == KeyEvent.ACTION_UP) {
// Key Release
}
return false;
}
}
- AndroidManifest.xml
여기서도 내가 엄청 헤맸었는데,..
android:accessibilityFlags="flagRequestFilterKeyEvents" 이 옵션을 넣지 않아서 KeyEvent를 못받고, onAccessibilityEvent 이벤트만 계속 받았다는 슬픈이야기.. 저 옵션을 추가하니까 마법처럼 keyEvent를 받을 수 있었다.!
<service
android:name=".KeyEventServiceAccessibility"
android:accessibilityFlags="flagRequestFilterKeyEvents"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice" />
</service>
이렇게 2단계를 이용하면 Accessibility 서비스를 이용할 수 있다.
하지만 모든 Key 에 대한 이벤트가 올라오는 것은 아니며,
화면이 OFF 되어 있을때는 더더더더 확인 가능한 key가 적다.!
이에대한 key 동작을 알아보는 것은 다음 게시물로 써야징~~
'WORK > Android' 카테고리의 다른 글
[Android][Framework] Key 추가 1단계 | Kernel keycode 확인 | adb shell getevent 정보 | Keyevent 확인 (0) | 2022.04.26 |
---|---|
[Android] KeyEvent 처리 | KeyEvent 순서 | Framework Key event (0) | 2022.04.25 |
[Android] Jack server 빌드 에러 (2) | 2021.05.11 |
[Android] storage 접근 권한 요청, 처리 (0) | 2021.04.13 |
[Android] 안드로이드 제공 vector 이미지 추가 | 안드로이드 버튼 아이콘 추가 (0) | 2021.04.09 |