package me.barrasso.android.volume.media.compat;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.service.notification.NotificationListenerService;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import java.io.FileNotFoundException;
/**
* Compatibility class for dealing with {@link android.media.RemoteController}
* and {@link android.media.session.MediaController} APIs.
*/
public abstract class RemoteControlCompat {
/** {@link java.lang.String} extra with the package name of the originating app. */
public static final String METADATA_KEY_PACKAGE = "package";
/** {@link java.lang.Long} extra with the time, in milliseconds, when the event occurred. */
public static final String METADATA_KEY_TIMESTAMP = "timestamp";
/**
* @return The {@link android.graphics.Bitmap} references by {@link android.support.v4.media.MediaMetadataCompat}
* @throws FileNotFoundException If an error parsing the {@link android.net.Uri} occurred.
*/
public static Bitmap getBitmap(Context context, MediaMetadataCompat metadata) throws FileNotFoundException{
if (null == metadata) return null;
Bitmap albumArtBitmap = metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
// No album art... check the URI.
if (null == albumArtBitmap) {
String albumArtUri = metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI);
// Still no URI... check the art URI.
if (TextUtils.isEmpty(albumArtUri))
albumArtUri = metadata.getString(MediaMetadataCompat.METADATA_KEY_ART_URI);
// If we've got a URI, try to load it.
if (!TextUtils.isEmpty(albumArtUri)) {
ContentResolver cr = context.getContentResolver();
albumArtBitmap = BitmapFactory.decodeStream(cr.openInputStream(Uri.parse(albumArtUri)));
}
}
return albumArtBitmap;
}
/** @see {@link #getBitmap(android.content.Context, android.support.v4.media.MediaMetadataCompat)} */
public static Bitmap getIcon(Context context, MediaMetadataCompat metadata) throws FileNotFoundException{
if (null == metadata) return null;
Bitmap albumArtBitmap = metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON);
// No icon... check the URI.
if (null == albumArtBitmap) {
String albumArtUri = metadata.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI);
// If we've got a URI, try to load it.
if (!TextUtils.isEmpty(albumArtUri)) {
ContentResolver cr = context.getContentResolver();
albumArtBitmap = BitmapFactory.decodeStream(cr.openInputStream(Uri.parse(albumArtUri)));
}
}
return albumArtBitmap;
}
/** Listener for media-related events. */
public static interface MediaControlListener {
void onMetadataChanged(MediaMetadataCompat metadata);
void onPlaybackStateChanged(PlaybackStateCompat state);
}
public static RemoteControlCompat get(Context context, Class<? extends NotificationListenerService> clazz) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
return new RemoteControlLollipop(context, clazz);
return new RemoteControlKitKat(context);
}
public static boolean isPlaying(PlaybackStateCompat state) {
if (null == state) return false;
switch (state.getState()) {
case PlaybackStateCompat.STATE_PLAYING:
case PlaybackStateCompat.STATE_FAST_FORWARDING:
case PlaybackStateCompat.STATE_REWINDING:
case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
return true;
}
return false;
}
protected MediaControlListener mListener;
protected final Context mContext;
// The last state and metadata change.
protected PlaybackStateCompat mPlaybackState;
protected MediaMetadataCompat mMetadata;
public MediaMetadataCompat getMetadata() { return mMetadata; }
public PlaybackStateCompat getPlaybackState() { return mPlaybackState; }
public RemoteControlCompat(Context context) {
mContext = context;
}
public void setMediaControlListener(MediaControlListener listener) {
mListener = listener;
}
public void release() { /* No-op */ }
abstract boolean isRegistered();
protected void metadataChanged(MediaMetadataCompat metadata) {
// Append a timestamp to know when this event occurred.
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(metadata);
builder.putLong(METADATA_KEY_TIMESTAMP, System.currentTimeMillis());
mMetadata = builder.build();
if (null != mListener && null != mMetadata && null != mPlaybackState)
mListener.onMetadataChanged(metadata);
}
protected void playbackStateChanged(PlaybackStateCompat state) {
mPlaybackState = state;
if (null != mListener && null != mMetadata && null != mPlaybackState)
mListener.onPlaybackStateChanged(state);
}
/**
* @return {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
*/
protected final String getPermission() {
String permission;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
permission = Manifest.permission.MEDIA_CONTENT_CONTROL;
} else {
permission = "android.permission.MEDIA_CONTENT_CONTROL";
}
return permission;
}
/**
* @see android.Manifest.permission#MEDIA_CONTENT_CONTROL
* @return True if this app holds the media control permission.
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public final boolean hasPermission() {
PackageManager pm = mContext.getPackageManager();
int result = pm.checkPermission(getPermission(), mContext.getPackageName());
return (result == PackageManager.PERMISSION_GRANTED);
}
/** @return {@link android.support.v4.media.MediaMetadataCompat} log info (what keys it contains). */
public static String getMediaMetadataLog(MediaMetadataCompat metadata) {
if (null == metadata) return "";
final String[] METADATA_KEYS = new String[] {
MediaMetadataCompat.METADATA_KEY_ALBUM,
MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST,
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
MediaMetadataCompat.METADATA_KEY_ART,
MediaMetadataCompat.METADATA_KEY_ARTIST,
MediaMetadataCompat.METADATA_KEY_ART_URI,
MediaMetadataCompat.METADATA_KEY_AUTHOR,
MediaMetadataCompat.METADATA_KEY_COMPILATION,
MediaMetadataCompat.METADATA_KEY_COMPOSER,
MediaMetadataCompat.METADATA_KEY_DATE,
MediaMetadataCompat.METADATA_KEY_DISC_NUMBER,
MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON,
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,
MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE,
MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE,
MediaMetadataCompat.METADATA_KEY_DURATION,
MediaMetadataCompat.METADATA_KEY_GENRE,
MediaMetadataCompat.METADATA_KEY_NUM_TRACKS,
MediaMetadataCompat.METADATA_KEY_RATING,
MediaMetadataCompat.METADATA_KEY_TITLE,
MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER,
MediaMetadataCompat.METADATA_KEY_USER_RATING,
MediaMetadataCompat.METADATA_KEY_WRITER,
MediaMetadataCompat.METADATA_KEY_YEAR };
StringBuffer builder = new StringBuffer("{");
for (String key : METADATA_KEYS)
builder.append(key).append('=').append(
(metadata.containsKey(key)) ? metadata.getText(key) : false).append(',');
builder.append('}');
return builder.toString();
}
}