USB 저장소 미디어

MediaStore

MediaStore는 앱이 Android에서 미디어 콘텐츠를 둘러보고 액세스하기에 좋은 방법입니다. MediaStore는 모든 채택 가능한 볼륨의 인덱스를 생성한 다음, 오디오, 동영상, 이미지 콘텐츠를 애플리케이션에서 사용할 수 있도록 합니다. LocalMediaPlayer는 MediaStore API의 사용 예입니다.

채택 가능한 저장소

드라이브는 자주 연결이 해제될 가능성이 적은 안정적인 위치에 연결되었을 때 채택 가능한 것으로 간주합니다. USB 포트는 encryptable=userdata 속성을 사용하여 fstab안정적이라고 표시할 수 있습니다(기기 설정 참고).

채택 가능한 포트에 연결된 모든 드라이브는 색인이 생성됩니다. 처리 시간 외에 결과 색인이 내부 플래시 저장소에 기록됩니다.

Android 9의 알려진 제한사항

Android 9에서는 드라이브 연결이 끊기면 채택 가능한 드라이브의 색인이 삭제되었습니다. 즉, 사용자가 드라이브를 삭제한 후 곧바로 다시 연결하면 플래시 저장소에서 원래 색인이 삭제되고 드라이브 색인이 다시 생성될 때 기록됩니다.

또한 Android 9에는 시작 시 드라이브가 연결 해제로 잘못 판단되어 인덱스를 삭제하고 다시 생성하는 동일한 절차를 거치는 경합 상태가 포함되어 있었습니다. 최악의 경우, 자동차 시스템을 켤 때마다 로컬 플래시 저장소에 다시 기록하는 일이 발생할 수 있었습니다.

Android 10의 새로운 기능

Android 10에서는 다양한 MediaStore 개선사항을 제공합니다. 예를 들면 위에서 설명한 경합 상태가 수정되었습니다. 드라이브가 삭제되면 드라이브가 마지막으로 감지된 날짜부터 1주일 동안 색인이 보관됩니다. 이 기간에 드라이브가 다시 연결되면 색인이 플래시 저장소에 다시 기록되지 않습니다. 프레임워크는 여러 드라이브에 이 작업을 실행합니다.

드라이브를 다시 연결하는 경우, 콘텐츠가 변경되면 색인을 완전히 다시 작성하는 대신 업데이트합니다. 이는 플래시 저장소에 미치는 영향을 최소화합니다. 이 검사는 시작 시 실행됩니다. 사용자가 차량 시스템을 끈 후 드라이브를 삭제하고 일부 새로운 미디어를 추가한 다음 차량을 시작하기 전에 드라이브를 다시 연결하면 드라이브의 색인은 업데이트되어 새로 추가된 미디어를 포함합니다.

기타 요구사항

포트를 채택 가능한 것으로 설정하면 포트에 연결된 모든 드라이브를 시스템 저장소의 일부로 채택할 수 있습니다. 이렇게 한 후에는 드라이브가 기기 저장소의 확장으로 취급되며 다시 휴대용으로 전환되기 전에는 삭제하면 안 됩니다.

드라이브가 연결되면 프레임워크는 사용자가 드라이브를 채택할 수 있도록 허용하는 알림을 트리거합니다. 이 알림은 사용자가 드라이브를 포맷할 수 있는 마법사 흐름을 시작합니다. Android 10에서는 이 흐름이 자동차 설정에 내장되어 있지 않습니다. OEM은 포트를 채택 가능한 포트로 지정할 때 이 기능이 지원되는지 확인해야 합니다. CtsAppSecurityHostTestCases는 채택 가능한 포트와 관련된 기능을 다루며 반드시 실행되어야 합니다.

미디어 변화 감지

실행 중인 프로세스(활동 또는 서비스)는 MediaStore.AUTHORITY_URIContentObserver를 등록할 수 있으며, 그러면 관찰자는 모든 채택 가능한 볼륨의 콘텐츠 변경에 관해 알림을 받을 수 있습니다.

ContentObserver mContentObserver = new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        if (isResumed()) {
            // take action here
        }
    }
};

context.getContentResolver().registerContentObserver(
MediaStore.AUTHORITY_URI, true, mContentObserver);

notifyForDescendantstrue로 설정하면 관찰자는 URI에서 발생한 변경사항 대신 URI의 하위 URI에서 발생한 사용할 수 있는 미디어의 모든 변경사항에 관해 알림을 받습니다. 따라서 새로 연결된 드라이브의 색인이 생성되는 동안 이 관찰자는 새로 추가된 URI로 각각 트리거됩니다.

