Handle audio focus in HTML5 audio

    Bug: 5416191

    Video will follow later

Change-Id: I51da05aa0e3c8c0f33151df84d84a65cb7003080
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
index 3600d09..9fc48a1 100644
--- a/core/java/android/webkit/HTML5Audio.java
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -16,12 +16,9 @@
 
 package android.webkit;
 
+import android.content.Context;
+import android.media.AudioManager;
 import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnBufferingUpdateListener;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.MediaPlayer.OnPreparedListener;
-import android.media.MediaPlayer.OnSeekCompleteListener;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -45,7 +42,8 @@
                             MediaPlayer.OnCompletionListener,
                             MediaPlayer.OnErrorListener,
                             MediaPlayer.OnPreparedListener,
-                            MediaPlayer.OnSeekCompleteListener {
+                            MediaPlayer.OnSeekCompleteListener,
+                            AudioManager.OnAudioFocusChangeListener {
     // Logging tag.
     private static final String LOGTAG = "HTML5Audio";
 
@@ -69,6 +67,7 @@
 
     private String mUrl;
     private boolean mAskToPlay = false;
+    private Context mContext;
 
     // Timer thread -> UI thread
     private static final int TIMEUPDATE = 100;
@@ -183,6 +182,7 @@
         // Save the native ptr
         mNativePointer = nativePtr;
         resetMediaPlayer();
+        mContext = webViewCore.getContext();
         mIsPrivateBrowsingEnabledGetter = new IsPrivateBrowsingEnabledGetter(
                 webViewCore.getContext().getMainLooper(), webViewCore.getWebView());
     }
@@ -233,6 +233,34 @@
         }
     }
 
+    @Override
+    public void onAudioFocusChange(int focusChange) {
+        switch (focusChange) {
+        case AudioManager.AUDIOFOCUS_GAIN:
+            // resume playback
+            if (mMediaPlayer == null) resetMediaPlayer();
+            else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
+            mState = STARTED;
+            break;
+
+        case AudioManager.AUDIOFOCUS_LOSS:
+            // Lost focus for an unbounded amount of time: stop playback and release media player
+            if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+            break;
+
+        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+            // Lost focus for a short time, but we have to stop
+            // playback. We don't release the media player because playback
+            // is likely to resume
+            if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
+            break;
+        }
+    }
+
+
     private void play() {
         if ((mState >= ERROR && mState < PREPARED) && mUrl != null) {
             resetMediaPlayer();
@@ -241,8 +269,17 @@
         }
 
         if (mState >= PREPARED) {
-            mMediaPlayer.start();
-            mState = STARTED;
+            AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+            int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
+                AudioManager.AUDIOFOCUS_GAIN);
+
+            if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+                // could not get audio focus.
+                teardown();
+            } else {
+                mMediaPlayer.start();
+                mState = STARTED;
+            }
         }
     }
 
@@ -276,4 +313,5 @@
     private native void nativeOnEnded(int nativePointer);
     private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
     private native void nativeOnTimeupdate(int position, int nativePointer);
+
 }