WindowManager 확장 프로그램

Jetpack WindowManager 라이브러리를 사용하면 애플리케이션 개발자가 새로운 기기 폼 팩터와 멀티 윈도우 환경을 지원할 수 있습니다.

WindowManager 확장 프로그램(확장 프로그램)은 선택 후 사용하는 Android 플랫폼 모듈로, 이 모듈을 통해 다양한 Jetpack WindowManager 기능을 사용할 수 있습니다. 이 모듈은 AOSP frameworks/base/libs/WindowManager/Jetpack에 구현되어 있으며 WindowManager 기능을 지원하는 기기에 제공됩니다.

확장 프로그램 모듈 배포

확장 프로그램은 .jar 라이브러리로 컴파일되며 기기 makefile에 확장 프로그램이 사용 설정된 경우 기기의 system_ext 파티션에 배치됩니다.

기기에서 확장 프로그램을 사용 설정하려면 다음을 제품 기기 makefile에 추가하세요.

$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)

이렇게 하면 androidx.window.extensionsandroidx.window.sidecar 패키지가 기기에서 사용 설정되고 persist.wm.extensions.enabled 속성이 설정됩니다. makefile에 이러한 패키지를 포함하면 etc/permissions/에 선언이 위치하게 되며 애플리케이션 프로세스에서 패키지를 사용할 수 있습니다. 일반적으로 확장 프로그램 모듈은 Jetpack WindowManager 라이브러리에서 사용할 때 런타임에 애플리케이션 프로세스에 로드되고 애플리케이션 프로세스의 일부로 실행됩니다. 이렇게 하면 아래 그림에서 보는 바와 같이 확장 프로그램 모듈의 작업이 클라이언트 측 프레임워크 코드와 비슷해집니다.

그림 1. 플랫폼 코드와 유사하게 애플리케이션 프로세스에 로드된 WindowManager 확장 프로그램

androidx.window.extensions 모듈은 현재 활발하게 개발 중인 확장 프로그램 모듈입니다. androidx.window.sidecar 모듈은 Jetpack WindowManager의 초기 버전과의 호환성을 위해 포함된 레거시 모듈이며 sidecar는 더 이상 유지관리되지 않습니다.

다음 그림은 androidx.window.extensionsandroidx.window.sidecar 중 어느 모듈을 사용할지 결정하는 로직을 보여줍니다.

그림 2. androidx.window.extensionsandroidx.window.sidecar 중 어느 모듈에 액세스할지 결정하는 결정 트리

확장 프로그램 모듈

확장 프로그램은 현재 대형 화면이 있는 폴더블 기기 및 외부 화면에 윈도잉을 지원하는 기기에 윈도잉 기능을 제공합니다. 기능 영역에는 다음이 포함됩니다.

확장 프로그램의 OEM 구현은 호환성 정의 문서(CDD) 7.1.1.1에서 명시적으로 요구하는 기능이 아닌 한 기기 하드웨어가 해당 기능을 지원하지 않는 경우 null 구성요소 또는 WindowExtensions 인터페이스 메서드의 default/stub 구현을 사용하는 구성요소를 제공할 수 있습니다.

확장 프로그램과 Jetpack API

WindowManager 확장 프로그램 모듈은 공개 플랫폼 API 외에 자체 API 노출 영역을 제공합니다. 확장 프로그램 모듈은 Jetpack WindowManager(androidx.window)가 컴파일 시 모듈에 링크될 수 있도록 개발자 대상이 아닌 androidx.window.extensions Jetpack 라이브러리에 공개적으로 개발되었습니다. 확장 프로그램 API 노출 영역은 일반적으로 하위 수준 API로 제공됩니다.

확장 프로그램에서 제공하는 API는 Jetpack WindowManager 라이브러리에서만 사용해야 합니다. 확장 프로그램 API를 애플리케이션 개발자가 직접 호출해서는 안 됩니다. 올바르게 기능할 수 있도록 하기 위해 확장 프로그램 라이브러리를 Gradle 빌드 파일에 애플리케이션 종속 항목으로 추가하면 안 됩니다. 확장 프로그램 라이브러리를 사전에 애플리케이션에 직접 컴파일하면 안 됩니다. 대신 사전 컴파일된 확장 프로그램 클래스와 런타임 시 제공되는 확장 프로그램 클래스가 혼합되어 로드되는 것을 막기 위해 런타임 로드를 사용하세요.

