새 미디어 컨트롤

Android 11은 미디어 컨트롤이 표시되는 방식을 업데이트하여 컨트롤 및 오디오 출력 정보를 렌더링하는 데 MediaSessionMediaRouter2 API를 활용합니다.

Android 11의 미디어 컨트롤은 빠른 설정 근처에 있습니다. 여러 앱의 세션이 스와이프할 수 있는 캐러셀에 정렬됩니다. 캐러셀은 다음 순서로 세션을 나열합니다.

  • 휴대전화에서 로컬로 재생되는 스트림
  • 외부 기기나 전송 세션에서 감지된 것과 같은 원격 스트림
  • 마지막으로 재생된 순서로 재개 가능한 이전 세션

사용자는 앱을 시작할 필요 없이 캐러셀에서 이전 세션을 다시 시작할 수 있습니다. 재생이 시작되면 사용자는 일반적인 방법으로 미디어 컨트롤과 상호작용합니다.

재생 재개 지원

이 기능을 사용하려면 개발자 옵션 설정에서 미디어 재개를 사용 설정해야 합니다.

빠른 설정 영역에 플레이어 앱을 표시하려면 유효한 MediaSession 토큰으로 MediaStyle 알림을 만들어야 합니다.

미디어 플레이어의 브랜드 아이콘을 표시하려면 NotificationBuilder.setSmallIcon()을 사용하세요.

재생 재개를 지원하려면 앱에서 MediaBrowserServiceMediaSession을 구현해야 합니다.

MediaBrowserService 구현

기기가 부팅되면 시스템에서는 가장 최근에 사용한 미디어 앱 5개를 찾고 각 앱에서 재생을 다시 시작하는 데 사용할 수 있는 컨트롤을 제공합니다.

시스템은 SystemUI의 연결을 통해 MediaBrowserService에 연결하려고 합니다. 앱은 이러한 연결을 허용해야 합니다. 허용하지 않으면 재생 재개를 지원할 수 없습니다.

SystemUI의 연결은 패키지 이름 com.android.systemui 및 서명을 사용하여 식별 및 확인할 수 있습니다. SystemUI는 플랫폼 서명으로 서명됩니다. 플랫폼 서명을 확인하는 방법의 예는 UAMP 앱에서 확인할 수 있습니다.

재생 재개를 지원하려면 MediaBrowserService에서 다음 동작을 구현해야 합니다.

  • onGetRoot()는 null이 아닌 루트를 빠르게 반환해야 합니다. 다른 복잡한 로직은 onLoadChildren()에서 처리해야 합니다.

  • onLoadChildren()이 루트 미디어 ID에서 호출되면 결과에는 FLAG_PLAYABLE 하위 요소가 포함되어야 합니다.

  • MediaBrowserServiceEXTRA_RECENT 쿼리를 수신할 때 가장 최근에 재생된 미디어 항목을 반환해야 합니다. 반환되는 값은 일반 함수가 아닌 실제 미디어 항목이어야 합니다.

  • MediaBrowserService는 비어 있지 않은 제목자막이 있는 적절한 MediaDescription을 제공해야 합니다. 아이콘 URI아이콘 비트맵도 설정해야 합니다.

다음 코드 예에서는 onGetRoot()를 구현하는 방법을 보여줍니다.

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        rootHints?.let {
            if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return BrowserRoot(MY_RECENTS_ROOT_ID, null)
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return BrowserRoot(MY_MEDIA_ROOT_ID, null)
    }
    // Return an empty tree to disallow browsing.
    return BrowserRoot(MY_EMPTY_ROOT_ID, null)

자바

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        if (rootHints != null) {
            if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return new BrowserRoot(MY_RECENTS_ROOT_ID, null);
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    }
    // Return an empty tree to disallow browsing.
    return new BrowserRoot(MY_EMPTY_ROOT_ID, null);
}

MediaSession 구현

시스템은 MediaSessionMediaMetadata에서 다음 정보를 검색하여 사용 가능한 경우 표시합니다.

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION(지속 시간이 설정되지 않은 경우 탐색 막대에 진행률이 표시되지 않음)

재생 재개를 지원하려면 MediaSession에서 onPlay()MediaSession 콜백을 구현해야 합니다.

미디어 플레이어는 현재 재생 중인 미디어의 경과 시간과 MediaSession PlaybackState에 매핑된 탐색 막대를 표시합니다.

탐색 막대가 올바르게 작동하려면 PlaybackState.Builder#setActions를 구현하고 ACTION_SEEK_TO를 포함해야 합니다. 이렇게 하지 않으면 플레이어는 경과 시간과 지속 시간만 표시합니다.

플레이어 컨트롤을 설정하려면 Notification.Builder#setCustomActions를 사용하세요. Notification.MediaStyle#setShowsActionsInCompactView로 표시된 작업만 축소된 빠른 설정에 나타나는 미디어 플레이어에 표시됩니다.