/*
HostMediaPlayerProfile.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.host.profile;
import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import org.deviceconnect.android.activity.PermissionUtility;
import org.deviceconnect.android.deviceplugin.host.BuildConfig;
import org.deviceconnect.android.deviceplugin.host.file.HostFileProvider;
import org.deviceconnect.android.deviceplugin.host.mediaplayer.HostMediaPlayerManager;
import org.deviceconnect.android.event.EventError;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.MediaPlayerProfile;
import org.deviceconnect.android.profile.api.DConnectApi;
import org.deviceconnect.android.profile.api.DeleteApi;
import org.deviceconnect.android.profile.api.GetApi;
import org.deviceconnect.android.profile.api.PutApi;
import org.deviceconnect.android.provider.FileManager;
import org.deviceconnect.message.DConnectMessage;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Media Player Profile.
*
* @author NTT DOCOMO, INC.
*/
public class HostMediaPlayerProfile extends MediaPlayerProfile {
/** Debug Tag. */
private static final String TAG = "HOST";
/** ミリ秒 - 秒オーダー変換用. */
private static final int UNIT_SEC = 1000;
/** Sort flag. */
enum SortOrder {
/** Title (asc). */
TITLE_ASC,
/** Title (desc). */
TITLE_DESC,
/** Duration (asc). */
DURATION_ASC,
/** Duration (desc). */
DURATION_DESC,
/** Artist (asc). */
ARTIST_ASC,
/** Artist (desc). */
ARTIST_DESC,
/** Mime (asc). */
MIME_ASC,
/** Mime (desc). */
MIME_DESC,
/** Id (asc). */
ID_ASC,
/** Id (desc). */
ID_DESC,
/** Composer (asc). */
COMPOSER_ASC,
/** Composer (desc). */
COMPOSER_DESC,
/** Language (asc). */
LANGUAGE_ASC,
/** Language (desc). */
LANGUAGE_DESC
}
/**
* AudioのContentProviderのキー一覧を定義する.
*/
private static final String[] AUDIO_TABLE_KEYS = { MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.COMPOSER, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media._ID, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.DATE_ADDED,
MediaStore.Audio.Media.DISPLAY_NAME };
/**
* VideoのContentProviderのキー一覧を定義する.
*/
private static final String[] VIDEO_TABLE_KEYS = { MediaStore.Video.Media.ALBUM, MediaStore.Video.Media.ARTIST,
MediaStore.Video.Media.LANGUAGE, MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DURATION,
MediaStore.Video.Media._ID, MediaStore.Video.Media.MIME_TYPE, MediaStore.Video.Media.DATE_ADDED,
MediaStore.Video.Media.DISPLAY_NAME };
/** Mute Status. */
private static Boolean sIsMute = false;
private HostMediaPlayerManager mHostMediaPlayerManager;
private final DConnectApi mPutPlayApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_PLAY;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.playMedia(response);
return false;
}
};
private final DConnectApi mPutStopApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_STOP;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.stopMedia(response);
return false;
}
};
private final DConnectApi mPutPauseApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_PAUSE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.pauseMedia(response);
return false;
}
};
private final DConnectApi mPutResumeApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_RESUME;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.resumeMedia(response);
return false;
}
};
private final DConnectApi mGetPlayStatusApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_PLAY_STATUS;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.getPlayStatus(response);
return false;
}
};
private final DConnectApi mPutMediaApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MEDIA;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
final String mediaId = getMediaId(request);
if (checkInteger(mediaId)) {
mHostMediaPlayerManager.putMediaId(response, mediaId);
return true;
} else {
PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
new PermissionUtility.PermissionRequestCallback() {
@Override
public void onSuccess() {
FileManager mFileManager = new FileManager(getContext(), HostFileProvider.class.getName());
long newMediaId = mediaIdFromPath(getContext(), mFileManager.getBasePath() + mediaId);
if (newMediaId == -1) {
MessageUtils.setInvalidRequestParameterError(response);
sendResponse(response);
return;
}
mHostMediaPlayerManager.putMediaId(response, "" + newMediaId);
sendResponse(response);
}
@Override
public void onFail(@NonNull String deniedPermission) {
MessageUtils.setIllegalServerStateError(response,
"Permission READ_EXTERNAL_STORAGE not granted.");
sendResponse(response);
}
});
return false;
}
}
};
private final DConnectApi mGetMediaApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MEDIA;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
final String serviceId = getServiceID(request);
final String mediaId = getMediaId(request);
PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
new PermissionUtility.PermissionRequestCallback() {
@Override
public void onSuccess() {
onGetMediaInternal(request, response, serviceId, mediaId);
}
@Override
public void onFail(@NonNull String deniedPermission) {
MessageUtils.setIllegalServerStateError(response,
"Permission READ_EXTERNAL_STORAGE not granted.");
sendResponse(response);
}
});
return false;
}
};
private final DConnectApi mGetMediaListApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MEDIA_LIST;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String query = getQuery(request);
String mimeType = getMIMEType(request);
String[] orders = getOrder(request);
Integer offset = getOffset(request);
Integer limit = getLimit(request);
Bundle b = request.getExtras();
if (b.getString(PARAM_LIMIT) != null) {
if (parseInteger(b.get(PARAM_LIMIT)) == null) {
MessageUtils.setInvalidRequestParameterError(response);
return true;
}
}
if (b.getString(PARAM_OFFSET) != null) {
if (parseInteger(b.get(PARAM_OFFSET)) == null) {
MessageUtils.setInvalidRequestParameterError(response);
return true;
}
}
return getMediaList(response, query, mimeType, orders, offset, limit);
}
};
private final DConnectApi mPutVolumeApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_VOLUME;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
Double volume = getVolume(request);
AudioManager manager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
double maxVolume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
manager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) (maxVolume * volume), 1);
setResult(response, DConnectMessage.RESULT_OK);
mHostMediaPlayerManager.sendOnStatusChangeEvent("volume");
return true;
}
};
private final DConnectApi mGetVolumeApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_VOLUME;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
AudioManager manager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
double maxVolume = 1;
double mVolume = 0;
mVolume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);
maxVolume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
setVolume(response, mVolume / maxVolume);
setResult(response, DConnectMessage.RESULT_OK);
return true;
}
};
private final DConnectApi mPutSeekApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_SEEK;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
mHostMediaPlayerManager.setMediaPos(response, getPos(request));
return false;
}
};
private final DConnectApi mGetSeekApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_SEEK;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
int pos = mHostMediaPlayerManager.getMediaPos();
if (pos < 0) {
setPos(response, 0);
switch (pos) {
case -1:
MessageUtils.setIllegalDeviceStateError(response, "Media is not set.");
break;
case -10:
default:
MessageUtils.setUnknownError(response, "Position acquisition failure.");
break;
}
} else if (pos == Integer.MAX_VALUE) {
mHostMediaPlayerManager.setVideoMediaPosRes(response);
return false;
} else {
setPos(response, pos);
setResult(response, DConnectMessage.RESULT_OK);
}
return true;
}
};
private final DConnectApi mPutMuteApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MUTE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
AudioManager manager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
manager.setStreamMute(AudioManager.STREAM_MUSIC, true);
sIsMute = true;
setResult(response, DConnectMessage.RESULT_OK);
mHostMediaPlayerManager.sendOnStatusChangeEvent("mute");
return true;
}
};
private final DConnectApi mDeleteMuteApi = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MUTE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
AudioManager manager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
manager.setStreamMute(AudioManager.STREAM_MUSIC, false);
sIsMute = false;
setResult(response, DConnectMessage.RESULT_OK);
mHostMediaPlayerManager.sendOnStatusChangeEvent("unmute");
return true;
}
};
private final DConnectApi mGetMuteApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_MUTE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
setMute(response, sIsMute);
setResult(response, DConnectMessage.RESULT_OK);
return true;
}
};
private final DConnectApi mPutOnStatusChangeApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_ON_STATUS_CHANGE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String serviceId = getServiceID(request);
// イベントの登録
EventError error = EventManager.INSTANCE.addEvent(request);
if (error == EventError.NONE) {
mHostMediaPlayerManager.registerOnStatusChange(response, serviceId);
return false;
} else {
MessageUtils.setInvalidRequestParameterError(response, "Can not register event.");
return true;
}
}
};
private final DConnectApi mDeleteOnStatusChangeApi = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_ON_STATUS_CHANGE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
// イベントの解除
EventError error = EventManager.INSTANCE.removeEvent(request);
if (error == EventError.NONE) {
mHostMediaPlayerManager.unregisterOnStatusChange(response);
return false;
} else {
MessageUtils.setInvalidRequestParameterError(response, "Can not unregister event.");
return true;
}
}
};
public HostMediaPlayerProfile(final HostMediaPlayerManager manager) {
mHostMediaPlayerManager = manager;
addApi(mPutPlayApi);
addApi(mPutStopApi);
addApi(mPutPauseApi);
addApi(mPutResumeApi);
addApi(mGetPlayStatusApi);
addApi(mPutMediaApi);
addApi(mGetMediaApi);
addApi(mGetMediaListApi);
addApi(mPutVolumeApi);
addApi(mGetVolumeApi);
addApi(mPutSeekApi);
addApi(mGetSeekApi);
addApi(mPutMuteApi);
addApi(mDeleteMuteApi);
addApi(mGetMuteApi);
addApi(mPutOnStatusChangeApi);
addApi(mDeleteOnStatusChangeApi);
}
private void onGetMediaInternal(final Intent request, final Intent response, final String serviceId,
final String mediaId) {
// Query table parameter.
String[] param = null;
// URI
Uri uriType = null;
// Query filter.
String filter = "_display_name=?";
// Query cursor.
Cursor cursor = null;
if (mediaId.length() == 0) {
MessageUtils.setInvalidRequestParameterError(response);
sendResponse(response);
return;
}
// Get media path.
String fileName = null;
Uri uri = getMediaUri(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, mediaId);
if (uri != null) {
fileName = getDisplayNameFromUri(uri);
if (fileName == null) {
uri = getMediaUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mediaId);
if (uri != null) {
fileName = getDisplayNameFromUri(uri);
if (fileName != null) {
param = AUDIO_TABLE_KEYS;
uriType = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
}
} else {
param = VIDEO_TABLE_KEYS;
uriType = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
}
if (fileName == null) {
FileManager mFileManager = new FileManager(getContext(), HostFileProvider.class.getName());
File basePath = mFileManager.getBasePath();
String absolutePath = basePath.getAbsolutePath();
uri = getMediaUri(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, absolutePath + mediaId);
if (uri != null) {
fileName = getDisplayNameFromUri(uri);
if (fileName == null) {
uri = getMediaUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, absolutePath + mediaId);
if (uri != null) {
fileName = getDisplayNameFromUri(uri);
if (fileName != null) {
param = AUDIO_TABLE_KEYS;
uriType = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
}
} else {
param = VIDEO_TABLE_KEYS;
uriType = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
}
}
if (fileName == null) {
MessageUtils.setInvalidRequestParameterError(response);
sendResponse(response);
return;
}
ContentResolver cresolver = getContext().getApplicationContext().getContentResolver();
try {
cursor = cresolver.query(uriType, param, filter, new String[] { fileName }, null);
if (cursor == null) {
MessageUtils.setInvalidRequestParameterError(response);
} else if (cursor.moveToFirst()) {
loadMediaData(uriType, cursor, response);
setResult(response, DConnectMessage.RESULT_OK);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
sendResponse(response);
}
/**
* Get Media Uri.
* @param typeUri type Uri.
* @param mediaId media ID.
* @return uri.
*/
private Uri getMediaUri(final Uri typeUri, final String mediaId) {
if (!(isMediaId(mediaId))) {
long newMediaId = mediaIdFromPath(getContext(), mediaId);
if (newMediaId != -1) {
return ContentUris.withAppendedId(typeUri, newMediaId);
} else {
return null;
}
} else {
return ContentUris.withAppendedId(typeUri, Long.valueOf(mediaId));
}
}
/**
* cursorからMediaDataを読み込みBundleに格納して返却する.
*
* @param uriType メディアタイプ
* @param cursor データが格納されているCursor
* @param response response.
*/
private void loadMediaData(final Uri uriType, final Cursor cursor, final Intent response) {
String mId;
String mType;
String mTitle;
int mDuration;
String mArtist;
String mComp;
if (uriType == MediaStore.Audio.Media.EXTERNAL_CONTENT_URI) {
mId = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
mType = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.MIME_TYPE));
mTitle = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
mDuration = (cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))) / UNIT_SEC;
mArtist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
mComp = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.COMPOSER));
setType(response, "Music");
List<Bundle> dataList = new ArrayList<>();
Bundle creator = new Bundle();
setCreator(creator, mArtist);
setRole(creator, "Artist");
dataList.add((Bundle) creator.clone());
setCreator(creator, mComp);
setRole(creator, "Composer");
dataList.add((Bundle) creator.clone());
setCreators(response, dataList.toArray(new Bundle[dataList.size()]));
} else {
mId = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID));
mType = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.MIME_TYPE));
mTitle = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
mDuration = (cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))) / UNIT_SEC;
mArtist = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.ARTIST));
String mLang = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.LANGUAGE));
setLanguage(response, mLang);
setType(response, "Video");
List<Bundle> dataList = new ArrayList<>();
Bundle creatorVideo = new Bundle();
setCreator(creatorVideo, mArtist);
setRole(creatorVideo, "Artist");
dataList.add((Bundle) creatorVideo.clone());
setCreators(response, dataList.toArray(new Bundle[dataList.size()]));
}
setMediaId(response, mId);
setMIMEType(response, mType);
setTitle(response, mTitle);
setDuration(response, mDuration);
}
/**
* Get display name from URI.
*
* @param mUri URI
* @return name display name.
*/
private String getDisplayNameFromUri(final Uri mUri) {
Cursor c = null;
try {
ContentResolver mContentResolver = getContext().getApplicationContext().getContentResolver();
c = mContentResolver.query(mUri, null, null, null, null);
if (c != null && c.moveToFirst()) {
int index = c.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
if (index != -1) {
return c.getString(index);
}
}
} finally {
if (c != null) {
c.close();
}
}
return null;
}
/**
* Get Media List.
*
* @param response Response
* @param query Query
* @param mimeType MIME Type
* @param orders Order
* @param offset Offset
* @param limit Limit
*/
private boolean getMediaList(final Intent response, final String query, final String mimeType,
final String[] orders, final Integer offset, final Integer limit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
new PermissionUtility.PermissionRequestCallback() {
@Override
public void onSuccess() {
getMediaListInternal(response, query, mimeType, orders, offset, limit);
sendResponse(response);
}
@Override
public void onFail(@NonNull String deniedPermission) {
MessageUtils.setIllegalServerStateError(response,
"READ_EXTERNAL_STORAGE permission not granted.");
sendResponse(response);
}
});
return false;
}
getMediaListInternal(response, query, mimeType, orders, offset, limit);
return true;
}
private void getMediaListInternal(final Intent response, final String query, final String mimeType,
final String[] orders, final Integer offset, final Integer limit) {
try {
SortOrder mSort = SortOrder.TITLE_ASC;
int counter;
if (limit != null) {
if (limit < 0) {
MessageUtils.setInvalidRequestParameterError(response);
return;
}
}
if (offset != null) {
if (offset < 0) {
MessageUtils.setInvalidRequestParameterError(response);
return;
}
}
// 音楽用のテーブルの項目.
String[] mMusicParam;
String[] mVideoParam;
// URI
Uri mMusicUriType;
Uri mVideoUriType;
// 検索用 Filterを作成.
String mVideoFilter = "";
String mMusicFilter = "";
// Orderの処理
String mOrderBy = "";
// 検索用Cursor.
Cursor cursorMusic = null;
Cursor cursorVideo = null;
if (mimeType != null) {
mVideoFilter = "" + MediaStore.Video.Media.MIME_TYPE + " LIKE '" + mimeType + "%'";
mMusicFilter = "" + MediaStore.Audio.Media.MIME_TYPE + " LIKE '" + mimeType + "%'";
}
if (query != null) {
if (!mVideoFilter.equals("")) {
mVideoFilter += " AND ";
}
mVideoFilter += MediaStore.Video.Media.TITLE + " LIKE '%" + query + "%'";
if (!mMusicFilter.equals("")) {
mMusicFilter += " AND ";
}
mMusicFilter += "(" + MediaStore.Audio.Media.TITLE + " LIKE '%" + query + "%'";
mMusicFilter += " OR " + MediaStore.Audio.Media.COMPOSER + " LIKE '%" + query + "%')";
}
if (orders != null) {
if (orders.length == 2) {
mOrderBy = orders[0] + " " + orders[1];
mSort = getSortOrder(orders[0], orders[1]);
} else {
MessageUtils.setInvalidRequestParameterError(response);
return;
}
} else {
mOrderBy = "title asc";
mSort = SortOrder.TITLE_ASC;
}
// 音楽用のテーブルキー設定.
mMusicParam = new String[] { MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.COMPOSER, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media._ID, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.DATE_ADDED };
mMusicUriType = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
// 動画用のテーブルキー設定.
mVideoParam = new String[] { MediaStore.Video.Media.ALBUM, MediaStore.Video.Media.ARTIST,
MediaStore.Video.Media.LANGUAGE, MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DURATION,
MediaStore.Video.Media._ID, MediaStore.Video.Media.MIME_TYPE, MediaStore.Video.Media.DATE_ADDED };
mVideoUriType = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = this.getContext().getApplicationContext().getContentResolver();
try {
cursorMusic = mContentResolver.query(mMusicUriType, mMusicParam, mMusicFilter, null, mOrderBy);
if (cursorMusic != null) {
cursorMusic.moveToFirst();
}
} catch (Exception e) {
MessageUtils.setInvalidRequestParameterError(response);
if (cursorMusic != null) {
cursorMusic.close();
}
return;
}
ArrayList<MediaList> mList = new ArrayList<>();
if (cursorMusic.getCount() > 0) {
counter = getMusicList(cursorMusic, mList);
}
try {
cursorVideo = mContentResolver.query(mVideoUriType, mVideoParam, mVideoFilter, null, mOrderBy);
cursorVideo.moveToFirst();
} catch (Exception e) {
MessageUtils.setInvalidRequestParameterError(response);
if (cursorMusic != null) {
cursorMusic.close();
}
if (cursorVideo != null) {
cursorVideo.close();
}
return;
}
if (cursorVideo.getCount() > 0) {
counter = getVideoList(cursorVideo, mList);
}
List<Bundle> list = new ArrayList<>();
counter = getMediaDataList(mList, list, offset, limit, mSort);
setCount(response, counter);
setMedia(response, list.toArray(new Bundle[list.size()]));
setResult(response, DConnectMessage.RESULT_OK);
cursorMusic.close();
cursorVideo.close();
} catch (Throwable throwable) {
MessageUtils.setUnknownError(response, "Failed to get a media list.");
}
}
/**
* Get Music List.
*
* @param cursorMusic Cursor Music
* @param list List
* @return counter Music data count.
*/
private int getMusicList(final Cursor cursorMusic, final ArrayList<MediaList> list) {
int counter = 0;
do {
String mId = cursorMusic.getString(cursorMusic.getColumnIndex(MediaStore.Audio.Media._ID));
String mType = cursorMusic.getString(cursorMusic.getColumnIndex(MediaStore.Audio.Media.MIME_TYPE));
String mTitle = cursorMusic.getString(cursorMusic.getColumnIndex(MediaStore.Audio.Media.TITLE));
int mDuration = (cursorMusic.getInt(cursorMusic.getColumnIndex(MediaStore.Audio.Media.DURATION)))
/ UNIT_SEC;
String mArtist = cursorMusic.getString(cursorMusic.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String mComp = cursorMusic.getString(cursorMusic.getColumnIndex(MediaStore.Audio.Media.COMPOSER));
list.add(new MediaList(mId, mType, mTitle, mArtist, mDuration, mComp, null, false));
counter++;
} while (cursorMusic.moveToNext());
return counter;
}
/**
* Get Video List.
*
* @param cursorVideo Cursor Video
* @param list List
* @return counter Video data count.
*/
private int getVideoList(final Cursor cursorVideo, final ArrayList<MediaList> list) {
int counter = 0;
do {
String mLang = cursorVideo.getString(cursorVideo.getColumnIndex(MediaStore.Video.Media.LANGUAGE));
String mId = cursorVideo.getString(cursorVideo.getColumnIndex(MediaStore.Video.Media._ID));
String mType = cursorVideo.getString(cursorVideo.getColumnIndex(MediaStore.Video.Media.MIME_TYPE));
String mTitle = cursorVideo.getString(cursorVideo.getColumnIndex(MediaStore.Video.Media.TITLE));
int mDuration = (cursorVideo.getInt(cursorVideo.getColumnIndex(MediaStore.Video.Media.DURATION)))
/ UNIT_SEC;
String mArtist = cursorVideo.getString(cursorVideo.getColumnIndex(MediaStore.Video.Media.ARTIST));
list.add(new MediaList(mId, mType, mTitle, mArtist, mDuration, null, mLang, true));
counter++;
} while (cursorVideo.moveToNext());
return counter;
}
/**
* Get Media List.
*
* @param orglist original list.
* @param medialist Media list.
* @param offset Offset.
* @param limit Limit.
* @param sortflag Sort flag.
* @return counter Video data count.
*/
private int getMediaDataList(final ArrayList<MediaList> orglist, final List<Bundle> medialist, final Integer offset,
final Integer limit, final SortOrder sortflag) {
switch (sortflag) {
case DURATION_ASC:
case DURATION_DESC:
Collections.sort(orglist, new MediaListDurationComparator());
break;
case ARTIST_ASC:
case ARTIST_DESC:
Collections.sort(orglist, new MediaListArtistComparator());
break;
case MIME_ASC:
case MIME_DESC:
Collections.sort(orglist, new MediaListTypeComparator());
break;
case ID_ASC:
case ID_DESC:
Collections.sort(orglist, new MediaListIdComparator());
break;
case COMPOSER_ASC:
case COMPOSER_DESC:
Collections.sort(orglist, new MediaListComposerComparator());
break;
case LANGUAGE_ASC:
case LANGUAGE_DESC:
Collections.sort(orglist, new MediaListLanguageComparator());
break;
case TITLE_ASC:
case TITLE_DESC:
default:
Collections.sort(orglist, new MediaListTitleComparator());
break;
}
switch (sortflag) {
case TITLE_DESC:
case DURATION_DESC:
case ARTIST_DESC:
case MIME_DESC:
case ID_DESC:
case COMPOSER_DESC:
case LANGUAGE_DESC:
Collections.reverse(orglist);
break;
default:
break;
}
int mOffset = 0;
if (offset == null) {
mOffset = 0;
} else {
mOffset = offset;
}
int mLimit = 0;
if (limit == null) {
mLimit = orglist.size();
} else {
mLimit = limit + mOffset;
}
for (int i = mOffset; i < mLimit; i++) {
Bundle medium = new Bundle();
String mComp = null;
String mId = orglist.get(i).getId();
String mType = orglist.get(i).getType();
String mTitle = orglist.get(i).getTitle();
String mArtist = orglist.get(i).getArtist();
int mDuration = orglist.get(i).getDuration();
setMediaId(medium, mId);
setMIMEType(medium, mType);
setTitle(medium, mTitle);
setDuration(medium, mDuration);
if (orglist.get(i).isVideo()) {
String mLang = orglist.get(i).getLanguage();
setType(medium, "Video");
setLanguage(medium, mLang);
} else {
mComp = orglist.get(i).getComposer();
setType(medium, "Music");
}
List<Bundle> dataList = new ArrayList<Bundle>();
Bundle creator = new Bundle();
setCreator(creator, mArtist);
setRole(creator, "Artist");
dataList.add((Bundle) creator.clone());
if (!(orglist.get(i).isVideo())) {
setCreator(creator, mComp);
setRole(creator, "Composer");
dataList.add((Bundle) creator.clone());
}
setCreators(medium, dataList.toArray(new Bundle[dataList.size()]));
medialist.add(medium);
}
return orglist.size();
}
/**
* 数値かどうかをチェックする.
*
* @param value チェックしたいID
* @return 数値の場合はtrue、そうでない場合はfalse
*/
private boolean checkInteger(final String value) {
try {
Integer.parseInt(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
* ファイルパスからメディアIDを取得する.
*
* @param context コンテキスト
* @param path パス
* @return MediaID
*/
private static long mediaIdFromPath(final Context context, final String path) {
long id = 0;
String[] mParam = { BaseColumns._ID };
String[] mArgs = new String[] { path };
Cursor mAudioCursor = null;
// Audio
Uri mAudioUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String mFilter = MediaStore.Audio.AudioColumns.DATA + " LIKE ?";
// Search Contents Provider
ContentResolver mAudioContentsProvider = context.getContentResolver();
try {
mAudioCursor = mAudioContentsProvider.query(mAudioUri, mParam, mFilter, mArgs, null);
if (mAudioCursor.moveToFirst()) {
int mIdField = mAudioCursor.getColumnIndex(mParam[0]);
id = mAudioCursor.getLong(mIdField);
}
mAudioCursor.close();
} catch (NullPointerException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
if (mAudioCursor != null) {
mAudioCursor.close();
}
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
if (mAudioCursor != null) {
mAudioCursor.close();
}
return -1;
}
// Search video
if (id == 0) {
Cursor mVideoCursor = null;
Uri mViodeUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
mFilter = MediaStore.Video.VideoColumns.DATA + " LIKE ?";
// Search Contents Provider
ContentResolver mVideoContentsProvider = context.getContentResolver();
try {
mVideoCursor = mVideoContentsProvider.query(mViodeUri, mParam, mFilter, mArgs, null);
if (mVideoCursor.moveToFirst()) {
int mIdField = mVideoCursor.getColumnIndex(mParam[0]);
id = mVideoCursor.getLong(mIdField);
} else {
id = -1;
}
mVideoCursor.close();
} catch (NullPointerException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
if (mVideoCursor != null) {
mVideoCursor.close();
}
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
if (mVideoCursor != null) {
mVideoCursor.close();
}
return -1;
}
}
return id;
}
/**
* Media list class.
*/
private class MediaList {
/** ID. */
private String mId;
/** Mime Type. */
private String mType;
/** Title. */
private String mTitle;
/** Artist. */
private String mArtist;
/** Duration. */
private int mDuration;
/** Composer(Audio only). */
private String mComposer;
/** Language(Video only). */
private String mLanguage;
/** Video flag. */
private boolean mIsVideo;
/**
* Constructor.
*
* @param id Id.
* @param type Mime type.
* @param title Title.
* @param artist Artist.
* @param duration Duration.
* @param composer Composer(Audio only).
* @param language Language(Video only).
* @param isvideo Video flag.
*/
public MediaList(final String id, final String type, final String title, final String artist,
final int duration, final String composer, final String language, final boolean isvideo) {
this.setId(id);
this.setType(type);
this.setTitle(title);
this.setArtist(artist);
this.setDuration(duration);
this.setComposer(composer);
this.setLanguage(language);
this.setVideo(isvideo);
}
/**
* Get Id.
*
* @return Id.
*/
public String getId() {
return mId;
}
/**
* Set Id.
*
* @param id Id.
*/
public void setId(final String id) {
this.mId = id;
}
/**
* Get mime type.
*
* @return Mime type.
*/
public String getType() {
return mType;
}
/**
* Set mime type.
*
* @param type mime type.
*/
public void setType(final String type) {
this.mType = type;
}
/**
* Get title.
*
* @return Title.
*/
public String getTitle() {
return mTitle;
}
/**
* Set title.
*
* @param title Title.
*/
public void setTitle(final String title) {
this.mTitle = title;
}
/**
* Get artist.
*
* @return Artist.
*/
public String getArtist() {
return mArtist;
}
/**
* Set artist.
*
* @param artist Artist.
*/
public void setArtist(final String artist) {
this.mArtist = artist;
}
/**
* Get duration.
*
* @return Duration.
*/
public int getDuration() {
return mDuration;
}
/**
* Set duration.
*
* @param duration Duration.
*/
public void setDuration(final int duration) {
this.mDuration = duration;
}
/**
* Get composer.
*
* @return Composer.
*/
public String getComposer() {
return mComposer;
}
/**
* Set composer.
*
* @param composer Composer.
*/
public void setComposer(final String composer) {
this.mComposer = composer;
}
/**
* Get language.
*
* @return Language.
*/
public String getLanguage() {
return mLanguage;
}
/**
* Set language.
*
* @param language Language.
*/
public void setLanguage(final String language) {
this.mLanguage = language;
}
/**
* Get Video flag.
*
* @return the mIsVideo.
*/
public boolean isVideo() {
return mIsVideo;
}
/**
* Set video flag.
*
* @param isvideo the isVideo to set.
*/
public void setVideo(final boolean isvideo) {
this.mIsVideo = isvideo;
}
}
/**
* Duration sorting comparator.
*/
private class MediaListDurationComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
int mData1 = lhs.getDuration();
int mData2 = rhs.getDuration();
if (mData1 > mData2) {
return 1;
} else if (mData1 == mData2) {
return 0;
} else {
return -1;
}
}
}
/**
* Title sorting comparator.
*/
private class MediaListTitleComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getTitle(), rhs.getTitle());
}
}
/**
* Artist sorting comparator.
*/
private class MediaListArtistComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getArtist(), rhs.getArtist());
}
}
/**
* Composer sorting comparator.
*/
private class MediaListComposerComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getComposer(), rhs.getComposer());
}
}
/**
* Language sorting comparator.
*/
private class MediaListLanguageComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getLanguage(), rhs.getLanguage());
}
}
/**
* ID sorting comparator.
*/
private class MediaListIdComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getId(), rhs.getId());
}
}
/**
* Type sorting comparator.
*/
private class MediaListTypeComparator implements Comparator<MediaList> {
@Override
public int compare(final MediaList lhs, final MediaList rhs) {
return compareData(lhs.getType(), rhs.getType());
}
}
/**
* Data compare.
*
* @param data1 Data1.
* @param data2 Data2.
* @return result.
*/
private int compareData(final String data1, final String data2) {
if (data1 == null && data2 == null) {
return 0;
} else if (data1 != null && data2 == null) {
return 1;
} else if (data1 == null && data2 != null) {
return -1;
}
if (data1.compareTo(data2) > 0) {
return 1;
} else if (data1.compareTo(data2) == 0) {
return 0;
} else {
return -1;
}
}
/**
* Get sort order.
*
* @param order1 sort column.
* @param order2 asc / desc.
* @return SortOrder flag.
*/
private SortOrder getSortOrder(final String order1, final String order2) {
if (order1.compareToIgnoreCase("id") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.ID_DESC;
} else if (order1.compareToIgnoreCase("id") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.ID_ASC;
} else if (order1.compareToIgnoreCase("duration") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.DURATION_DESC;
} else if (order1.compareToIgnoreCase("duration") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.DURATION_ASC;
} else if (order1.compareToIgnoreCase("artist") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.ARTIST_DESC;
} else if (order1.compareToIgnoreCase("artist") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.ARTIST_ASC;
} else if (order1.compareToIgnoreCase("composer") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.COMPOSER_DESC;
} else if (order1.compareToIgnoreCase("composer") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.COMPOSER_ASC;
} else if (order1.compareToIgnoreCase("language") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.LANGUAGE_DESC;
} else if (order1.compareToIgnoreCase("language") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.LANGUAGE_ASC;
} else if (order1.compareToIgnoreCase("mime") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.MIME_DESC;
} else if (order1.compareToIgnoreCase("mime") == 0 && order2.compareToIgnoreCase("asc") == 0) {
return SortOrder.MIME_ASC;
} else if (order1.compareToIgnoreCase("title") == 0 && order2.compareToIgnoreCase("desc") == 0) {
return SortOrder.TITLE_DESC;
} else {
return SortOrder.TITLE_ASC;
}
}
/**
* Check mediaId exchange Long value.
* @param mediaId media ID
* @return true:OK, false:NG
*/
private boolean isMediaId(final String mediaId) {
try {
Long.valueOf(mediaId);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}