Jetpack WindowManager(androidx.window)는 WindowManager 확장 프로그램 기능의 API를 포함한 개발자 대상의 공개 API를 제공하며, 애플리케이션 종속 항목으로 추가되어야 합니다. WindowManager 라이브러리는 확장 프로그램을 자동으로 애플리케이션 프로세스에 로드하고 하위 수준 확장 프로그램 API를 상위 수준 추상화 인터페이스와 더 집중된 인터페이스로 래핑합니다. WindowManager Jetpack API는 최신 Android 애플리케이션 개발 표준을 따르고 있으며 다른 AndroidX 라이브러리를 사용하는 코드베이스와 잘 통합하여 편리한 상호 운용성을 제공합니다.

확장 프로그램 버전과 업데이트

확장 프로그램 모듈은 Android 플랫폼의 연간 업데이트 또는 분기별 업데이트와 함께 업데이트될 수 있습니다. 분기별 업데이트를 사용하면 확장 프로그램 API 수준이 Android 플랫폼 API 업데이트 사이에 증가되며 이를 통해 더 빠른 반복이 가능하고 하드웨어 출시 시점에 가까운 새로운 기능에 대한 공식 API 액세스를 추가할 기회를 OEM에 제공할 수 있습니다.

다음 표에는 다양한 Android 출시에 대한 androidx.window.extensions API 버전이 나와 있습니다.

Android 플랫폼 버전 WindowManager 확장 프로그램 API 수준 androidx.window.extensions API 버전
14 3 1.2.0
13 QPR3 2 1.1.0
13 1 1.0.0
12L 1 1.0.0

표 1. Android 플랫폼 버전과 AOSP WindowManager 확장 프로그램 버전 간의 대응

확장 프로그램 API 수준(2열)은 기존의 안정적인 API 노출 영역(3열) 버전이 증가할 때마다 증가합니다.

OEM에서 제공하는 모든 기본 플랫폼 소프트웨어 버전은 위의 표에 정의된 확장 프로그램 버전 이상이어야 합니다. 오래된 버전의 플랫폼을 확장 프로그램의 최신 버전과 함께 제공할 수는 있지만, 이런 경우 일반적으로 기능을 지원하기 위해 WindowManager 핵심을 광범위하게 수정해야 합니다. 구현은 대응되는 오래된 플랫폼 버전의 CTS 테스트를 통해 자동으로 인증되지 않습니다.

하위 호환성과 상위 호환성

Jetpack WindowManager는 빈번한 API 수준 업데이트, 빠른 API 진화, 하위 호환성을 다루는 복잡도를 처리합니다. 라이브러리 코드가 애플리케이션 프로세스에서 실행되면 라이브러리는 선언된 확장 프로그램 API 수준을 확인하고 선언된 수준에 따라 기능에 대한 액세스를 제공합니다.

애플리케이션이 런타임에 비정상 종료되는 것을 방지하기 위해, WindowManager는 선언된 확장 프로그램 API 수준에 따라 사용 가능한 확장 프로그램 API의 런타임 Java 리플렉션 검사도 실행합니다. 불일치가 있는 경우 WindowManager는 확장 프로그램을 부분적으로 또는 전체적으로 사용 중지할 수 있고 관련 기능을 애플리케이션에서 사용할 수 없는 것으로 신고할 수 있습니다.

WindowManager 확장 프로그램은 확장 프로그램 기능 구현에서 WindowManager의 핵심인 DeviceStateManager와 기타 시스템 서비스를 호출하기 위해 비공개 플랫폼 API를 사용하는 system_ext 모듈로 구현됩니다.

확장 프로그램 버전에 대응하는 분기별 또는 연간 Android 플랫폼 버전이 완료되어 출시되기 전에는 확장 프로그램의 출시 전 버전과 호환성이 유지되지 않을 수도 있습니다. 확장 프로그램 API의 전체 기록을 보려면 출시 브랜치의 window:extensions:extensions API 텍스트 파일을 참고하세요.

새 확장 프로그램 버전은 상위 호환성을 유지하기 위해 애플리케이션에 컴파일된 WindowManager의 기존 버전과 계속 호환되어야 합니다. 이를 보장하기 위해 확장 프로그램 API의 새 버전은 새로운 API를 추가하기만 하고 기존 API를 삭제하지는 않습니다. 따라서, 기존의 WindowManager 버전을 사용하는 애플리케이션은 앱이 컴파일된 기존의 확장 프로그램 API를 계속 사용할 수 있습니다.

