PIP 모드

Android 휴대기기의 PIP (picture-in-picture) 기능을 사용하면 활동을 지속 중인 앱을 작은 창으로 전환할 수 있습니다. PIP가 동영상 앱에 특히 유용한 이유는 콘텐츠가 계속해서 재생해는 동안에도 사용자가 자유롭게 다른 작업을 수행할 수 있기 때문입니다. 사용자는 SystemUI를 통해 이 창의 위치를 변경하고 현재 앱에서 제공하는 작업(최대 3개)을 수행 중인 PIP 모드의 애플리케이션과 상호작용할 수 있습니다.

PIP 사용을 위해서는 해당 기능을 지원하고 활동별 기준으로 작동하는 애플리케이션의 명시적인 선택이 필요합니다. 한 애플리케이션에는 여러 개의 활동이 포함될 수 있으며, 여기서 하나만 PIP 모드가 가능합니다. 활동은 enterPictureInPictureMode()를 호출하여 PIP 전환을 요청하며, onPictureInPictureModeChanged() 형식의 활동 콜백을 수신합니다.

setPictureInPictureParams() 메서드는 활동이 PIP 및 맞춤 작업 상태에서 가로세로 비율을 제어할 수 있게 해주며, 덕분에 사용자는 활동을 펼치지 않고도 활동과 상호작용할 수 있습니다. PIP에서는 활동이 일시중지 상태이지만 계속해서 렌더링되며, 터치 입력 또는 창 포커스를 직접적으로 수신하지 않습니다. 한 번에 하나의 작업만 PIP 모드가 가능합니다.

자세한 내용은 Android 개발자 PIP(Picture-in-picture) 문서를 참고하세요.

기기 요구사항

PIP를 지원하려면 /android/frameworks/base/core/java/android/content/pm/PackageManager.java에서 PackageManager#FEATURE_PICTURE_IN_PICTURE 시스템 기능을 사용 설정합니다. PIP를 지원하는 기기에는 가장 작은 너비가 200dp를 초과하는 큰 화면이 있어야 합니다. 화면 분할 멀티 윈도우처럼 PIP는 화면에서 여러 활동을 동시에 실행할 수 있게 해줍니다. 따라서 기기의 CPU 및 RAM은 이러한 사용 사례를 지원할 수 있을 만큼 충분해야 합니다.

구현

활동 수명 주기 관리의 대부분은 시스템에서 ActivityManager 및 WindowManager 사이에 실행됩니다. 참조 UI 구현은 SystemUI 패키지에 있습니다.

시스템 수정사항은 호환성 테스트 모음(CTS) 테스트에 의해 정의된 것처럼 시스템의 근본적인 동작에 영향을 미치면 안 됩니다. PIP의 시스템 논리는 기본적으로 '고정된' 스택 내의 작업 및 활동 관리를 중심으로 이루어집니다. 다음은 간단한 클래스 개요입니다.

  • ActivityRecord: 활동의 PIP(picture-in-picture) 상태를 추적합니다. 특정 상황에서 사용자가 PIP 모드로 전환되지 않도록 하려면(예: 잠금 화면에서 또는 VR 도중) checkEnterPictureInPictureState()에 사례를 추가합니다.
  • ActivityManagerService: PIP 모드로의 전환을 요청하기 위한 활동의 기본 인터페이스, 그리고 PIP 활동 상태를 변경하기 위한 WindowManager 및 SystemUI의 호출 인터페이스입니다.
  • ActivityStackSupervisor: ActivityManagerService에서 호출되어 고정된 스택 안팎으로 작업을 이동하고, 필요에 따라 WindowManager를 업데이트합니다.
  • PinnedStackWindowController: ActivityManager의 WindowManager 인터페이스입니다.
  • PinnedStackController: 시스템의 변경사항을 SystemUI에 보고합니다(표시된/숨겨진 IME, 변경된 가로세로 비율 또는 변경된 작업 등).
  • BoundsAnimationController: 크기 변경 도중 구성 변경을 트리거하지 않는 방식으로 PIP 활동 창에 애니메이션을 적용합니다.
  • PipSnapAlgorithm: 시스템 및 SystemUI에 사용되는 공유된 클래스입니다. 화면 가장자리 근처 PIP 창의 맞추기 동작을 제어합니다.

