맞춤 탐색 작업 구현

맞춤 재생 작업을 사용하여 재생 뷰에서 고유한 기능을 지원하는 것과 마찬가지로 맞춤 탐색 작업을 사용하여 탐색 뷰에서 고유한 기능을 지원할 수 있습니다. 예를 들어 사용자가 재생목록을 다운로드하거나 대기열에 항목을 추가할 수 있도록 맞춤 탐색 작업을 사용할 수 있습니다.

원래 장비 제조업체 (OEM)에서 표시하는 것보다 더 많은 맞춤 작업이 있으면 더보기 메뉴가 사용자에게 표시됩니다. 각 맞춤 탐색 작업은 다음으로 정의됩니다.

  • 작업 ID: 고유한 문자열 식별자
  • 작업 라벨: 사용자에게 표시되는 텍스트
  • 작업 아이콘 URI (Uniform Resource Identifier): 색조를 조정할 수 있는 벡터 드로어블

맞춤 탐색 작업 더보기

그림 1. 맞춤 탐색 작업 더보기

맞춤 탐색 작업 목록은 BrowseRoot의 일부로 전역적으로 정의합니다. 그런 다음 이러한 작업의 하위 집합을 개별 MediaItem에 연결합니다.

사용자가 맞춤 탐색 작업과 상호작용하면 앱은 onCustomAction에서 콜백을 수신합니다. 그런 다음 작업을 처리하고 필요한 경우 MediaItem의 작업 목록을 업데이트합니다. 이는 즐겨찾기 및 다운로드와 같은 스테이트풀(Stateful) 작업에 유용합니다. 라디오 재생과 같이 업데이트가 필요 없는 작업의 경우 작업 목록을 업데이트하지 않아도 됩니다.

맞춤 탐색 작업 툴바

그림 2. 맞춤 탐색 작업 툴바

맞춤 탐색 작업은 탐색 노드 루트에도 연결할 수 있습니다. 이러한 작업은 기본 툴바 아래의 보조 툴바에 표시됩니다.

앱에 맞춤 탐색 작업을 추가하려면 다음 단계를 따르세요.

  1. MediaBrowserServiceCompat 구현에서 다음 두 메서드를 재정의합니다.

  2. 런타임 시 작업 한도를 파싱합니다.

    onGetRoot에서 rootHints BundleBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT 키를 사용하여 각 MediaItem에 허용되는 최대 작업 수를 가져옵니다. 한도가 0이면 기능이 시스템에서 지원되지 않음을 나타냅니다.

  3. 맞춤 탐색 작업의 전역 목록을 빌드합니다. 각 작업에 대해 다음 키를 사용하여 Bundle 객체를 만듭니다.

    • 작업 ID EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
    • 작업 라벨 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
    • 작업 아이콘 URI EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
  4. 모든 작업 Bundle 객체를 목록에 추가합니다.

  5. 전체 목록을 BrowseRoot에 추가합니다. BrowseRoot 추가 항목 Bundle에서 BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST 키를 사용하여 작업 목록을 Parcelable ArrayList로 추가합니다.

  6. MediaItem 객체에 작업을 추가합니다. DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST 키를 사용하여 MediaDescriptionCompat 추가 항목에 작업 ID 목록을 포함하는 방식으로 개별 MediaItem 객체에 작업을 추가할 수 있습니다. 이 목록은 BrowseRoot에서 정의한 전역 작업 목록의 하위 집합이어야 합니다.

  7. 작업을 처리하고 진행 상황이나 결과를 반환합니다.

작업 상태 업데이트

MediaBrowserServiceCompat에서 이러한 메서드를 재정의하려면 다음을 실행하세요.

public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)

다음 URL은

public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)

작업 한도 파싱

지원되는 맞춤 탐색 작업의 수를 확인합니다.

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) {
    rootHints.getInt(
            MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0)
}

맞춤 탐색 작업 빌드

각 작업은 별도의 Bundle로 패키징해야 합니다.

  • 작업 ID:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
    
  • 작업 라벨:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
    
  • 작업 아이콘 URI:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                    "<ACTION_ICON_URI>")
    

Parcelable ArrayList에 맞춤 탐색 작업 추가

모든 맞춤 탐색 작업 Bundle 객체를 ArrayList에 추가합니다.

private ArrayList<Bundle> createCustomActionsList(
                                        CustomBrowseAction browseActions) {
    ArrayList<Bundle> browseActionsBundle = new ArrayList<>();
    for (CustomBrowseAction browseAction : browseActions) {
        Bundle action = new Bundle();
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                browseAction.mId);
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                getString(browseAction.mLabelResId));
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                browseAction.mIcon);
        browseActionsBundle.add(action);
    }
    return browseActionsBundle;
}

탐색 루트에 맞춤 탐색 작업 목록 추가

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid,
                             Bundle rootHints) {
    Bundle browserRootExtras = new Bundle();
    browserRootExtras.putParcelableArrayList(
            BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST,
            createCustomActionsList()));
    mRoot = new BrowserRoot(ROOT_ID, browserRootExtras);
    return mRoot;
}

