package io.hefuyi.listener;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.widget.Toast;
import java.util.Arrays;
import java.util.WeakHashMap;
import io.hefuyi.listener.util.ListenerUtil;
/**
* Created by hefuyi on 2016/10/8.
*/
public class MusicPlayer {
private static final WeakHashMap<Context, ServiceBinder> mConnectionMap;
private static final long[] sEmptyList;
public static IListenerService mService = null;
private static ContentValues[] mContentValuesCache = null;
static {
mConnectionMap = new WeakHashMap<Context, ServiceBinder>();
sEmptyList = new long[0];
}
public static ServiceToken bindToService(final Context context,
final ServiceConnection callback) {
Activity realActivity = ((Activity) context).getParent();
if (realActivity == null) {
realActivity = (Activity) context;
}
final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
contextWrapper.startService(new Intent(contextWrapper, MusicService.class));
final ServiceBinder binder = new ServiceBinder(callback,
contextWrapper.getApplicationContext());
if (contextWrapper.bindService(
new Intent().setClass(contextWrapper, MusicService.class), binder, 0)) {
mConnectionMap.put(contextWrapper, binder);
return new ServiceToken(contextWrapper);
}
return null;
}
public static void unbindFromService(final ServiceToken token) {
if (token == null) {
return;
}
final ContextWrapper mContextWrapper = token.mWrappedContext;
final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper);
if (mBinder == null) {
return;
}
mContextWrapper.unbindService(mBinder);
if (mConnectionMap.isEmpty()) {
mService = null;
}
}
public static void next() {
try {
if (mService != null) {
mService.next();
}
} catch (final RemoteException ignored) {
}
}
public static void initPlaybackServiceWithSettings(final Context context) {
setShowAlbumArtOnLockscreen(true);
}
/**
* 在锁屏显示专辑封面
* @param enabled
*/
public static void setShowAlbumArtOnLockscreen(final boolean enabled) {
try {
if (mService != null) {
mService.setLockscreenAlbumArt(enabled);
}
} catch (final RemoteException ignored) {
}
}
public static void previous(final Context context, final boolean force) {
final Intent previous = new Intent(context, MusicService.class);
if (force) {
previous.setAction(MusicService.PREVIOUS_FORCE_ACTION);
} else {
previous.setAction(MusicService.PREVIOUS_ACTION);
}
context.startService(previous);
}
public static void playOrPause() {
try {
if (mService != null) {
if (mService.isPlaying()) {
mService.pause();
} else {
mService.play();
}
}
} catch (final Exception ignored) {
}
}
public static boolean isPlaying() {
if (mService != null) {
try {
return mService.isPlaying();
} catch (final RemoteException ignored) {
}
}
return false;
}
public static int getShuffleMode() {
if (mService != null) {
try {
return mService.getShuffleMode();
} catch (final RemoteException ignored) {
}
}
return 0;
}
public static void setShuffleMode(int mode) {
try {
if (mService != null) {
mService.setShuffleMode(mode);
}
} catch (RemoteException ignored) {
}
}
public static void setRepeatMode(int mode) {
try {
if (mService != null) {
mService.setRepeatMode(mode);
}
} catch (RemoteException ignored) {
}
}
public static int getRepeatMode() {
if (mService != null) {
try {
return mService.getRepeatMode();
} catch (final RemoteException ignored) {
}
}
return 0;
}
public static String getTrackName() {
if (mService != null) {
try {
return mService.getTrackName();
} catch (final RemoteException ignored) {
}
}
return null;
}
public static String getArtistName() {
if (mService != null) {
try {
return mService.getArtistName();
} catch (final RemoteException ignored) {
}
}
return null;
}
public static String getAlbumName() {
if (mService != null) {
try {
return mService.getAlbumName();
} catch (final RemoteException ignored) {
}
}
return null;
}
public static long getCurrentAlbumId() {
if (mService != null) {
try {
return mService.getAlbumId();
} catch (final RemoteException ignored) {
}
}
return -1;
}
public static long getCurrentAudioId() {
if (mService != null) {
try {
return mService.getAudioId();
} catch (final RemoteException ignored) {
}
}
return -1;
}
public static long getCurrentArtistId() {
if (mService != null) {
try {
return mService.getArtistId();
} catch (final RemoteException ignored) {
}
}
return -1;
}
public static int getAudioSessionId() {
if (mService != null) {
try {
return mService.getAudioSessionId();
} catch (final RemoteException ignored) {
}
}
return -1;
}
public static long[] getQueue() {
try {
if (mService != null) {
return mService.getQueue();
} else {
}
} catch (final RemoteException ignored) {
}
return sEmptyList;
}
public static int getQueueSize() {
try {
if (mService != null) {
return mService.getQueueSize();
} else {
}
} catch (final RemoteException ignored) {
}
return 0;
}
public static int getQueuePosition() {
try {
if (mService != null) {
return mService.getQueuePosition();
}
} catch (final RemoteException ignored) {
}
return 0;
}
public static void refresh() {
try {
if (mService != null) {
mService.refresh();
}
} catch (final RemoteException ignored) {
}
}
public static int removeTrack(final long id) {
try {
if (mService != null) {
return mService.removeTrack(id);
}
} catch (final RemoteException ingored) {
}
return 0;
}
public static void playAll(final Context context, final long[] list, int position,
final long sourceId, final ListenerUtil.IdType sourceType,
final boolean forceShuffle) {
if (list == null || list.length == 0 || mService == null) {
return;
}
try {
if (forceShuffle) {
mService.setShuffleMode(MusicService.SHUFFLE_NORMAL);
}
final long currentId = mService.getAudioId();
final int currentQueuePosition = getQueuePosition();
if (position != -1 && currentQueuePosition == position && currentId == list[position]) {
final long[] playlist = getQueue();
if (Arrays.equals(list, playlist)) {
mService.play();
return;
}
}
if (position < 0) {
position = 0;
}
mService.open(list, forceShuffle ? -1 : position, sourceId, sourceType.mId);
mService.play();
} catch (final RemoteException ignored) {
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
/**
* 在播放列表当前播放位置插入歌曲
* @param context context to use
* @param list songs to insert
* @param sourceId source id
* @param sourceType source type
*/
public static void playNext(Context context, final long[] list, final long sourceId, final ListenerUtil.IdType sourceType) {
if (mService == null) {
return;
}
try {
mService.enqueue(list, MusicService.NEXT, sourceId, sourceType.mId);
Toast.makeText(context, R.string.set_play_next_success, Toast.LENGTH_SHORT).show();
} catch (final RemoteException ignored) {
}
}
public static void seek(final long position) {
if (mService != null) {
try {
mService.seek(position);
} catch (final RemoteException ignored) {
}
}
}
public static long position() {
if (mService != null) {
try {
return mService.position();
} catch (final RemoteException ignored) {
} catch (final IllegalStateException ex) {
}
}
return 0;
}
public static long duration() {
if (mService != null) {
try {
return mService.duration();
} catch (final RemoteException ignored) {
} catch (final IllegalStateException ignored) {
}
}
return 0;
}
public static void clearQueue() {
try {
mService.removeTracks(0, Integer.MAX_VALUE);
} catch (final RemoteException ignored) {
}
}
/**
* 在播放列表尾部插入歌曲
* @param context context to use
* @param list song list to insert
* @param sourceId source id
* @param sourceType source type
*/
public static void addToQueue(final Context context, final long[] list, long sourceId,
ListenerUtil.IdType sourceType) {
if (mService == null) {
return;
}
try {
mService.enqueue(list, MusicService.LAST, sourceId, sourceType.mId);
final String message = makeLabel(context, R.plurals.NNNtrackstoqueue, list.length);
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
} catch (final RemoteException ignored) {
}
}
/**
* 删除播放队列中歌曲
* @param position song position in queue
*/
public static void removeFromQueue(int position) {
try {
mService.removeTracks(position, position);
} catch (final RemoteException ignored) {
}
}
public static String makeLabel(final Context context, final int pluralInt,
final int number) {
return context.getResources().getQuantityString(pluralInt, number, number);
}
/**
* 在歌单中批量增加曲目
* @param context
* @param ids
* @param playlistid
*/
public static void addToPlaylist(final Context context, final long[] ids, final long playlistid) {
final int size = ids.length;
final ContentResolver resolver = context.getContentResolver();
final String[] projection = new String[]{
"max(" + "play_order" + ")",
};
final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistid);
Cursor cursor = null;
int base = 0;
try {
cursor = resolver.query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
base = cursor.getInt(0) + 1;
}
} finally {
if (cursor != null) {
cursor.close();
cursor = null;
}
}
int numinserted = 0;
for (int offSet = 0; offSet < size; offSet += 1000) {
makeInsertItems(ids, offSet, 1000, base);
numinserted += resolver.bulkInsert(uri, mContentValuesCache);
}
final String message = context.getResources().getQuantityString(
R.plurals.NNNtrackstoplaylist, numinserted, numinserted);
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
public static void makeInsertItems(final long[] ids, final int offset, int len, final int base) {
if (offset + len > ids.length) {
len = ids.length - offset;
}
if (mContentValuesCache == null || mContentValuesCache.length != len) {
mContentValuesCache = new ContentValues[len];
}
for (int i = 0; i < len; i++) {
if (mContentValuesCache[i] == null) {
mContentValuesCache[i] = new ContentValues();
}
mContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i);
mContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, ids[offset + i]);
}
}
/**
* 创建歌单
* @param context context to use
* @param name playlist name
* @return playlist id or -1 for fail
*/
public static long createPlaylist(final Context context, final String name) {
if (name != null && name.length() > 0) {
final ContentResolver resolver = context.getContentResolver();
final String[] projection = new String[]{
MediaStore.Audio.PlaylistsColumns.NAME
};
final String selection = MediaStore.Audio.PlaylistsColumns.NAME + " = '" + name + "'";
Cursor cursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
projection, selection, null, null);
if (cursor.getCount() <= 0) {
final ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
final Uri uri = resolver.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
values);
return Long.parseLong(uri.getLastPathSegment());
}
cursor.close();
cursor = null;
return -1;
}
return -1;
}
public static void renamePlaylist(final Context context, long playlistid, String newName) {
final ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.Playlists.NAME, newName);
resolver.update(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
values, "_id=" + playlistid, null);
}
public static void openFile(final String path) {
if (mService != null) {
try {
mService.openFile(path);
} catch (final RemoteException ignored) {
}
}
}
public static final class ServiceBinder implements ServiceConnection {
private final ServiceConnection mCallback;
private final Context mContext;
public ServiceBinder(final ServiceConnection callback, final Context context) {
mCallback = callback;
mContext = context;
}
@Override
public void onServiceConnected(final ComponentName className, final IBinder service) {
mService = IListenerService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
initPlaybackServiceWithSettings(mContext);
}
@Override
public void onServiceDisconnected(final ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
mService = null;
}
}
public static final class ServiceToken {
public ContextWrapper mWrappedContext;
public ServiceToken(final ContextWrapper context) {
mWrappedContext = context;
}
}
}