Android 10에서는 JobScheduler를 사용하여 실행 중인 프로세스 없이도 콘텐츠 변경사항을 모니터링할 수 있습니다. 그러나 이 작업은 기기에 사용 가능한 리소스가 있는 경우에만 실행됩니다.

볼륨 나열

Android 10에서는 새로운 Media Store API를 사용하여 색인을 생성했거나 색인을 생성하고 있는 채택 가능한 모든 볼륨의 이름을 검색할 수 있습니다.

List<String> volumeNames = MediaStore.getExternalVolumeNames(context);

볼륨 콘텐츠 탐색

프로세스는 채택 가능한 볼륨의 이름을 사용하여 볼륨(오디오, 동영상, 이미지 또는 파일) 내의 특정 미디어 유형에 관한 URI를 가져올 수 있고 볼륨에서 색인이 생성된 사용 가능한 모든 파일을 쿼리할 수 있습니다.

import android.provider.MediaStore.Audio.Media;

Uri volumeAudioUri = Media.getContentUri(volumeName);
String[] projection = {Media._ID, Media.ARTIST, Media.TITLE};

Cursor cursor = getContext().getContentResolver().query(volumeAudioUri, projection, null, null);

모든 볼륨 탐색

MediaStore 아래의 각 콘텐츠 유형에는 EXTERNAL_CONTENT_URIINTERNAL_CONTENT_URI가 포함되어 있어 외부 및 내부 볼륨의 모든 콘텐츠 목록을 가져올 수 있습니다. 두 필드를 결합하여 사용 가능한 모든 미디어를 확인하는 방법의 예는 packages/apps/Car/LocalMediaPlayer를 참고하세요.

필요한 권한

외부 저장소에서 읽기를 원하는 모든 앱은 READ_EXTERNAL_STORAGE 권한을 요청해야 합니다.

미디어 재생

특정 커서 항목용 URI를 생성할 수 있습니다.

Long mediaId = cursor.getLong(cursor.getColumnIndex(Media._ID));
Uri mediaUri = ContentUris.withAppendedId(volumeAudioUri, mediaId);

URI에서 애플리케이션은 오디오 포커스를 요청하고 콘텐츠를 재생할 수 있습니다. 미디어 앱 빌드를 위한 권장사항을 자세히 알아보려면 오디오 및 동영상 개요를 참고하세요.

MediaStore의 대안

채택 가능한 드라이브의 콘텐츠에 액세스하려면 MediaStore와 ContentResolver를 사용하는 것이 좋습니다. 하지만 채택할 수 없는 USB 포트의 경우 변경을 감지하고 콘텐츠에 액세스하는 다른 방법이 있습니다.

연결된 볼륨의 변경 감지

시스템 애플리케이션은 연결된 볼륨의 변경을 수신 대기할 수 있습니다. 볼륨이 확인되거나 삭제될 때 또는 볼륨이 마운트 되거나 마운트 해제될 때와 같이 볼륨 상태가 변경될 때마다 StorageEventListener에서 알림을 받을 수 있습니다.

StorageEventListener mStorageEventListener = new StorageEventListener() {
    @Override
    public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
        if (isResumed()) {
            // take action here
        }
    }
};

StorageManager mStorageManager = context.getSystemService(StorageManager.class);
mStorageManager.registerListener(mStorageEventListener);

이 방법은 실행 중인 프로세스 내에서만 사용할 수 있습니다.

저장소 액세스 프레임워크를 통한 액세스

채택 가능한 드라이브의 미디어가 아닌 파일 또는 채택할 수 없는 드라이브의 모든 파일에 액세스하려면 애플리케이션에서 저장소 액세스 프레임워크(SAF)를 사용해야 합니다. ACTIONS_OPEN_DOCUMENT 인텐트를 트리거하면 모든 볼륨에서 하나 이상의 파일을 선택할 수 있는 시스템 UI가 사용자에게 표시됩니다. 이 인텐트의 호출 애플리케이션은 MIME 유형을 지정하여 파일을 필터링해야 합니다. 사용자는 애플리케이션에서 실행하려고 찾고 있는 파일까지 MIME 유형을 선택할 수 있습니다.

참고: 애플리케이션은 사용자에게 메시지를 표시하여 파일을 명시적으로 선택하도록 하지 않고는 SAF를 사용하여 파일에 액세스할 수 없습니다. Android에서는 일반 파일 UI 액세스 APK를 제공하며 이 APK는 스타일을 지정할 수 있도록 확장하거나 OEM에서 제공하는 APK로 대체할 수 있습니다.