MediaItem에 작업 추가

MediaItem의 탐색 작업 ID는 onGetRoot에 제공된 탐색 작업의 전역 목록의 하위 집합이어야 합니다. 전역 목록에 없는 작업은 무시됩니다.

MediaDescriptionCompat buildDescription (long id, String title, String subtitle,
                String description, Uri iconUri, Uri mediaUri,
                ArrayList<String> browseActionIds) {

    MediaDescriptionCompat.Builder bob = new MediaDescriptionCompat.Builder();
    bob.setMediaId(id);
    bob.setTitle(title);
    bob.setSubtitle(subtitle);
    bob.setDescription(description);
    bob.setIconUri(iconUri);
    bob.setMediaUri(mediaUri);

    Bundle extras = new Bundle();
    extras.putStringArrayList(
          DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST,
          browseActionIds);

    bob.setExtras(extras);
    return bob.build();
}
MediaItem mediaItem = new MediaItem(buildDescription(...), flags);

onCustomAction 결과 빌드

결과를 빌드하려면 다음을 실행합니다.

  1. Bundle extras에서 mediaId 파싱

    @Override
    public void onCustomAction(
                @NonNull String action, Bundle extras, @NonNull Result<Bundle> result){
        String mediaId = extras.getString(MediaConstans.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID);
                }
    
  2. 비동기 결과의 경우 결과를 분리합니다(result.detach).

  3. 결과 번들을 빌드합니다.

    1. 사용자에게 메시지를 표시합니다.

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                    mContext.getString(stringRes))
      
    2. 항목을 업데이트합니다 (항목의 작업을 업데이트하는 데 사용).

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
      
    3. 재생 뷰를 엽니다.

      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
      
    4. 탐색 노드를 업데이트합니다.

      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
      
  4. 결과를 확인합니다.

    • 오류: result.sendError(resultBundle) 호출
    • 진행 상황 업데이트: result.sendProgressUpdate(resultBundle) 호출
    • 완료: result.sendResult(resultBundle) 호출

작업 상태 업데이트

result.sendProgressUpdate(resultBundle) 메서드를 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM 키와 함께 사용하면 작업의 새로운 상태를 반영하도록 MediaItem을 업데이트할 수 있습니다. 이를 통해 사용자에게 작업의 진행 상황과 결과에 관한 실시간 피드백을 제공할 수 있습니다.

샘플 다운로드 작업

다음은 이 기능을 사용하여 세 가지 상태가 있는 다운로드 작업을 구현하는 방법을 보여주는 예입니다.

  • 다운로드는 작업의 초기 상태입니다. 사용자가 이 작업을 선택하면 '다운로드 중'으로 바꾸고 sendProgressUpdate를 호출하여 사용자 인터페이스 (UI)를 업데이트할 수 있습니다.

  • 다운로드 중 상태는 다운로드가 진행 중임을 나타냅니다. 이 상태를 사용하여 진행률 표시줄이나 다른 표시기를 사용자에게 표시할 수 있습니다.

  • 다운로드됨 상태는 다운로드가 완료되었음을 나타냅니다. 다운로드가 완료되면 'Downloading'을 'Downloaded'로 바꾸고 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM 키로 sendResult를 호출하여 항목을 새로고침해야 함을 나타낼 수 있습니다. 또한 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE 키를 사용하여 사용자에게 성공 메시지를 표시할 수 있습니다.

이 접근 방식을 사용하면 다운로드 프로세스 및 현재 상태에 관한 명확한 피드백을 사용자에게 제공할 수 있습니다. 아이콘을 통해 다운로드 상태를 25%, 50%, 75% 로 표시하는 세부정보를 추가할 수 있습니다.

즐겨찾기 작업 샘플

또 다른 예는 다음과 같은 두 상태가 있는 즐겨찾기 작업입니다.

  • Favorite은 사용자의 즐겨찾기 목록에 없는 항목에 표시됩니다. 사용자가 이 작업을 선택하면 Favorited로 바꾸고 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM 키로 sendResult를 호출하여 UI를 업데이트합니다.

  • Favorited는 사용자의 즐겨찾기 목록에 있는 항목에 표시됩니다. 사용자가 이 작업을 선택하면 즐겨찾기로 바꾸고 EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM 키로 sendResult를 호출하여 UI를 업데이트합니다.

이 접근 방식을 통해 사용자는 즐겨찾기 항목을 명확하고 일관된 방식으로 관리할 수 있습니다. 이러한 예에서는 맞춤 탐색 작업의 유연성을 보여주며 이러한 작업을 사용하여 실시간 피드백으로 다양한 기능을 구현해 자동차의 미디어 앱 사용자 환경을 개선하는 방법을 보여줍니다.

TestMediaApp 프로젝트에서 이 기능의 종합적인 샘플 구현을 확인할 수 있습니다.