CTS 인증을 통해 기기에 선언된 모든 확장 프로그램 API 버전에 대해 모든 API와 이전 버전이 존재하고 기능하도록 보장할 수 있습니다.

성능

확장 프로그램 모듈은 Android 14(API 수준 34)부터 기본적으로 비bootclasspath 시스템 클래스 로더에 캐시됩니다. 따라서 앱 시작 시 모듈을 메모리에 로드해도 성능에 영향을 미치지 않습니다. 개별 모듈 기능을 사용하면 클라이언트와 서버 간에 추가 IPC 호출이 실행될 때 앱의 성능 특성에 약간의 영향을 미칠 수 있습니다.

모듈

활동 삽입

활동 삽입 구성요소는 애플리케이션이 상위 애플리케이션 경계 내에 활동 창 표시를 구성할 수 있도록 하는 여러 기능을 제공합니다. 여기에는 두 개의 활동을 동시에 여러 창 레이아웃에 나란히 표시하는 것과 레거시 애플리케이션에 맞게 대형 화면을 최적화하는 것이 포함됩니다.

활동 삽입 구성요소는 기본 화면 크기가 sw600 dp 이상인 모든 기기에서 사용할 수 있어야 합니다. 또한, 활동 삽입은 런타임에 외부 화면이 연결되는 경우 애플리케이션이 대형 화면에 표시될 수 있을 때 외부 화면 연결을 지원하는 기기에서 사용 설정되어야 합니다.

기기 설정

활동 프로그램 모듈 배포 섹션에서 설명한 대로 확장 프로그램 모듈을 사용 설정하는 것 외에 특별한 기기 구성은 필요하지 않습니다. 멀티 윈도우 모드를 지원하는 모든 기기에서 확장 프로그램을 사용 설정하는 것이 타당합니다. 향후 Android 버전에서는 일반적인 휴대기기와 대형 화면 기기 구성에서 확장 프로그램을 요구할 수 있습니다.

창 레이아웃 정보

창 레이아웃 정보 구성요소는 폴더블 기기 힌지가 애플리케이션 창을 넘을 때 힌지의 위치와 상태를 인식합니다. 창 레이아웃 정보를 사용하면 애플리케이션이 폴더블의 탁자 모드에서 최적화된 레이아웃에 반응하고 이를 표시할 수 있습니다. 자세한 사용법은 앱에서 접힌 상태 인식을 참고하세요.

분리되어 있거나 연속된 화면 패널 영역을 연결하는 힌지가 포함된 폴더블 Android 기기는 힌지에 대한 정보를 WindowLayoutComponent를 통해 애플리케이션에 제공해야 합니다.

힌지의 위치와 경계는 API에 전달되는 Context에서 인식하는 애플리케이션 창에 대해 상대적인 위치와 경계로 보고되어야 합니다. 애플리케이션 창 경계는 힌지 경계와 교차하지 않으며 힌지의 DisplayFeature는 보고되면 안 됩니다. 또한, 사용자가 멀티 윈도우 모드 또는 호환성 레터박스 모드에서 애플리케이션 창을 자유롭게 이동할 수 있을 때와 같이 창의 위치가 안정적으로 보고될 수 없을 때 화면 기능을 보고하지 않는 것은 허용됩니다.

접기 기능의 경우 상태 업데이트는 안정적인 상태 간에 힌지 위치를 변경할 때 보고되어야 합니다. 기본적으로 API는 화면이 평평한 상태일 때 FoldingFeature.State.FLAT을 보고해야 합니다. 기기 하드웨어가 안정적인 상태에서 반만 접힌 모드로 있을 수 있다면 API는 FoldingFeature.State.HALF_OPENED를 보고해야 합니다. API에 닫힌 상태는 없습니다. 그런 경우에는 애플리케이션 창이 표시되지 않거나 힌지 경계를 넘지 않기 때문입니다.

기기 설정

