Merge "VideoView: option for audio focus, support for AudioAttributes"
diff --git a/api/current.txt b/api/current.txt
index e58aa0c..568baf5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20798,6 +20798,7 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -50825,6 +50826,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
diff --git a/api/system-current.txt b/api/system-current.txt
index 367d471..6c59316 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -22465,6 +22465,7 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -54734,6 +54735,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
diff --git a/api/test-current.txt b/api/test-current.txt
index 78c2d50..6a75188 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -20894,6 +20894,7 @@
field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
+ field public static final int AUDIOFOCUS_NONE = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
@@ -51204,6 +51205,8 @@
method public int resolveAdjustedSize(int, int);
method public void resume();
method public void seekTo(int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
method public void setMediaController(android.widget.MediaController);
method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index b973324..7b2efea 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -16,11 +16,13 @@
package android.widget;
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Cea708CaptionRenderer;
import android.media.ClosedCaptionRenderer;
@@ -67,6 +69,14 @@
* {@link android.app.Activity#onRestoreInstanceState}.<p>
* Also note that the audio session id (from {@link #getAudioSessionId}) may
* change from its previously returned value when the VideoView is restored.
+ * <p>
+ * By default, VideoView requests audio focus with {@link AudioManager#AUDIOFOCUS_GAIN}. Use
+ * {@link #setAudioFocusRequest(int)} to change this behavior.
+ * <p>
+ * The default {@link AudioAttributes} used during playback have a usage of
+ * {@link AudioAttributes#USAGE_MEDIA} and a content type of
+ * {@link AudioAttributes#CONTENT_TYPE_MOVIE}, use {@link #setAudioAttributes(AudioAttributes)} to
+ * modify them.
*/
public class VideoView extends SurfaceView
implements MediaPlayerControl, SubtitleController.Anchor {
@@ -113,6 +123,9 @@
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
+ private AudioManager mAudioManager;
+ private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
+ private AudioAttributes mAudioAttributes;
/** Subtitle rendering widget overlaid on top of the video. */
private RenderingWidget mSubtitleWidget;
@@ -138,6 +151,10 @@
mVideoWidth = 0;
mVideoHeight = 0;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mAudioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE).build();
+
getHolder().addCallback(mSHCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
@@ -260,6 +277,41 @@
}
/**
+ * Sets which type of audio focus will be requested during the playback, or configures playback
+ * to not request audio focus. Valid values for focus requests are
+ * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. Or use
+ * {@link AudioManager#AUDIOFOCUS_NONE} to express that audio focus should not be
+ * requested when playback starts. You can for instance use this when playing a silent animation
+ * through this class, and you don't want to affect other audio applications playing in the
+ * background.
+ * @param focusGain the type of audio focus gain that will be requested, or
+ * {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during playback.
+ */
+ public void setAudioFocusRequest(int focusGain) {
+ if (focusGain != AudioManager.AUDIOFOCUS_NONE
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
+ && focusGain != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) {
+ throw new IllegalArgumentException("Illegal audio focus type " + focusGain);
+ }
+ mAudioFocusType = focusGain;
+ }
+
+ /**
+ * Sets the {@link AudioAttributes} to be used during the playback of the video.
+ * @param attributes non-null <code>AudioAttributes</code>.
+ */
+ public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Illegal null AudioAttributes");
+ }
+ mAudioAttributes = attributes;
+ }
+
+ /**
* Adds an external subtitle source file (from the provided input stream.)
*
* Note that a single external subtitle source may contain multiple or no
@@ -301,8 +353,7 @@
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
+ mAudioManager.abandonAudioFocus(null);
}
}
@@ -315,8 +366,10 @@
// called start() previously
release(false);
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ // TODO this should have a focus listener
+ mAudioManager.requestAudioFocus(null, mAudioAttributes, mAudioFocusType, 0 /*flags*/);
+ }
try {
mMediaPlayer = new MediaPlayer();
@@ -345,7 +398,7 @@
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
mMediaPlayer.setDisplay(mSurfaceHolder);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setAudioAttributes(mAudioAttributes);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
@@ -482,6 +535,9 @@
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ mAudioManager.abandonAudioFocus(null);
+ }
}
};
@@ -644,8 +700,9 @@
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- am.abandonAudioFocus(null);
+ if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
+ mAudioManager.abandonAudioFocus(null);
+ }
}
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a4f2a7e..95d354b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1981,8 +1981,7 @@
}
/**
- * @hide
- * Used to indicate no audio focus has been gained or lost.
+ * Used to indicate no audio focus has been gained or lost, or requested.
*/
public static final int AUDIOFOCUS_NONE = 0;
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index dd9c6a7..6b8a279 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -366,11 +366,18 @@
* @param pw
*/
public void dump(PrintWriter pw) {
- pw.println(" ID:" + mPlayerIId
- + " -- type:" + toLogFriendlyPlayerType(mPlayerType)
- + " -- u/pid:" + mClientUid +"/" + mClientPid
- + " -- state:" + toLogFriendlyPlayerState(mPlayerState)
- + " -- attr:" + mPlayerAttr);
+ pw.println(" " + toLogFriendlyString(this));
+ }
+
+ /**
+ * @hide
+ */
+ public static String toLogFriendlyString(AudioPlaybackConfiguration apc) {
+ return new String("ID:" + apc.mPlayerIId
+ + " -- type:" + toLogFriendlyPlayerType(apc.mPlayerType)
+ + " -- u/pid:" + apc.mClientUid +"/" + apc.mClientPid
+ + " -- state:" + toLogFriendlyPlayerState(apc.mPlayerState)
+ + " -- attr:" + apc.mPlayerAttr);
}
public static final Parcelable.Creator<AudioPlaybackConfiguration> CREATOR
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 1f64b65..e8ff510 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -47,6 +47,7 @@
implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
public final static String TAG = "AudioService.PlaybackActivityMonitor";
+
private final static boolean DEBUG = false;
private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;