Androidで標準ギャラリーのように動画も写真も取得する


Androidでは写真や動画、音楽などのファイルをアプリ間で共有する仕組みとしてMediaStoreが用意されています。
MediaStoreはContentProviderで公開されていてURIを知っていればContentResolver経由で取得したり追加したりすることができます。

取得できる種類は色いろあるのですが、
http://android.roof-balcony.com/shori/content-provider/getcontent-3/
ここにあるような

MediaStore.Images.Media.EXTERNAL_CONTENT_URI
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
MediaStore.Video.Media.EXTERNAL_CONTENT_URI

くらいしかつかっていませんでした。

標準ギャラリーのように動画と写真を一緒に取得したい

こんな時困りました。
普通にURIから

// 同期
Cursor cursor = getContentResolver().query(URI,...);
// 非同期
CursorLoader cursorLoader = new CursorLoader(callback,URI,...);

のようにCursorを取得すると思いますが、上記のMediaStore.Imagesは写真のみ、MediaStore.Videoは動画のみしか取得できません。

しかし、ファイル一般が全部取得できるURIがあったんですね、知りませんでした。

MediaStore.Files.getContentUri("external");

ちょっと定数がなくて不便な気もしますが、こちらでいろんなファイルが取得出来ました。
ちょっと調べても日本語のサイトが無かったんですが、常識だったんですね、すみません。

上記参考URLにありますが、MediaStore.Files.FilesColumnsにMEDIA_TYPEというのがあってそれを判別することで動画と写真だけを取り出せました。

String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
     + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE 
     + " OR "
     + MediaStore.Files.FileColumns.MEDIA_TYPE + "="
     + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;

Uri queryUri = MediaStore.Files.getContentUri("external");

CursorLoader cursorLoader = new CursorLoader(
    this,
    queryUri,
    projection,
    selection,
    null, // Selection args (none).
    MediaStore.Files.FileColumns.DATE_ADDED + " DESC" // Sort order.);

Cursor cursor = cursorLoader.loadInBackground();

注意点

中身はcontent://media/external/fileとかなので、ContentObserverで登録しても

MediaStore.Images.Media.EXTERNAL_CONTENT_URI="content://media/external/images/media"

などの変更は通知されてきません。
なのでCursorAdapterとかでFLAG_REGISTER_CONTENT_OBSERVERをセットしても通知されずに困りました。
個別にURIを監視するしか無いかもしれません。

また、MediaStore.Files自体はAPI 11から追加されてるみたいなので、古い場合は組み合わせで取得するしか無いみたいですね。
今頃2.3系使ってる人もいるかと思ったのですが、アプリによってはまだ1/4以上シェアがあったりします。。