접기 기능 구현을 지원하려면 OEM에서 다음을 해야 합니다.

  • DeviceStateManagerService에서 사용하도록 device_state_configuration.xml에서 기기 상태를 설정합니다. DeviceStateProviderImpl.java를 참고하세요.

    DeviceStateProvider 또는 DeviceStatePolicy의 기본 구현이 기기에 적합하지 않다면 맞춤 구현을 사용할 수 있습니다.

  • 확장 프로그램 모듈 배포 섹션에 설명한 대로 확장 프로그램 모듈을 사용 설정합니다.

  • com.android.internal.R.string.config_display_features 문자열 리소스의 화면 기능 위치를 지정합니다(항상 기기 오버레이의 frameworks/base/core/res/res/values/config.xml임).

    문자열의 예상 형식은 다음과 같습니다.

    <type>-[<left>,<top>,<right>,<bottom>]

    typefold 또는 hinge입니다. left, top, right, bottom의 값은 자연스러운 화면 방향에서 화면 좌표 공간의 정수 픽셀 좌표입니다. 구성 문자열은 세미콜론으로 구분된 여러 화면 기능을 포함합니다.

    예:

    <!-- Jetpack WindowManager display features -->
    <string name="config_display_features" translatable="false">fold-[1000,0,1000,2000]</string>
    
  • DeviceStateManager에서 사용되는 내부 기기 상태 식별자 간의 매핑과 com.android.internal.R.array.config_device_state_postures의 개발자에게 전송되는 공개 상태 상수를 정의합니다.

    각 항목의 예상 형식은 다음과 같습니다.

    <device_specific_state_identifier>:<Jetpack WindowManager state identifier>

    지원되는 상태 식별자는 다음과 같습니다.

    • COMMON_STATE_NO_FOLDING_FEATURES = 1: 상태에 보고할 접기 기능이 없습니다. 예를 들어, 내부에 기본 화면이 장착되고 안쪽으로 접는 일반적인 기기의 닫힌 상태가 될 수 있습니다.
    • COMMON_STATE_HALF_OPENED = 2: 접기 기능이 반만 열려 있습니다.
    • COMMON_STATE_FLAT = 3: 접기 기능이 평평합니다. 예를 들어, 내부에 기본 화면이 장착되고 안쪽으로 접는 일반적인 기기의 열린 상태가 될 수 있습니다.
    • COMMON_STATE_USE_BASE_STATE = 1000: Android 14에서는 CommonFoldingFeature.java에 정의된 대로 힌지 상태가 기본 상태를 사용하여 파생되는 에뮬레이션된 상태에 사용할 수 있는 값입니다.

    자세한 내용은 DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)를 참고하세요.

    예:

    <!-- Map of System DeviceState supplied by DeviceStateManager to WindowManager posture.-->
    <string-array name="config_device_state_postures" translatable="false">
        <item>0:1</item>    <!-- CLOSED       : COMMON_STATE_NO_FOLDING_FEATURES -->
        <item>1:2</item>    <!-- HALF_OPENED  : COMMON_STATE_HALF_OPENED -->
        <item>2:3</item>    <!-- OPENED       : COMMON_STATE_FLAT -->
        <item>3:1</item>    <!-- REAR_DISPLAY : COMMON_STATE_NO_FOLDING_FEATURES -->
        <item>4:1000</item> <!-- CONCURRENT   : COMMON_STATE_USE_BASE_STATE -->
    </string-array>
    

창 영역

창 영역 구성요소는 일부 폴더블 및 다중 디스플레이 기기의 추가 화면과 화면 영역에 액세스할 수 있는 일련의 기능을 애플리케이션에 제공합니다.

후면 디스플레이 모드를 사용하면 애플리케이션이 폴더블 기기의 커버 화면에 카메라 미리보기 UI를 표시하므로 셀카 및 동영상 촬영에 기본 기기 카메라를 사용할 수 있습니다. 후면 기기 카메라와 맞는 Android 호환(크기, 밀도, 사용할 수 있는 탐색 어포던스와 같은 속성 측면에서 Android CDD에 정의된 내용) 커버 디스플레이가 있는 기기는 후면 디스플레이 모드 액세스를 제공해야 합니다.

Android 14에서 듀얼 디스플레이 모드를 사용하면 폴더블 기기의 내부 디스플레이에서 실행되는 애플리케이션이 다른 사용자에게 표시되는 커버 디스플레이에 추가 콘텐츠를 표시할 수 있습니다. 예를 들어 커버 디스플레이는 사진을 찍히거나 녹화되는 사람에게 카메라 미리보기를 표시할 수 있습니다.

기기 구성

