이 도움말에서는 VHAL에서 로터리 입력을 처리하고 로터리 서비스를 포함하도록 빌드를 구성하는 방법과 모든 앱에서 로터리 환경을 맞춤설정하는 방법을 설명합니다. OEM 제공 런처와 같은 사전 설치된 OEM 앱은 자동차 UI 라이브러리(car-ui-library)를 참고하세요.
VHAL
로터리 컨트롤러는 다음 작업을 지원합니다.
- 위, 아래, 왼쪽, 오른쪽으로 조금씩 이동
- 시계 방향과 시계 반대 방향으로 회전
- 가운데 버튼 누르기
- 뒤로 버튼 누르기
- 홈 버튼 누르기
- 전화, 미디어와 같은 기타 버튼 누르기
시스템 속성과 이에 상응하는 int32Values
에 관한 문서는 hardware/interfaces/automotive/vehicle/2.0/types.hal
을 참고하세요.
VHAL은 다음 작업을 처리해야 합니다.
조금씩 이동
사용자가 로터리 컨트롤러를 오른쪽으로 밀면 VHAL은 다음 int32Values
와 함께 HW_KEY_INPUT
속성을 사용하여 Android에 이벤트를 전송해야 합니다.
ACTION_DOWN
KEYCODE_SYSTEM_NAVIGATION_RIGHT
- 타겟 디스플레이
사용자가 로터리 컨트롤러에서 손을 떼면 VHAL은 ACTION_UP
과 함께 같은 속성과 키 코드를 사용해야 합니다. 다른 방향으로 조금씩 이동하는 경우 상응하는 키 코드를 사용해야 합니다.
대각선에 적용되는 키 코드는 없지만 하드웨어에서 대각선을 지원하면 VHAL은 수평과 수직 이벤트를 결합하여 대각선을 생성할 수 있습니다. 예를 들어 위로 조금씩 이동과 왼쪽으로 조금씩 이동은 다음과 같이 표시됩니다.
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
어떤 순서로든(또는 이후에) 로터리 컨트롤러에서 손을 떼면 다음과 같이 표시됩니다.
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
사용자는 로터리 컨트롤러에서 손을 떼기 전에 직각 방향으로 컨트롤러를 밀 수 있습니다. 다음 시나리오를 예로 들어 보겠습니다.
![직각 방향](https://source.android.google.cn/static/docs/devices/automotive/images/rotary_06.png?authuser=19&hl=ko)
그러면 다음과 같은 이벤트 시퀀스가 생성됩니다.
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
로터리 컨트롤러가 한 방향으로 유지되는 동안에는 repeat 이벤트가 생성되면 안 됩니다.
회전
사용자가 로터리 컨트롤러를 시계 방향으로 1디텐트(클릭) 회전하면 VHAL은 다음 int32Values
와 함께 HW_ROTARY_INPUT
속성을 사용하여 Android에 이벤트를 전송해야 합니다.
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- 1디텐트
- 타겟 디스플레이
이벤트의 타임스탬프는 경과 시간(나노초)으로 설정해야 합니다.
시계 반대 방향으로 1디텐트 회전하면 같은 이벤트를 생성하지만 디텐트 수는 -1입니다.
빠르게 연속해서 같은 방향으로 여러 디텐트를 회전하면 VHAL은 디텐트를 단일 이벤트로 결합하여 시스템이 이벤트로 과부하되지 않도록 해야 합니다.
이 경우 이벤트의 타임스탬프는 첫 번째 회전 디텐트가 발생한 시점이어야 합니다.
int32Values
에는 연속적인 회전 디텐트 간의 나노초 수가 포함되어야 합니다.
다음과 같은 회전 시퀀스를 예로 들 수 있습니다.
- t0 시간에 사용자가 시계 반대 방향으로 1디텐트 회전했습니다.
- t0 + 5ns 시간에 사용자가 시계 반대 방향으로 1디텐트 회전했습니다.
- t0 + 8ns 시간에 사용자가 시계 반대 방향으로 1디텐트 회전했습니다.
그러면 다음 이벤트가 생성됩니다.
- 속성:
HW_ROTARY_INPUT
- 타임스탬프:
t0
int32Values
:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- -3(시계 반대 방향으로 3디텐트)
- 타겟 디스플레이
- 첫 번째와 두 번째 디텐트 사이에 5ns
- 두 번째와 세 번째 디텐트 사이에 3ns
가운데 버튼
사용자가 가운데 버튼을 누르면 VHAL은 다음 int32Values
와 함께 HW_KEY_INPUT
속성을 사용하여 Android에 이벤트를 전송해야 합니다.
ACTION_DOWN
KEYCODE_DPAD_CENTER
- 타겟 디스플레이
사용자가 로터리 컨트롤러에서 손을 떼면 VHAL은 ACTION_UP
과 같은 속성과 키 코드를 사용해야 합니다.
가운데 버튼을 누른 상태에서는 repeat 이벤트를 생성하지 마세요.
뒤로 버튼
사용자가 뒤로 버튼을 누르면 VHAL은 다음 int32Values
와 함께 HW_KEY_INPUT
속성을 사용하여 Android에 이벤트를 전송해야 합니다.
ACTION_DOWN
KEYCODE_BACK
- 타겟 디스플레이
사용자가 로터리 컨트롤러에서 손을 떼면 VHAL은 ACTION_UP
과 같은 속성과 키 코드를 사용해야 합니다.
가운데 버튼을 누르고 있는 동안에는 repeat 이벤트를 생성하면 안 됩니다.
홈 버튼
뒤로 버튼처럼 홈 버튼을 처리하되 KEYCODE_BACK
대신 KEYCODE_HOME
을 사용합니다.
기타 버튼
로터리 컨트롤러에 추가 버튼이 포함되어 있는 경우 VHAL은 OEM이 원하는 대로 처리할 수 있습니다. Android의 관점에서는 로터리의 일부로 간주되지 않기 때문입니다.
일반적으로 뒤로 버튼과 홈 버튼처럼 처리되지만 다른 키 코드를 사용합니다.
예를 들면 KEYCODE_CALL
또는 KEYCODE_MUSIC
이 있습니다.
빌드 구성
로터리 탐색은 RotaryService
라는 접근성 서비스에서 제공합니다.
이 서비스를 기기의 시스템 이미지에 포함하려면 다음 줄을 makefile에 추가하세요.
PRODUCT_PACKAGES += CarRotaryController
디버그 빌드에 다음 패키지를 포함하는 것도 좋습니다.
RotaryPlayground
: 로터리를 위한 참조 앱입니다(RotaryPlayground 참고).RotaryIME
: 데모 로터리 IME입니다(입력 방식 편집기(IME) 참고).CarRotaryImeRRO
:RotaryIME
의 오버레이입니다.
로터리 서비스는 기기가 부팅될 때와 사용자가 전환될 때 자동으로 사용 설정됩니다. 그러면 사용자가 설정 중에 로터리 컨트롤러를 사용할 수 있습니다.
로터리 컨트롤러가 있는 자동차와 없는 자동차에 같은 빌드를 사용한다면 위와 같이 CarRotaryController
를 추가하여 필요한 코드가 빌드에 포함되도록 합니다. 로터리 컨트롤러가 없는 자동차에서 로터리 서비스가 사용 설정되지 않도록 하려면 packages/services/Car/service
의 rotaryService
문자열 리소스를 빈 문자열로 오버레이하는 고정 RRO를 만듭니다. 로터리 기기와 비 로터리 기기에 같은 빌드를 사용하지만 제품 구성은 별도로 있습니다. 비 로터리 기기에만 오버레이가 포함됩니다.
맞춤설정
OEM은 다음 위치에서 리소스 오버레이를 통해 포커스 찾기 로직, 포커스 하이라이트, 일부 추가 항목을 맞춤설정할 수 있습니다.
- car-ui-library는
packages/apps/Car/libs/car-ui-lib
에 있습니다. RotaryService
는packages/apps/Car/RotaryController
에 있습니다.Core
는frameworks/base/core
에 있습니다.
조금씩 이동 기록
OEM은 두 유형의 조금씩 이동 기록을 각각 사용 설정할지 여부, 그리고 사용 설정된 경우 캐시 크기와 만료 정책을 구성할 수 있습니다. 이 작업은 모두 다양한 car-ui-library 리소스를 재정의하여 실행됩니다.
포커스 기록 캐시
(Android 11 QPR3, Android 11 Car, Android 12)
이 FocusArea
별 캐시는 FocusArea
내에서 가장 최근에 포커스가 맞춰진 뷰를 저장하므로 FocusArea
로 다시 조금씩 이동할 때 포커스를 맞출 수 있습니다.
이 캐시는 다음 car-ui-library 리소스를 오버레이하여 구성할 수 있습니다.
-
car_ui_focus_history_cache_type
:- 캐시가 사용 중지되었습니다.
- 캐시가 일정 시간이 지나면 만료됩니다(아래 참고).
- 캐시가 만료되지 않습니다.
car_ui_focus_history_expiration_period_ms
: 캐시 유형이 2로 설정된 경우 캐시가 만료되기까지의 시간(밀리초 단위)입니다(위 참고).
FocusArea 기록 캐시
(Android 11 QPR3, Android 11 Car, Android 12)
이 캐시는 조금씩 이동 기록을 저장하므로 반대 방향으로 조금씩 이동하면 같은 FocusArea
에 포커스를 반환할 수 있습니다. 이 캐시는 다음 car-ui-library 리소스를 오버레이하여 구성할 수 있습니다.
-
car_ui_focus_area_history_cache_type
:- 캐시가 사용 중지되었습니다.
- 캐시가 일정 시간이 지나면 만료됩니다(아래 참고).
- 캐시가 만료되지 않습니다.
car_ui_focus_area_history_expiration_period_ms
: 캐시 유형이 2로 설정된 경우 캐시가 만료되기까지의 시간(밀리초 단위)입니다(위 참고).car_ui_clear_focus_area_history_when_rotating
: 사용자가 컨트롤러를 회전할 때 캐시를 무효화할지 여부입니다.
회전
(Android 11 QPR3, Android 11 Car, Android 12)
OEM은 RotaryService
에서 두 정수 리소스를 재정의하여 회전 가속(예: 마우스 가속)이 있는지를 지정할 수 있습니다.
rotation_acceleration_3x_ms
: Google이 회전 디텐트와 관련해 컨트롤러 회전을 가속화해야 하는지 판단하는 데 사용되는 시간 간격(밀리초)입니다. 이 회전 디텐트와 이전 회전 디텐트 사이의 간격이 이 값보다 작으면 3디텐트 회전으로 간주됩니다. 3배 가속을 사용 중지하려면 2147483647로 설정합니다.rotation_acceleration_2x_ms
:rotation_acceleration_3x_ms
와 유사하며 2배 가속에 사용됩니다. 2배 가속을 사용 중지하려면 이 값을2147483647
로 설정합니다.
가속은 VHAL에 필요한 대로 각 회전 디텐트에 개별 타임스탬프가 있을 때 가장 잘 작동합니다. 개별 타임스탬프를 사용할 수 없다면 RotaryService
는 회전 디텐트의 간격이 균일하다고 간주합니다.
/** * Property to feed H/W rotary events to android * * int32Values[0] : RotaryInputType identifying which rotary knob rotated * int32Values[1] : number of detents (clicks), positive for clockwise, * negative for counterclockwise * int32Values[2] : target display defined in VehicleDisplay. Events not * tied to specific display must be sent to * VehicleDisplay#MAIN. * int32values[3 .. 3 + abs(number of detents) - 2]: * nanosecond deltas between pairs of consecutive detents, * if the number of detents is > 1 or < -1 * * VehiclePropValue.timestamp: when the rotation occurred. If the number of * detents is > 1 or < -1, this is when the * first detent of rotation occurred. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @data_enum RotaryInputType * @access VehiclePropertyAccess:READ */ HW_ROTARY_INPUT = ( 0x0A20 | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:INT32_VEC | VehicleArea:GLOBAL),
포커스 하이라이트
OEM은 Android 프레임워크의 기본 포커스 하이라이트와 car-ui-library의 여러 포커스 하이라이트 리소스를 재정의할 수 있습니다.
기본 포커스 하이라이트
Android 프레임워크는 selectableItemBackground
속성을 통해 기본 포커스 하이라이트를 제공합니다. Theme.DeviceDefault
에서 이 속성은 Core
의 item_background.xml
을 참조합니다. OEM은 item_background.xml
을 오버레이하여 기본 포커스 하이라이트 드로어블을 변경할 수 있습니다.
이 드로어블은 일반적으로 android:state_focused
, android:state_pressed
등 다양한 상태 조합에 따라 배경을 조정하는 StateListDrawable
이어야 합니다. 사용자가 로터리 컨트롤러를 사용하여 뷰에 포커스를 맞추면 android:state_focused
는 true
이지만 android:state_pressed
는 false
입니다. 그런 다음 사용자가 로터리 컨트롤러의 가운데 버튼을 누르면 사용자가 버튼을 누르고 있는 동안 android:state_focused
와 android:state_pressed
는 모두 true
가 됩니다.
사용자가 버튼에서 손을 떼면 android:state_focused
만 true
로 유지됩니다.
car-ui-library는 Theme.DeviceDefault
에서 파생된 테마를 사용합니다. 따라서 이 오버레이는 이 라이브러리를 사용하는 앱과 Theme.DeviceDefault
에서 파생된 테마를 사용하는 앱에 영향을 미칩니다. Theme.Material
과 같이 관련 없는 테마를 사용하는 앱에는 영향을 미치지 않습니다.
car-ui-library의 포커스 하이라이트 리소스
OEM은 여러 car-ui-library 리소스를 재정의하여 직사각형이 아닌(예: 원형 또는 알약 모양) 포커스 하이라이트가 있는 뷰와 Theme.DeviceDefault
에서 파생되지 않은 테마를 사용하는 앱에서 포커스 하이라이트가 표시되는 방식을 제어할 수 있습니다. 포커스 하이라이트가 기본 포커스 하이라이트 드로어블과 일치하도록 이러한 리소스를 오버레이해야 합니다.
(Android 11 QPR3, Android 11 Car, Android 12)
다음 리소스는 뷰에 포커스가 있지만 뷰를 누르지 않은 경우를 나타내는 데 사용됩니다.
car_ui_rotary_focus_fill_color
: 채우기 색상car_ui_rotary_focus_stroke_color
: 윤곽선 색상car_ui_rotary_focus_stroke_width
: 윤곽선 두께
(Android 11 QPR3, Android 11 Car, Android 12)
다음 리소스는 뷰에 포커스가 있고 뷰를 누른 경우를 나타내는 데 사용됩니다.
car_ui_rotary_focus_pressed_fill_color
: 채우기 색상car_ui_rotary_focus_pressed_stroke_color
: 윤곽선 색상car_ui_rotary_focus_pressed_stroke_width
: 윤곽선 두께
다음 예와 같이 버튼은 배경 색상을 단색으로 하여 사용자의 주의를 끌기도 합니다. 이로 인해 포커스 하이라이트가 잘 표시되지 않을 수 있습니다.
![배경이 단색인 버튼](https://source.android.google.cn/static/docs/devices/automotive/images/rotary_05.png?authuser=19&hl=ko)
이 경우 개발자는 보조 색상을 사용하여 맞춤 포커스 하이라이트를 지정할 수 있습니다.
- (Android 11 QPR3, Android 11 Car, Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12)
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
모든 색상은 투명할 수 있고 예를 들어 채우기만 원하거나 윤곽선만 원할 경우 두 치수 모두 0이 될 수 있습니다.
FocusArea 하이라이트
(Android 11 QPR3, Android 11 Car, Android 12)
FocusArea
는 하위 요소 중 하나에 포커스가 있을 때 두 가지 하이라이트 유형을 그릴 수 있습니다. 원한다면 둘 다 함께 사용할 수 있습니다. 이 기능은 AOSP에서 기본적으로 사용 중지되어 있지만 car-ui-library 리소스를 재정의하여 사용 설정할 수 있습니다.
car_ui_enable_focus_area_foreground_highlight
:FocusArea
와 그 하위 요소 위에 하이라이트를 그립니다. AOSP에서 이 드로어블은FocusArea
주변의 윤곽선입니다. OEM은car_ui_focus_area_foreground_highlight
드로어블을 재정의할 수 있습니다.car_ui_enable_focus_area_background_highlight
:FocusArea
위 그러나 그 하위 요소 뒤에 하이라이트를 그립니다. AOSP에서 이 드로어블은 단색 채우기입니다. OEM은car_ui_focus_area_background_highlight
드로어블을 재정의할 수 있습니다.
입력 방식 편집기(IME)
입력 방식 편집기(IME)는 입력 방법입니다. 터치 키보드를 예로 들 수 있습니다.
(Android 11 QPR3, Android 11 Car, Android 12)
OEM은 RotaryService
의 default_touch_input_method
문자열 리소스를 오버레이하여 터치 기반 IME의 ComponentName
을 지정해야 합니다. 예를 들어 OEM이 Android Automotive와 함께 제공된 IME를 사용하는 경우 com.google.android.apps.automotive.inputmethod/.InputMethodService
를 지정해야 합니다.
(Android 11 QPR3, Android 11 Car, Android 12)
OEM이 로터리 전용으로 IME를 만든 경우 rotary_input_method
리소스에서 ComponentName
을 지정해야 합니다. 이 리소스가 오버레이되면 사용자가 로터리 컨트롤러의 조금씩 이동, 회전, 가운데 버튼을 통해 헤드 단위와 상호작용할 때마다 지정된 IME가 사용됩니다. 사용자가 화면을 터치하면 이전 IME가 사용됩니다. 뒤로 버튼(및 로터리 컨트롤러의 기타 버튼)은 IME 선택에 영향을 미치지 않습니다. 이 리소스가 오버레이되지 않으면 IME 전환은 발생하지 않습니다. Carboard는 로터리를 지원하지 않으므로 OEM이 로터리 IME를 제공하지 않았다면 사용자는 로터리 컨트롤러를 통해 텍스트를 입력할 수 없습니다.
RotaryIME
는 데모 로터리 IME입니다. 기본적이긴 하지만 위에서 설명한 자동 IME 전환을 시도해 보기에 충분합니다. RotaryIME
의 소스 코드는 packages/apps/Car/tests/RotaryIME/
에서 확인할 수 있습니다.
화면 밖으로 조금씩 이동
기본적으로 사용자가 화면 가장자리에서 조금씩 이동하려고 하면 아무 일도 발생하지 않습니다. OEM은 다음 조합을 지정하여 4방향 각각에 발생해야 하는 작업을 구성할 수 있습니다.
AccessibilityService
에서 정의한 전역 작업. 예:GLOBAL_ACTION_BACK
- 키 코드(예:
KEYCODE_BACK
) - URL로 표시되는 활동을 실행할 인텐트
(Android 11 QPR3, Android 11 Car, Android 12)RotaryService
에서 다음 배열 리소스를 오버레이하여 지정됩니다.
off_screen_nudge_global_actions
: 사용자가 화면 가장자리에서 위, 아래, 왼쪽, 오른쪽으로 조금씩 이동할 때 실행할 전역 작업의 배열입니다. 이 배열의 관련 요소가 -1이면 전역 작업이 실행되지 않습니다.off_screen_nudge_key_codes
: 사용자가 화면 가장자리에서 위, 아래, 왼쪽, 오른쪽으로 조금씩 이동할 때 삽입할 클릭 이벤트의 키 코드 배열입니다. 이 배열의 관련 요소가 0(KEYCODE_UNKNOWN
)이면 이벤트가 삽입되지 않습니다.off_screen_nudge_intents
: 사용자가 화면 가장자리에서 위, 아래, 왼쪽, 오른쪽으로 조금씩 이동할 때 활동을 실행할 인텐트의 배열입니다. 이 배열의 관련 요소가 비어 있으면 활동이 실행되지 않습니다.
기타 구성
다음 RotaryService
리소스를 오버레이해야 합니다.
- (Android 11 QPR3, Android 11 Car, Android 12)
config_showHeadsUpNotificationOnBottom
: 상단이 아닌 하단에 사전 경고 알림을 표시해야 하는지 나타내는 부울 값입니다. 이 값은frameworks/base/packages/CarSystemUI/res/values/config.xml
의config_showHeadsUpNotificationOnBottom
부울 리소스와 같은 값이어야 합니다. - (Android 11 QPR3, Android 11 Car, Android 12)
notification_headsup_card_margin_horizontal
: 사전 경고 알림 창의 왼쪽과 오른쪽 여백입니다.packages/apps/Car/Notification/res/values/dimens.xml
의notification_headsup_card_margin_horizontal
치수 리소스와 같은 값이어야 합니다. - (Android 12)
excluded_application_overlay_window_titles
: 오버레이 창으로 간주하면 안 되는 창 제목의 배열입니다. 여기에는TaskViews
나TaskDisplayAreas
를 나타내는 애플리케이션 창 제목이 포함되어야 합니다. 기본적으로 이 목록에는 '지도'만 포함됩니다.
다음 RotaryService
리소스를 오버레이할 수 있습니다.
- (Android 11 QPR3, Android 11 Car, Android 12)
long_press_ms
: 길게 누르기를 트리거하기 위해 가운데 버튼을 누르고 있어야 하는 시간(밀리초)을 나타내는 정숫값입니다. 0은 시스템 기본 길게 누르기 제한 시간을 사용해야 함을 나타냅니다. 기본값입니다.