New API on java's MediaPlayer to suspend/resume a session.

related-to-bug: 2231576
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 89ee7d3..e8b89e0 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1064,6 +1064,53 @@
     private native void _reset();
 
     /**
+     * Suspends the MediaPlayer. The only methods that may be called while
+     * suspended are {@link #reset()}, {@link #release()} and {@link #resume()}.
+     * MediaPlayer will release its hardware resources as far as
+     * possible and reasonable. A successfully suspended MediaPlayer will
+     * cease sending events.
+     * If suspension is successful, this method returns true, otherwise
+     * false is returned and the player's state is not affected.
+     * @hide
+     */
+    public boolean suspend() {
+        if (native_suspend_resume(true) < 0) {
+            return false;
+        }
+
+        stayAwake(false);
+
+        // make sure none of the listeners get called anymore
+        mEventHandler.removeCallbacksAndMessages(null);
+
+        return true;
+    }
+
+    /**
+     * Resumes the MediaPlayer. Only to be called after a previous (successful)
+     * call to {@link #suspend()}.
+     * MediaPlayer will return to a state close to what it was in before
+     * suspension.
+     * @hide
+     */
+    public boolean resume() {
+        if (native_suspend_resume(false) < 0) {
+            return false;
+        }
+
+        if (isPlaying()) {
+            stayAwake(true);
+        }
+
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    private native int native_suspend_resume(boolean isSuspend);
+
+    /**
      * Sets the audio stream type for this MediaPlayer. See {@link AudioManager}
      * for a list of stream types.
      *
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2773e5c..8ed3730 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -692,6 +692,19 @@
     return ret;
 }
 
+static jint
+android_media_MediaPlayer_native_suspend_resume(
+        JNIEnv *env, jobject thiz, jboolean isSuspend) {
+    LOGV("suspend_resume(%d)", isSuspend);
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return UNKNOWN_ERROR;
+    }
+
+    return isSuspend ? mp->suspend() : mp->resume();
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -724,6 +737,7 @@
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
     {"snoop",               "([SI)I",                           (void *)android_media_MediaPlayer_snoop},
+    {"native_suspend_resume", "(Z)I",                           (void *)android_media_MediaPlayer_native_suspend_resume},
 };
 
 static const char* const kClassPathName = "android/media/MediaPlayer";
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 9c127d4..ed792b3 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -43,6 +43,8 @@
     INVOKE,
     SET_METADATA_FILTER,
     GET_METADATA,
+    SUSPEND,
+    RESUME,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -199,6 +201,26 @@
         remote()->transact(GET_METADATA, request, reply);
         return reply->readInt32();
     }
+
+    status_t suspend() {
+        Parcel request;
+        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        Parcel reply;
+        remote()->transact(SUSPEND, request, &reply);
+
+        return reply.readInt32();
+    }
+
+    status_t resume() {
+        Parcel request;
+        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        Parcel reply;
+        remote()->transact(RESUME, request, &reply);
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -299,6 +321,16 @@
             reply->writeInt32(setMetadataFilter(data));
             return NO_ERROR;
         } break;
+        case SUSPEND: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(suspend());
+            return NO_ERROR;
+        } break;
+        case RESUME: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(resume());
+            return NO_ERROR;
+        } break;
         case GET_METADATA: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 01cd8ce..2157814 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -167,6 +167,16 @@
     return INVALID_OPERATION;
 }
 
+status_t MediaPlayer::suspend() {
+    Mutex::Autolock _l(mLock);
+    return mPlayer->suspend();
+}
+
+status_t MediaPlayer::resume() {
+    Mutex::Autolock _l(mLock);
+    return mPlayer->resume();
+}
+
 status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
 {
     LOGD("setMetadataFilter");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 55b06f4..b4fc035 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -970,6 +970,20 @@
     return OK;
 }
 
+status_t MediaPlayerService::Client::suspend() {
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+
+    return p->suspend();
+}
+
+status_t MediaPlayerService::Client::resume() {
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+
+    return p->resume();
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     LOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index c9cae35..2408c62 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -222,6 +222,8 @@
         virtual status_t        getMetadata(bool update_only,
                                             bool apply_filter,
                                             Parcel *reply);
+        virtual status_t        suspend();
+        virtual status_t        resume();
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
 
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 1bfcf65..7776b4e 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -136,6 +136,16 @@
     return STAGEFRIGHT_PLAYER;
 }
 
+status_t StagefrightPlayer::suspend() {
+    LOGV("suspend");
+    return mPlayer->suspend();
+}
+
+status_t StagefrightPlayer::resume() {
+    LOGV("resume");
+    return mPlayer->resume();
+}
+
 status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
     return INVALID_OPERATION;
 }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 9e6674a..4446582 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -50,6 +50,8 @@
     virtual player_type playerType();
     virtual status_t invoke(const Parcel &request, Parcel *reply);
     virtual void setAudioSink(const sp<AudioSink> &audioSink);
+    virtual status_t suspend();
+    virtual status_t resume();
 
 private:
     AwesomePlayer *mPlayer;