접기 기능 구현을 지원하려면 OEM에서 다음을 해야 합니다.

  • DeviceStateManagerService에서 사용하도록 device_state_configuration.xml에서 기기 상태를 설정합니다. 자세한 내용은 DeviceStateProviderImpl.java를 참고하세요.

    DeviceStateProviderDeviceStatePolicy 기본 구현이 기기에 적합하지 않다면 맞춤 구현을 사용할 수 있습니다.

  • 열린 모드나 평평한 모드를 지원하는 폴더블 기기의 경우 com.android.internal.R.array.config_openDeviceStates에 해당 상태 식별자를 지정합니다.

  • 접힌 상태를 지원하는 안쪽으로 접는 기기의 경우 com.android.internal.R.array.config_foldedDeviceStates에 해당 상태 식별자를 나열합니다.

  • 반만 접는 상태(힌지가 노트북처럼 반만 열림)를 지원하는 안쪽으로 접는 기기의 경우 해당 상태를 com.android.internal.R.array.config_halfFoldedDeviceStates에 나열합니다.

  • 후면 디스플레이 모드를 지원하는 기기는 다음을 실행해야 합니다.

    • DeviceStateManagercom.android.internal.R.array.config_rearDisplayDeviceStates에 대응하는 상태를 나열합니다.
    • com.android.internal.R.string.config_rearDisplayPhysicalAddress에 후면 디스플레이의 물리적 디스플레이 주소를 지정합니다.
    • 확장 프로그램에서 사용할 상태 식별자를 com.android.internal.R.integer.config_deviceStateRearDisplay에 지정합니다.
    • 애플리케이션에서 사용할 수 있도록 com.android.internal.R.array.config_deviceStatesAvailableForAppRequests에 상태 식별자를 추가합니다.
  • Android 14에서 듀얼(동시 실행) 디스플레이 모드를 지원하는 기기는 다음을 실행해야 합니다.

    • com.android.internal.R.bool.config_supportsConcurrentInternalDisplaystrue로 설정합니다.
    • com.android.internal.R.config_deviceStateConcurrentRearDisplay에 후면 디스플레이의 물리적 디스플레이 주소를 지정합니다.
    • 식별자를 애플리케이션에서 사용할 수 있도록 한 경우 확장 프로그램에서 사용할 상태 식별자를 com.android.internal.R.integer.config_deviceStateConcurrentRearDisplay에 지정합니다.
    • 애플리케이션에서 사용할 수 있도록 com.android.internal.R.array.config_deviceStatesAvailableForAppRequests에 상태 식별자를 추가합니다.

인증

OEM은 일반적인 시나리오에서 예상 동작을 보장하도록 구현을 인증해야 합니다. 테스트 구현을 위해 CTS 테스트와 Jetpack WindowManager를 사용하는 테스트가 OEM에 제공됩니다.

CTS 테스트

CTS 테스트를 실행하려면 CTS 테스트 실행을 참고하세요. Jetpack WindowManager와 관련된 CTS 테스트는 cts/tests/framework/base/windowmanager/jetpack/에 있습니다. 테스트 모듈 이름은 CtsWindowManagerJetpackTestCases입니다.

WindowManager 테스트

Jetpack WindowManager 테스트를 다운로드하려면 Android Jetpack 안내를 따르세요. 테스트는 window:window 모듈 아래 window/window/src/androidTest/에 있습니다.

명령줄에서 window:window 모듈의 기기 테스트를 실행하려면 다음을 진행합니다.

  1. 개발자 옵션이 있고 USB 디버깅이 사용 설정된 기기에 연결합니다.
  2. 컴퓨터에서 기기를 디버그하도록 허용합니다.
  3. Androidx 저장소의 루트 디렉터리에서 셸을 엽니다.
  4. 디렉터리를 framework/support로 변경합니다.
  5. 다음 명령어를 실행합니다. ./gradlew window:window:connectedAndroidTest
  6. 결과를 분석합니다.

Android 스튜디오에서 테스트를 실행하려면 다음을 진행합니다.

  1. Android 스튜디오를 엽니다.
  2. 개발자 옵션이 있고 USB 디버깅이 사용 설정된 기기에 연결합니다.
  3. 컴퓨터에서 기기를 디버그하도록 허용합니다.
  4. 창 모듈의 창 라이브러리 내에서 테스트로 이동합니다.
  5. 테스트 클래스를 열고 편집기 오른쪽에 있는 녹색 화살표를 사용하여 실행합니다.

또는 Android 스튜디오에 테스트 메서드, 테스트 클래스 또는 모듈의 모든 테스트를 실행하도록 구성을 만듭니다.

셸의 출력을 보고 수동으로 결과를 분석할 수 있습니다. 기기가 특정 가정을 충족하지 않으면 일부 테스트는 건너뜁니다. 결과는 표준 위치에 저장되며 결과 분석을 자동화하도록 스크립트를 작성할 수 있습니다.