App 개발 : 잠금화면- HomeKey Control Problem

2014. 6. 5. 16:24프로그래밍/안드로이드

[인터넷 웹 포럼에서 쉽게 찾을 수 있는 제어 방법들을 통해 제어하기 힘든 이유]

홈 키 제어에 관련된 문제로 검색을 하면 쉽게 제시되는 방법이 몇 가지 있습니다.

하드웨어 키 이벤트를 막는다거나, 라이프 사이클을 이용해 홈키 발생 후 바로 앱을 실행한다거나 알람을 통해 호출한다거나 등등등....

하지만 실제로 테스트 해보신 분들은 위 방법들이 적용되지 않거나 문제가 있다는 것을 확인하셨을 겁니다.


그 이유에 대해 알아보겠습니다.


1. 홈키는 왜 하드웨어 키 제어가 안 먹히는가?

안드로이드의 하드웨어 버튼 제어에 관한 설명은 인터넷 검색을 통해 쉽게 찾을 수 있습니다.

아래는 OnKeyDown을 이용해 작성한 간단한 예입니다.


OnKeyDown은 단말기의 키 이벤트(Up, Down)와 키 코드(, 뒤로가기 기타 등등)를 캐치해서 알려줍니다.


위 예제에서는 하드웨어 키 이벤트를 캐치하는지 확인하기 위해 isSystem 함수를 호출하였고, 두 가지 버튼 뒤로가기 버튼과 홈 버튼의 이벤트를 캐치 하도록 하였습니다.

**isSystem()은 하드웨어 키가 눌러지면 True를 반환하는 함수입니다.

 

실행 후 뒤로가기 키에서는 isSystem함수가 True를 반환하고, KeyCodeKEYCODE_BACK을 반환한 것을 확인 할 수 있습니다.

하지만 홈키의 경우 isSystemFalse를 반환합니다. 키 이벤트가 넘어오지 않았다는 이야기죠. 당연 이벤트가 넘어오지 않았기에 키 코드의 체크는 불가능합니다.


이에 대해 좀더 자세히 알아보기 위해 구글에서 제공되는 오픈소스를 확인해보았습니다.

우선 isSystem을 확인해보았습니다.


홈 키를 포함한 모든 하드웨어 키가 명확히 명시되어 있습니다.

 

그래서 KeyEvent를 확인해보았습니다.


세 번째 확실하게 명시되어있습니다.

그런데도 홈키의 이벤트는 넘어오지 않습니다.


그래서 안드로이드 KEYCODE_HOME의 정의 부분을 찾았더니...


Application 레벨으로는 이벤트가 절대 전달되지 않는다고 명시가 되어있습니다

실제 코드를 따라가며 버튼 입력이 디스패치 되는 과정을 보면 홈키의 이벤트가 넘어오지 않게 처리되어 있습니다.


하드웨어 키와 홈키의 동작을 더 자세히 알고 싶으시면, PhoneWindowManager.javainterceptKeyMidWindowManager.javainterceptKey, launchHomeFromHotKey 부분을 확인해보세요.


키 이벤트가 넘어오지 않기 때문에 Application 레벨에서의 제어 자체가 불가능하다는 이야기입니다.

제공되는 API 자체를 수정하면 가능은 하겠지만, 만약 이 공개 API를 수정해서 App을 제작하게 된다면 배포 시 안드로이드 소스자체를 빌드하여 그 이미지 까지 같이 배포되어야 겠죠. App 하나를 위해 단말기를 갈아엎는 위험을 감수하는 사용자는 없다고 생각하기에(정말 큰 메리트를 가지고 있거나 개발자라면 예외지만...) 이 방법은 포기해야 합니다


2. 홈키를 누른 후 액티비티가 바로 호출되지 않는 이유는?

액티비티는 윈도우 응용프로그램과 같이 라이프 사이클을 가지고 있습니다.

아래는 구글에서 제공하는 ActivityLifecycle의 구조입니다.


라이프 사이클에 대한 자세한 설명은 생략하겠습니다. (글이 너무 길어질 것 같아요...)


액티비티가 종료되거나 화면에서 백그라운드로 내려가면 즉, 홈키나 뒤로가기 키를 눌러서 액티비티를 종료하거나 비활성화 하게되면 onPause함수가 호출됩니다.

이 때 홈키를 눌러 비활성화 된 경우에만 호출되는 함수가 있습니다바로 OnUserLeaveHint()함수입니다.

이 함수가 호출되었다는 것은 홈키가 눌러졌다는 이야기입니다. 


하드웨커 키제어를 통해 홈키를 제어할 수 없기 때문에 액티비티가 화면에서 사라지면 바로 다시 호출하면 되지 않을까 생각해서 많은 분들이 시도한 방법입니다. (저도 거기 포함..)


이 곳에서 액티비티를 재실행하면 홈키를 막은 것과 같은 효과를 낼 수 있겠죠.

그래서 아래와 같이 작성하였습니다.



실행 후 홈버튼을 눌러보면, 토스트 박스는 정상적으로 호출이 됩니다.

하지만 액티비티의 경우 재실행은 되지만 일정 시간이 지나야 실행이 됩니다.


다른 방법으로 알람을 이용해 보았습니다만 마찬가지입니다.

또 다른 방법으로 외부 패키지를 실행해보았지만 마찬가지입니다.


이런 일이 일어나는 이유가 있습니다.

구글에서는 홈키를 눌렀을 때 활성화 되어있던 액티비티를 전부 백그라운드로 내리며, 이때 이 액티비티 내에서의 동작들을 5초동안 멈춰버립니다.

일명 5초 룰이라고 하며, 이 때문에 홈키를 누르게 되면 실행중이던 액티비티에서는 무슨 짓을 해도 5초간 대기하게 되어버립니다.

 

이 시간은 ActivityManagerService.java에 명시되어 있으며 아래는 실제 코드의 해당 변수입니다.


정확히 5초로 잡혀있는 것이 보입니다. 예전에는 퍼미션을 통해 제어 가능했다고 하네요.

간단히 동작 구조를 설명하면 홈 키를 누르면 launchHomeFromHotKey 함수에 의해 StopAppSwitch 함수가 호출되며 이 함수 내부에서 App_Switch_delay_time 변수를 통해 해당 앱은 5초 동안 멈추게 됩니다.

 

그 외 알아본 방법으로는 브로드캐스트 리시버의 system_dialog_reason_home_key 이벤트를 체크하는 방법이 있으나 테스트는 해보지 않았지만 OnUserLeaveHint와 동일 할 것으로 보이며, STOP_APP_SWITCHES 퍼미션을 통한 제어가 있다하지만 이 또한 루팅이 필요한 부분인것 같습니다.


결과적으로 현재 루팅 및 내부소스를 수정하지 않고, 순수 어플리케이션 레벨에서 제공되는 API를 이용해 홈키 이벤트를 제어하는 것은 불가능하다는 것이 정론입니다.


다음 포스팅에서는 우회방법에 대해 알아보겠습니다.