Android 7.0 (API 24)부터 Quick Settings Tiles를 지원합니다. 이 기능은 Quick Settings에 Custom Tile을 추가할 수 있는 기능입니다.
내 앱에 TileService를 구현하면, Quick Settings가 그 서비스를 찾아서 Tile로 등록해 줍니다. Tile은 예를 들어 Quick Settings에 보이는 WIFI 아이콘과 같은 것들을 말하는 것입니다.
Tile은 Activity를 실행하거나 팝업을 뛰우는 것보다, WIFI 처럼 on/off로 어떤 기능을 켜고 끄는 동작이 필요할 때 사용하면 좋습니다.
Custom Tile 등록하기 위해 내 앱에 구현해야 할 것은 TileService 서비스를 구현하고 Manifest에 선언하는 것 뿐입니다.
샘플 앱을 만들어보면서 Custom Tile을 추가하는 방법에 대해서 알아보겠습니다.
이 글은 kotlin으로 작성되었습니다. 완성된 샘플은 GitHub - TileService에서 확인할 수 있습니다.
TileService 구현하기
내 앱에 다음과 같이 TileService를 상속받는 서비스를 생성합니다.
@RequiresApi(api = Build.VERSION_CODES.N)
class MyTileService : TileService() {
override fun onTileAdded() {
}
override fun onTileRemoved() {
}
override fun onStartListening() {
}
override fun onStopListening() {
}
override fun onClick() {
}
companion object {
val TAG = MyTileService::class.java.simpleName
}
}
각각의 메소드에 대한 설명은 다음과 같습니다.
- onTileAdded() : Quick Settings에 Tile이 추가될 때 호출됩니다.
- onTileRemoved() : Quick Settings에 Tile이 제거될 때 호출됩니다.
- onClick() : Tile을 클릭했을 때 호출 됩니다.
- onStartListening() : Tile에 대한 변화가 있을 때 호출됩니다. onClick() 이전에 호출됩니다.
- onStartListening() : Tile에 대한 변화가 있을 때 호출됩니다. onClick() 이후에 호출됩니다.
Manifest에 TileService 등록
앱의 AndroidManifest.xml에 다음과 같이 서비스를 등록합니다.
<service
android:name=".MyTileService"
android:label="Cloud"
android:icon="@drawable/ic_cloud"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
각각의 속성의 역할은 다음과 같습니다.
android:label
: Quick Settings에 보이는 이름입니다.android:icon
: Quick Settings에 보이는 아이콘입니다.android:permission
: Quick Settings만 내 서비스를 사용할 수 있도록 퍼미션을 설정해줘야 합니다.intent-filter
의android:name
: Quick Settings이 TileService를 찾을 때 이 action으로 찾습니다.android.service.quicksettings.action.QS_TILE
을 Action으로 설정하지 않으면 Quick Settings가 내 앱의 TileService를 찾을 수 없습니다.
Icon은 흰색으로 만드는 것이 좋습니다. Tile을 활성화하거나 비활성화할 때 Quick Settings가 Tint로 색을 변경하기 때문입니다.
기본적인 아이콘들은 File -> New -> Image Asset
에서 쉽게 만들 수 있습니다.
Tile을 Quick Settings에 추가하기
지금까지 TileService를 생성하고 앱에 등록도 하였습니다.
이제 Quick Settings에 내 앱의 Tile을 추가할 수 있습니다.
아래 화면에서 왼쪽 하단의 Pen 모양의 아이콘을 누릅니다.
그럼 내 앱의 Tile이 보입니다. 이것을 드래그해서 Quick Settings에 추가하면 됩니다.
다시 Quick Settings 화면으로 돌아가면 추가된 것을 볼 수 있습니다.
이 때 Tile을 클릭해도 On/Off 되는 것처럼 아이콘 색이 변경되지 않습니다.
Tile이 클릭될 때 상태를 변경해줘야 아이콘의 색이 변경됩니다.
Tile 상태 변경
Tile의 상태는 3가지 입니다.
STATE_ACTIVE
: 활성화된 상태입니다. On 또는 Enable과 같습니다.STATE_INACTIVE
: 비활성화된 상태입니다. Off 또는 Disable과 같습니다.STATE_UNAVAILABLE
: 사용 불가능한 상태입니다. 이 상태에서는 클릭할 수 없습니다.
왼쪽부터 ACTIVE, INACTIVE, UNAVAILABLE 상태에 따른 Tile의 아이콘입니다.
Tile이 Quick Settings에 추가되면 onTileAdded()
이 호출되며 이 때 다음과 같이 초기값을 설정할 수 있습니다.
override fun onTileAdded() {
qsTile.state = Tile.STATE_INACTIVE
qsTile.updateTile()
}
Tile의 state
를 변경하면 꼭 updateTile()
를 호출해야 합니다. 그렇지 않으면 Tile의 아이콘 색이 변하지 않습니다.
Tile Click 이벤트 처리
Tile을 클릭하면 onClick()
이 호출되며, 이 때 Tile의 state를 변경할 수 있습니다.
다음과 같이 클릭할 때마다 Tile의 상태가 Toggle되도록 하였습니다.
override fun onClick() {
when (qsTile.state) {
Tile.STATE_ACTIVE -> {
Log.d(TAG, "Current State is STATE_ACTIVE. change to STATE_INACTIVE")
qsTile.state = Tile.STATE_INACTIVE
}
Tile.STATE_INACTIVE -> {
Log.d(TAG, "Current State is STATE_INACTIVE. change to STATE_ACTIVE")
qsTile.state = Tile.STATE_ACTIVE
}
}
qsTile.updateTile()
}
또한, Tile의 State를 변경하는 것 외에 다른 작업을 수행하도록 코드를 추가할 수 있습니다.
Lockscreen에서 Quick Settings가 열렸는지 확인
isLocked
는 Lockscreen이 화면에 보이는 상태인지 알려줍니다. 만약 true를 리턴한다면 현재 Lockscreen에서 Quick settings를 열었다고 생각할 수 있습니다.
Lockscreen에서 다른 동작을 수행해야 한다면 다음과 같이 구현할 수 있습니다.
override fun onClick() {
Log.d(TAG, "isLocked: $isLocked")
if (isLocked) {
// ...
}
}
정리
내 앱에서 TileService를 구현한다면 Quick Settings에 Tile을 등록할 수 있습니다. 특별히 어려운 것은 없고 Manifest에 약속된 형태로 정의를 하면 됩니다. Tile이 클릭되었을 때 상태를 변경해주고, 필요한 작업을 처리하도록 구현하면 됩니다.
이 글에서 사용된 예제는 GitHub - TileService에서 확인할 수 있습니다.
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력