Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e6a6e86 authored by RoboErik's avatar RoboErik Committed by Android (Google) Code Review
Browse files

Merge "Add Session API calls to RCC and AudioManager"

parents 67e2196d f1372428
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -15103,6 +15103,7 @@ package android.media.routeprovider {
package android.media.session {
  public final class MediaMetadata implements android.os.Parcelable {
    method public boolean containsKey(java.lang.String);
    method public int describeContents();
    method public android.graphics.Bitmap getBitmap(java.lang.String);
    method public long getLong(java.lang.String);
@@ -15118,6 +15119,7 @@ package android.media.session {
    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
@@ -15150,25 +15152,25 @@ package android.media.session {
    method public long getBufferPosition();
    method public java.lang.String getErrorMessage();
    method public long getPosition();
    method public float getSpeed();
    method public float getRate();
    method public int getState();
    method public void setActions(long);
    method public void setBufferPosition(long);
    method public void setErrorMessage(java.lang.String);
    method public void setPosition(long);
    method public void setSpeed(float);
    method public void setState(int);
    method public void setState(int, long, float);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final long ACTION_FASTFORWARD = 64L; // 0x40L
    field public static final long ACTION_NEXT_ITEM = 32L; // 0x20L
    field public static final long ACTION_PAUSE = 2L; // 0x2L
    field public static final long ACTION_PLAY = 4L; // 0x4L
    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
    field public static final long ACTION_PREVIOUS_ITEM = 16L; // 0x10L
    field public static final long ACTION_RATING = 128L; // 0x80L
    field public static final long ACTION_REWIND = 8L; // 0x8L
    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
    field public static final long ACTION_STOP = 1L; // 0x1L
    field public static final android.os.Parcelable.Creator CREATOR;
    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
    field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
    field public static final int PLAYSTATE_CONNECTING = 8; // 0x8
    field public static final int PLAYSTATE_ERROR = 7; // 0x7
@@ -15177,6 +15179,8 @@ package android.media.session {
    field public static final int PLAYSTATE_PAUSED = 2; // 0x2
    field public static final int PLAYSTATE_PLAYING = 3; // 0x3
    field public static final int PLAYSTATE_REWINDING = 5; // 0x5
    field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 9; // 0x9
    field public static final int PLAYSTATE_SKIPPING_FORWARDS = 10; // 0xa
    field public static final int PLAYSTATE_STOPPED = 1; // 0x1
  }
+23 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.RemoteController.OnClientUpdateListener;
import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -48,6 +49,12 @@ import java.util.HashMap;
 */
public class AudioManager {

    // If we should use the new sessions APIs.
    private final static boolean USE_SESSIONS = true;
    // If we should use the legacy APIs. If both are true information will be
    // duplicated through both paths. Currently this flag isn't used.
    private final static boolean USE_LEGACY = true;

    private final Context mContext;
    private long mVolumeKeyUpTime;
    private final boolean mUseMasterVolume;
@@ -421,6 +428,7 @@ public class AudioManager {
    public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;

    private static IAudioService sService;
    private MediaSessionLegacyHelper mSessionHelper;

    /**
     * @hide
@@ -431,6 +439,9 @@ public class AudioManager {
                com.android.internal.R.bool.config_useMasterVolume);
        mUseVolumeKeySounds = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_useVolumeKeySounds);
        if (USE_SESSIONS) {
            mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
        }
    }

    private static IAudioService getService()
@@ -2166,6 +2177,9 @@ public class AudioManager {
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
        }
        if (USE_SESSIONS) {
            mSessionHelper.addMediaButtonListener(pi, mContext);
        }
    }

    /**
@@ -2239,6 +2253,9 @@ public class AudioManager {
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
        }
        if (USE_SESSIONS) {
            mSessionHelper.removeMediaButtonListener(pi);
        }
    }

    /**
@@ -2263,6 +2280,9 @@ public class AudioManager {
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
        }
        if (USE_SESSIONS) {
            rcClient.registerWithSession(mSessionHelper);
        }
    }

    /**
@@ -2282,6 +2302,9 @@ public class AudioManager {
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
        }
        if (USE_SESSIONS) {
            rcClient.unregisterWithSession(mSessionHelper);
        }
    }

    /**
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;

import android.graphics.Bitmap;
import android.media.session.MediaMetadata;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -106,6 +107,10 @@ public abstract class MediaMetadataEditor {
     */
    protected Bundle mEditorMetadata;

    /**
     * @hide
     */
    protected MediaMetadata.Builder mMetadataBuilder;

    /**
     * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
@@ -120,6 +125,7 @@ public abstract class MediaMetadataEditor {
        }
        mEditorMetadata.clear();
        mEditorArtwork = null;
        mMetadataBuilder = new MediaMetadata.Builder();
    }

    /**
+117 −12
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.media.session.MediaMetadata;
import android.media.session.MediaSessionLegacyHelper;
import android.media.session.PlaybackState;
import android.media.session.Session;
import android.media.session.TransportPerformer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -336,6 +341,8 @@ public class RemoteControlClient
     */
    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;

    private Session mSession;

    /**
     * Class constructor.
     * @param mediaButtonIntent The intent that will be sent for the media button events sent
@@ -384,6 +391,22 @@ public class RemoteControlClient
        mEventHandler = new EventHandler(this, looper);
    }

    /**
     * @hide
     */
    public void registerWithSession(MediaSessionLegacyHelper helper) {
        helper.addRccListener(mRcMediaIntent, mTransportListener);
        mSession = helper.getSession(mRcMediaIntent);
    }

    /**
     * @hide
     */
    public void unregisterWithSession(MediaSessionLegacyHelper helper) {
        helper.removeRccListener(mRcMediaIntent);
        mSession = null;
    }

    /**
     * Class used to modify metadata in a {@link RemoteControlClient} object.
     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -438,6 +461,15 @@ public class RemoteControlClient
        public synchronized MetadataEditor putString(int key, String value)
                throws IllegalArgumentException {
            super.putString(key, value);
            if (mMetadataBuilder != null) {
                // MediaMetadata supports all the same fields as MetadataEditor
                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
                // But just in case, don't add things we don't understand
                if (metadataKey != null) {
                    mMetadataBuilder.putString(metadataKey, value);
                }
            }

            return this;
        }

@@ -459,6 +491,14 @@ public class RemoteControlClient
        public synchronized MetadataEditor putLong(int key, long value)
                throws IllegalArgumentException {
            super.putLong(key, value);
            if (mMetadataBuilder != null) {
                // MediaMetadata supports all the same fields as MetadataEditor
                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
                // But just in case, don't add things we don't understand
                if (metadataKey != null) {
                    mMetadataBuilder.putLong(metadataKey, value);
                }
            }
            return this;
        }

@@ -476,6 +516,14 @@ public class RemoteControlClient
        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
                throws IllegalArgumentException {
            super.putBitmap(key, bitmap);
            if (mMetadataBuilder != null) {
                // MediaMetadata supports all the same fields as MetadataEditor
                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
                // But just in case, don't add things we don't understand
                if (metadataKey != null) {
                    mMetadataBuilder.putBitmap(metadataKey, bitmap);
                }
            }
            return this;
        }

@@ -521,6 +569,11 @@ public class RemoteControlClient
                    // send to remote control display if conditions are met
                    sendArtwork_syncCacheLock(null, 0, 0);
                }

                // USE_SESSIONS
                if (mSession != null && mMetadataBuilder != null) {
                    mSession.getTransportPerformer().setMetadata(mMetadataBuilder.build());
                }
                mApplied = true;
            }
        }
@@ -546,6 +599,12 @@ public class RemoteControlClient
            editor.mMetadataChanged = false;
            editor.mArtworkChanged = false;
        }
        // USE_SESSIONS
        if (startEmpty || mMediaMetadata == null) {
            editor.mMetadataBuilder = new MediaMetadata.Builder();
        } else {
            editor.mMetadataBuilder = new MediaMetadata.Builder(mMediaMetadata);
        }
        return editor;
    }

@@ -624,6 +683,15 @@ public class RemoteControlClient

                // handle automatic playback position refreshes
                initiateCheckForDrift_syncCacheLock();

                // USE_SESSIONS
                if (mSession != null) {
                    int pbState = PlaybackState.getStateFromRccState(state);
                    mSessionPlaybackState.setState(pbState, hasPosition ?
                            mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
                            playbackSpeed);
                    mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
                }
            }
        }
    }
@@ -704,6 +772,13 @@ public class RemoteControlClient

            // send to remote control display if conditions are met
            sendTransportControlInfo_syncCacheLock(null);

            // USE_SESSIONS
            if (mSession != null) {
                mSessionPlaybackState.setActions(PlaybackState
                        .getActionsFromRccControlFlags(transportControlFlags));
                mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
            }
        }
    }

@@ -1037,6 +1112,16 @@ public class RemoteControlClient
    // TODO consider using a ref count for IRemoteControlDisplay requiring sync instead
    private boolean mNeedsPositionSync = false;

    /**
     * Cache for the current playback state using Session APIs.
     */
    private final PlaybackState mSessionPlaybackState = new PlaybackState();

    /**
     * Cache for metadata using Session APIs. This is re-initialized in apply().
     */
    private MediaMetadata mMediaMetadata;

    /**
     * A class to encapsulate all the information about a remote control display.
     * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
@@ -1219,6 +1304,26 @@ public class RemoteControlClient
        return mRcseId;
    }

    // USE_SESSIONS
    private TransportPerformer.Listener mTransportListener = new TransportPerformer.Listener() {

        @Override
        public void onSeekTo(long pos) {
            RemoteControlClient.this.onSeekTo(mCurrentClientGenId, pos);
        }

        @Override
        public void onRate(Rating rating) {
            if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
                if (mEventHandler != null) {
                    mEventHandler.sendMessage(mEventHandler.obtainMessage(
                            MSG_UPDATE_METADATA, mCurrentClientGenId,
                            MetadataEditor.RATING_KEY_BY_USER, rating));
                }
            }
        }
    };

    private EventHandler mEventHandler;
    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
    private final static int MSG_REQUEST_METADATA = 2;
@@ -1325,7 +1430,7 @@ public class RemoteControlClient
            // target == null implies all displays must be updated
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mEnabled) {
                    try {
                        di.mRcDisplay.setPlaybackState(mInternalClientGenId,
@@ -1353,7 +1458,7 @@ public class RemoteControlClient
            // target == null implies all displays must be updated
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mEnabled) {
                    try {
                        di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
@@ -1381,7 +1486,7 @@ public class RemoteControlClient
            // target == null implies all displays must be updated
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mEnabled) {
                    try {
                        di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
@@ -1407,7 +1512,7 @@ public class RemoteControlClient
            // target == null implies all displays must be updated
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
                if (!sendArtworkToDisplay(displayIterator.next())) {
                    displayIterator.remove();
                }
            }
@@ -1453,7 +1558,7 @@ public class RemoteControlClient
            // target == null implies all displays must be updated
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                try {
                    if (di.mEnabled) {
                        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
@@ -1537,7 +1642,7 @@ public class RemoteControlClient
            boolean displayKnown = false;
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext() && !displayKnown) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
                if (displayKnown) {
                    // this display was known but the change in artwork size will cause the
@@ -1562,7 +1667,7 @@ public class RemoteControlClient
        synchronized(mCacheLock) {
            Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                    displayIterator.remove();
                    break;
@@ -1573,7 +1678,7 @@ public class RemoteControlClient
            boolean newNeedsPositionSync = false;
            displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mWantsPositionSync) {
                    newNeedsPositionSync = true;
                    break;
@@ -1592,7 +1697,7 @@ public class RemoteControlClient
        synchronized(mCacheLock) {
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
                        ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
                    di.mArtworkExpectedWidth = w;
@@ -1617,7 +1722,7 @@ public class RemoteControlClient
            // go through the list of RCDs and for each entry, check both whether this is the RCD
            //  that gets upated, and whether the list has one entry that wants position sync
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mEnabled) {
                    if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                        di.mWantsPositionSync = wantsSync;
@@ -1640,7 +1745,7 @@ public class RemoteControlClient
        synchronized(mCacheLock) {
            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
            while (displayIterator.hasNext()) {
                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                final DisplayInfoForClient di = displayIterator.next();
                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                    di.mEnabled = enable;
                }
+69 −7
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@
package android.media.session;

import android.graphics.Bitmap;
import android.media.MediaMetadataEditor;
import android.media.MediaMetadataRetriever;
import android.media.Rating;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;

/**
 * Contains metadata about an item, such as the title, artist, etc.
@@ -40,7 +43,8 @@ public final class MediaMetadata implements Parcelable {
    public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";

    /**
     * The duration of the media in ms. A duration of 0 is the default.
     * The duration of the media in ms. A negative duration indicates that the
     * duration is unknown (or infinite).
     */
    public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";

@@ -64,13 +68,18 @@ public final class MediaMetadata implements Parcelable {
     */
    public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";

    /**
     * The compilation status of the media.
     */
    public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";

    /**
     * The date the media was created or published as TODO determine format.
     */
    public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";

    /**
     * The year the media was created or published as a numeric String.
     * The year the media was created or published as a long.
     */
    public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";

@@ -151,8 +160,9 @@ public final class MediaMetadata implements Parcelable {
        METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
        METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_STRING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
        METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
@@ -165,6 +175,36 @@ public final class MediaMetadata implements Parcelable {
        METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
        METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
    }

    private static final SparseArray<String> EDITOR_KEY_MAPPING;

    static {
        EDITOR_KEY_MAPPING = new SparseArray<String>();
        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
                METADATA_KEY_ALBUM_ARTIST);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
                METADATA_KEY_TRACK_NUMBER);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
                METADATA_KEY_COMPILATION);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
                METADATA_KEY_DISC_NUMBER);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
                METADATA_KEY_NUM_TRACKS);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
    }

    private final Bundle mBundle;

    private MediaMetadata(Bundle bundle) {
@@ -175,6 +215,16 @@ public final class MediaMetadata implements Parcelable {
        mBundle = in.readBundle();
    }

    /**
     * Returns true if the given key is contained in the metadata
     *
     * @param key a String key
     * @return true if the key exists in this metadata, false otherwise
     */
    public boolean containsKey(String key) {
        return mBundle.containsKey(key);
    }

    /**
     * Returns the value associated with the given key, or null if no mapping of
     * the desired type exists for the given key or a null value is explicitly
@@ -195,7 +245,7 @@ public final class MediaMetadata implements Parcelable {
     * @return a long value
     */
    public long getLong(String key) {
        return mBundle.getLong(key);
        return mBundle.getLong(key, 0);
    }

    /**
@@ -244,6 +294,18 @@ public final class MediaMetadata implements Parcelable {
        dest.writeBundle(mBundle);
    }

    /**
     * Helper for getting the String key used by {@link MediaMetadata} from the
     * integer key that {@link MediaMetadataEditor} uses.
     *
     * @param editorKey The key used by the editor
     * @return The key used by this class or null if no mapping exists
     * @hide
     */
    public static String getKeyFromMetadataEditorKey(int editorKey) {
        return EDITOR_KEY_MAPPING.get(editorKey, null);
    }

    public static final Parcelable.Creator<MediaMetadata> CREATOR
            = new Parcelable.Creator<MediaMetadata>() {
                @Override
@@ -295,10 +357,9 @@ public final class MediaMetadata implements Parcelable {
         * <li>{@link #METADATA_KEY_WRITER}</li>
         * <li>{@link #METADATA_KEY_COMPOSER}</li>
         * <li>{@link #METADATA_KEY_DATE}</li>
         * <li>{@link #METADATA_KEY_YEAR}</li>
         * <li>{@link #METADATA_KEY_GENRE}</li>
         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>li>
         * <li>{@link #METADATA_KEY_ART_URI}</li>li>
         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
         * <li>{@link #METADATA_KEY_ART_URI}</li>
         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
         * </ul>
         *
@@ -326,6 +387,7 @@ public final class MediaMetadata implements Parcelable {
         * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
         * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
         * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
         * <li>{@link #METADATA_KEY_YEAR}</li>
         * </ul>
         *
         * @param key The key for referencing this value
Loading