참조 SystemUI는 확장 및 해제처럼 사용자 및 일반 변경에 대한 맞춤 작업 표시를 지원하는 온전한 PIP 구현을 제공합니다. 이 변경사항이 CDD에 의해 정의되는 근본적인 동작에 영향을 미치지 않는 한, 기기 제조업체는 이 변경사항을 기반으로 할 수 있습니다. 다음은 간단한 클래스 개요입니다.

  • PipManager: SystemUI로 시작하는 SystemUI 구성요소입니다.
  • PipTouchHandler: PIP를 조작하는 동작을 제어하는 터치 핸들러입니다. PIP의 입력 소비자가 활성 상태인 경우에만 사용됩니다(InputConsumerController 참조). 여기에서 새 동작을 추가할 수 있습니다.
  • PipMotionHelper: PIP 위치와 화면의 허용되는 부분을 추적하는 편의 클래스입니다. ActivityManagerService를 통해 호출하여 PIP 위치 및 크기를 업데이트하거나 애니메이션을 적용합니다.
  • PipMenuActivityController: 현재 PIP의 활동에 의해 제공되는 작업을 표시하는 활동을 시작합니다. 이 활동은 작업 오버레이 활동이며, 오버레이하는 입력 소비자를 제거하여 상호작용을 허용합니다.
  • PipMenuActivity: 메뉴 활동의 구현입니다.
  • PipMediaController: PIP의 기본 작업에 영향을 줄 수 있는 방식으로 미디어 세션이 변경될 때 SystemUI를 업데이트하는 리스너입니다.
  • PipNotificationController: 사용자가 PIP 기능을 사용하는 동안 알림이 활성화되도록 하는 컨트롤러입니다.
  • PipDismissViewController: 사용자가 PIP와 상호작용을 시작하면 사용자가 PIP를 해제할 수 있다고 표시하기 위해 표시되는 오버레이입니다.

기본 배치

PIP의 기본 배치를 제어하는 다양한 시스템 리소스가 있습니다.

  • config_defaultPictureInPictureGravity: PIP를 배치할 모서리를 제어하는 중력 정수입니다(예: BOTTOM|RIGHT).
  • config_defaultPictureInPictureScreenEdgeInsets: PIP 배치를 위한 화면 측면의 오프셋입니다.
  • config_pictureInPictureDefaultSizePercent 및 config_pictureInPictureDefaultAspectRatio: 화면 너비 및 가로세로 비율의 조합은 PIP 크기를 제어합니다. 계산된 기본 PIP 크기는 CTS 및 CDD에 의해 정의된 @dimen/default_minimal_size_pip_resizable_task보다 작을 수 없습니다.
  • config_pictureInPictureSnapMode: PipSnapAlgorithm에 정의된 맞추기 동작입니다.

기기 구현은 CDD 및 CTS에 정의된 최소 및 최대 가로세로 비율을 변경하면 안 됩니다.

권한

AppOpsManager(main/core/java/android/app/AppOpsManager.java)의 패키지별 '애플리케이션 작업'(OP_PICTURE_IN_PICTURE)을 사용하면 사용자가 시스템 설정을 통해 애플리케이션별로 PIP를 제어할 수 있습니다. 기기 구현은 활동이 PIP 모드 전환을 요청할 때 이러한 확인 내용을 적용해야 합니다.

테스트

PIP 구현을 테스트하려면 /cts/hostsidetests/services/activitymanager 아래에서, 특히 ActivityManagerPinnedStackTests.java에서 호스트 측 CTS 테스트에 있는 모든 PIP 관련 테스트를 실행합니다.