Merge "Add support for AudioAttributes in android.media.Ringtone" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 4ab730d..5c2a9d5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15762,11 +15762,12 @@
   }
 
   public class Ringtone {
-    method public int getStreamType();
+    method public deprecated int getStreamType();
     method public java.lang.String getTitle(android.content.Context);
     method public boolean isPlaying();
     method public void play();
-    method public void setStreamType(int);
+    method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method public deprecated void setStreamType(int);
     method public void stop();
   }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d8a219f..5f58839 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -279,6 +279,7 @@
      *
      * @deprecated Use {@link #audioAttributes} instead.
      */
+    @Deprecated
     public static final int STREAM_DEFAULT = -1;
 
     /**
@@ -288,6 +289,7 @@
      *
      * @deprecated Use {@link #audioAttributes} instead.
      */
+    @Deprecated
     public int audioStreamType = STREAM_DEFAULT;
 
     /**
@@ -2193,6 +2195,7 @@
          * @deprecated use {@link #setSound(Uri, AudioAttributes)} instead.
          * @see Notification#sound
          */
+        @Deprecated
         public Builder setSound(Uri sound, int streamType) {
             mSound = sound;
             mAudioStreamType = streamType;
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 0872f1d..7c011e6 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.UserHandle;
 
@@ -24,11 +25,11 @@
  */
 interface IRingtonePlayer {
     /** Used for Ringtone.java playback */
-    void play(IBinder token, in Uri uri, int streamType);
+    void play(IBinder token, in Uri uri, in AudioAttributes aa);
     void stop(IBinder token);
     boolean isPlaying(IBinder token);
 
     /** Used for Notification sound playback. */
-    void playAsync(in Uri uri, in UserHandle user, boolean looping, int streamType);
+    void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
     void stopAsync();
 }
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 2616b6c..a221104 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -60,7 +60,10 @@
     private Uri mUri;
     private String mTitle;
 
-    private int mStreamType = AudioManager.STREAM_RING;
+    private AudioAttributes mAudioAttributes = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
 
     /** {@hide} */
     public Ringtone(Context context, boolean allowRemote) {
@@ -75,22 +78,40 @@
      * Sets the stream type where this ringtone will be played.
      * 
      * @param streamType The stream, see {@link AudioManager}.
+     * @deprecated use {@link #setAudioAttributes(AudioAttributes)}
      */
+    @Deprecated
     public void setStreamType(int streamType) {
-        mStreamType = streamType;
-
-        // The stream type has to be set before the media player is prepared.
-        // Re-initialize it.
-        setUri(mUri);
+        setAudioAttributes(new AudioAttributes.Builder()
+                .setInternalLegacyStreamType(streamType)
+                .build());
     }
 
     /**
      * Gets the stream type where this ringtone will be played.
      * 
      * @return The stream type, see {@link AudioManager}.
+     * @deprecated use of stream types is deprecated, see
+     *     {@link #setAudioAttributes(AudioAttributes)}
      */
+    @Deprecated
     public int getStreamType() {
-        return mStreamType;
+        return AudioAttributes.toLegacyStreamType(mAudioAttributes);
+    }
+
+    /**
+     * Sets the {@link AudioAttributes} for this ringtone.
+     * @param attributes the non-null attributes characterizing this ringtone.
+     */
+    public void setAudioAttributes(AudioAttributes attributes)
+            throws IllegalArgumentException {
+        if (attributes == null) {
+            throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone");
+        }
+        mAudioAttributes = attributes;
+        // The audio attributes have to be set before the media player is prepared.
+        // Re-initialize it.
+        setUri(mUri);
     }
 
     /**
@@ -178,7 +199,7 @@
         mLocalPlayer = new MediaPlayer();
         try {
             mLocalPlayer.setDataSource(mContext, mUri);
-            mLocalPlayer.setAudioStreamType(mStreamType);
+            mLocalPlayer.setAudioAttributes(mAudioAttributes);
             mLocalPlayer.prepare();
 
         } catch (SecurityException e) {
@@ -214,13 +235,14 @@
         if (mLocalPlayer != null) {
             // do not play ringtones if stream volume is 0
             // (typically because ringer mode is silent).
-            if (mAudioManager.getStreamVolume(mStreamType) != 0) {
+            if (mAudioManager.getStreamVolume(
+                    AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
                 mLocalPlayer.start();
             }
         } else if (mAllowRemote && (mRemotePlayer != null)) {
             final Uri canonicalUri = mUri.getCanonicalUri();
             try {
-                mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
+                mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes);
             } catch (RemoteException e) {
                 if (!playFallbackRingtone()) {
                     Log.w(TAG, "Problem playing ringtone: " + e);
@@ -278,7 +300,8 @@
     }
 
     private boolean playFallbackRingtone() {
-        if (mAudioManager.getStreamVolume(mStreamType) != 0) {
+        if (mAudioManager.getStreamVolume(AudioAttributes.toLegacyStreamType(mAudioAttributes))
+                != 0) {
             int ringtoneType = RingtoneManager.getDefaultType(mUri);
             if (ringtoneType == -1 ||
                     RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) != null) {
@@ -295,7 +318,7 @@
                                     afd.getStartOffset(),
                                     afd.getDeclaredLength());
                         }
-                        mLocalPlayer.setAudioStreamType(mStreamType);
+                        mLocalPlayer.setAudioAttributes(mAudioAttributes);
                         mLocalPlayer.prepare();
                         mLocalPlayer.start();
                         afd.close();
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index f8b347c..803a014 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -17,6 +17,7 @@
 package com.android.systemui.media;
 
 import android.content.Context;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
@@ -45,11 +46,11 @@
         Context context;
         Uri uri;
         boolean looping;
-        int stream;
+        AudioAttributes attributes;
         long requestTime;
 
         public String toString() {
-            return "{ code=" + code + " looping=" + looping + " stream=" + stream
+            return "{ code=" + code + " looping=" + looping + " attributes=" + attributes
                     + " uri=" + uri + " }";
         }
     }
@@ -79,7 +80,7 @@
                     (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
                 try {
                     MediaPlayer player = new MediaPlayer();
-                    player.setAudioStreamType(mCmd.stream);
+                    player.setAudioAttributes(mCmd.attributes);
                     player.setDataSource(mCmd.context, mCmd.uri);
                     player.setLooping(mCmd.looping);
                     player.prepare();
@@ -90,10 +91,12 @@
                                 if (mAudioManagerWithAudioFocus == null) {
                                     if (mDebug) Log.d(mTag, "requesting AudioFocus");
                                     if (mCmd.looping) {
-                                        audioManager.requestAudioFocus(null, mCmd.stream,
+                                        audioManager.requestAudioFocus(null,
+                                                AudioAttributes.toLegacyStreamType(mCmd.attributes),
                                                 AudioManager.AUDIOFOCUS_GAIN);
                                     } else {
-                                        audioManager.requestAudioFocus(null, mCmd.stream,
+                                        audioManager.requestAudioFocus(null,
+                                                AudioAttributes.toLegacyStreamType(mCmd.attributes),
                                                 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
                                     }
                                     mAudioManagerWithAudioFocus = audioManager;
@@ -280,7 +283,9 @@
      *          (see {@link MediaPlayer#setLooping(boolean)})
      * @param stream the AudioStream to use.
      *          (see {@link MediaPlayer#setAudioStreamType(int)})
+     * @deprecated use {@link #play(Context, Uri, boolean, AudioAttributes)} instead.
      */
+    @Deprecated
     public void play(Context context, Uri uri, boolean looping, int stream) {
         Command cmd = new Command();
         cmd.requestTime = SystemClock.uptimeMillis();
@@ -288,7 +293,34 @@
         cmd.context = context;
         cmd.uri = uri;
         cmd.looping = looping;
-        cmd.stream = stream;
+        cmd.attributes = new AudioAttributes.Builder().setInternalLegacyStreamType(stream).build();
+        synchronized (mCmdQueue) {
+            enqueueLocked(cmd);
+            mState = PLAY;
+        }
+    }
+
+    /**
+     * Start playing the sound.  It will actually start playing at some
+     * point in the future.  There are no guarantees about latency here.
+     * Calling this before another audio file is done playing will stop
+     * that one and start the new one.
+     *
+     * @param context Your application's context.
+     * @param uri The URI to play.  (see {@link MediaPlayer#setDataSource(Context, Uri)})
+     * @param looping Whether the audio should loop forever.
+     *          (see {@link MediaPlayer#setLooping(boolean)})
+     * @param attributes the AudioAttributes to use.
+     *          (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)})
+     */
+    public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
+        Command cmd = new Command();
+        cmd.requestTime = SystemClock.uptimeMillis();
+        cmd.code = PLAY;
+        cmd.context = context;
+        cmd.uri = uri;
+        cmd.looping = looping;
+        cmd.attributes = attributes;
         synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 5b4bb2c..7eed7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.AudioAttributes;
 import android.media.IAudioService;
 import android.media.IRingtonePlayer;
 import android.media.Ringtone;
@@ -71,11 +72,11 @@
         private final IBinder mToken;
         private final Ringtone mRingtone;
 
-        public Client(IBinder token, Uri uri, UserHandle user, int streamType) {
+        public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
             mToken = token;
 
             mRingtone = new Ringtone(getContextForUser(user), false);
-            mRingtone.setStreamType(streamType);
+            mRingtone.setAudioAttributes(aa);
             mRingtone.setUri(uri);
         }
 
@@ -91,7 +92,7 @@
 
     private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
         @Override
-        public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
+        public void play(IBinder token, Uri uri, AudioAttributes aa) throws RemoteException {
             if (LOGD) {
                 Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
                         + Binder.getCallingUid() + ")");
@@ -101,7 +102,7 @@
                 client = mClients.get(token);
                 if (client == null) {
                     final UserHandle user = Binder.getCallingUserHandle();
-                    client = new Client(token, uri, user, streamType);
+                    client = new Client(token, uri, user, aa);
                     token.linkToDeath(client, 0);
                     mClients.put(token, client);
                 }
@@ -137,13 +138,13 @@
         }
 
         @Override
-        public void playAsync(Uri uri, UserHandle user, boolean looping, int streamType) {
+        public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
             if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Async playback only available from system UID.");
             }
 
-            mAsyncPlayer.play(getContextForUser(user), uri, looping, streamType);
+            mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8e11f37..d6afe68 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1761,26 +1761,27 @@
             if (hasValidSound) {
                 boolean looping =
                         (notification.flags & Notification.FLAG_INSISTENT) != 0;
-                int audioStreamType;
-                if (notification.audioStreamType >= 0) {
-                    audioStreamType = notification.audioStreamType;
+                AudioAttributes audioAttributes;
+                if (notification.audioAttributes != null) {
+                    audioAttributes = notification.audioAttributes;
                 } else {
-                    audioStreamType = DEFAULT_STREAM_TYPE;
+                    audioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
                 }
                 mSoundNotification = record;
                 // do not play notifications if stream volume is 0 (typically because
                 // ringer mode is silent) or if there is a user of exclusive audio focus
-                if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
-                        && !mAudioManager.isAudioFocusExclusive()) {
+                if ((mAudioManager.getStreamVolume(
+                        AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
+                            && !mAudioManager.isAudioFocusExclusive()) {
                     final long identity = Binder.clearCallingIdentity();
                     try {
                         final IRingtonePlayer player =
                                 mAudioManager.getRingtonePlayer();
                         if (player != null) {
                             if (DBG) Slog.v(TAG, "Playing sound " + soundUri
-                                    + " on stream " + audioStreamType);
+                                    + " with attributes " + audioAttributes);
                             player.playAsync(soundUri, record.sbn.getUser(), looping,
-                                    audioStreamType);
+                                    audioAttributes);
                             buzzBeepBlinked = true;
                         }
                     } catch (RemoteException e) {