From 81f871e2b96125d57b76c07169e868e516443794 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 6 Aug 2014 16:32:38 -0700 Subject: Add support for AudioAttributes in android.media.Ringtone Deprecate use of stream types. Map deprecated API to AudioAttributes. Add new methods to specify AudioAttributes on a Ringtone instance. Bug 16790748 Change-Id: Ifb3c2e838e1f119614459ad7d71d83a4d7c9ffdb --- api/current.txt | 5 ++- core/java/android/app/Notification.java | 3 ++ media/java/android/media/IRingtonePlayer.aidl | 5 ++- media/java/android/media/Ringtone.java | 47 ++++++++++++++++------ .../android/systemui/media/NotificationPlayer.java | 44 +++++++++++++++++--- .../com/android/systemui/media/RingtonePlayer.java | 13 +++--- .../notification/NotificationManagerService.java | 17 ++++---- 7 files changed, 98 insertions(+), 36 deletions(-) diff --git a/api/current.txt b/api/current.txt index e8d1369..8b2f69a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15762,11 +15762,12 @@ package android.media { } 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 90b8b86..c3619eb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -279,6 +279,7 @@ public class Notification implements Parcelable * * @deprecated Use {@link #audioAttributes} instead. */ + @Deprecated public static final int STREAM_DEFAULT = -1; /** @@ -288,6 +289,7 @@ public class Notification implements Parcelable * * @deprecated Use {@link #audioAttributes} instead. */ + @Deprecated public int audioStreamType = STREAM_DEFAULT; /** @@ -2193,6 +2195,7 @@ public class Notification implements Parcelable * @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 @@ import android.os.UserHandle; */ 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 @@ public class Ringtone { 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 @@ public class Ringtone { * 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 @@ public class Ringtone { mLocalPlayer = new MediaPlayer(); try { mLocalPlayer.setDataSource(mContext, mUri); - mLocalPlayer.setAudioStreamType(mStreamType); + mLocalPlayer.setAudioAttributes(mAudioAttributes); mLocalPlayer.prepare(); } catch (SecurityException e) { @@ -214,13 +235,14 @@ public class Ringtone { 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 @@ public class Ringtone { } 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 @@ public class Ringtone { 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 @@ public class NotificationPlayer implements OnCompletionListener { 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 @@ public class NotificationPlayer implements OnCompletionListener { (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 @@ public class NotificationPlayer implements OnCompletionListener { 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 @@ public class NotificationPlayer implements OnCompletionListener { * (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 @@ public class NotificationPlayer implements OnCompletionListener { 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 @@ package com.android.systemui.media; 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 @@ public class RingtonePlayer extends SystemUI { 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 @@ public class RingtonePlayer extends SystemUI { 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 @@ public class RingtonePlayer extends SystemUI { 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 @@ public class RingtonePlayer extends SystemUI { } @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 3eb2b7e..87468d2 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 @@ public class NotificationManagerService extends SystemService { 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) { -- cgit v1.1