diff options
author | Jeff Sharkey <jsharkey@android.com> | 2012-04-26 17:30:34 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2012-04-27 14:15:05 -0700 |
commit | 098d580cc2bb6c0891c756a4e5230c6c6b0d2376 (patch) | |
tree | bd5ae0f9e87a5516e8c481cebc54321272152491 | |
parent | f5d70fd2add31cdb2e4ca1e931b47db95fa4b3e0 (diff) | |
download | frameworks_base-098d580cc2bb6c0891c756a4e5230c6c6b0d2376.zip frameworks_base-098d580cc2bb6c0891c756a4e5230c6c6b0d2376.tar.gz frameworks_base-098d580cc2bb6c0891c756a4e5230c6c6b0d2376.tar.bz2 |
Migrate ringtone playback to SystemUI.
Introduce IRingtonePlayer, which handles playback for both Ringtone
objects and Notifications. SystemUI now hosts this player, which it
registers with AudioService. It also keeps MediaPlayer instances
warm, and cleans them up after stop() or Binder death.
Move both Ringtone and NotificationManagerService to play back audio
through this new interface.
Bug: 6376128, 6350773
Change-Id: I1dcb86d16ee3c4f07cdb2248d33dcff4ead3609a
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | core/java/android/app/Notification.java | 3 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 5 | ||||
-rw-r--r-- | media/java/android/media/AudioManager.java | 8 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 17 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 5 | ||||
-rw-r--r-- | media/java/android/media/IRingtonePlayer.aidl | 33 | ||||
-rw-r--r-- | media/java/android/media/Ringtone.java | 177 | ||||
-rw-r--r-- | media/java/android/media/RingtoneManager.java | 7 | ||||
-rw-r--r-- | packages/SystemUI/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/SystemUIService.java | 1 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java (renamed from services/java/com/android/server/NotificationPlayer.java) | 5 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java | 164 | ||||
-rwxr-xr-x | services/java/com/android/server/NotificationManagerService.java | 90 |
14 files changed, 390 insertions, 128 deletions
@@ -198,6 +198,7 @@ LOCAL_SRC_FILES += \ media/java/android/media/IMediaScannerService.aidl \ media/java/android/media/IRemoteControlClient.aidl \ media/java/android/media/IRemoteControlDisplay.aidl \ + media/java/android/media/IRingtonePlayer.aidl \ telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \ telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \ telephony/java/com/android/internal/telephony/ITelephony.aidl \ diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0a996df..69689c9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -21,6 +21,7 @@ import com.android.internal.R; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -213,7 +214,7 @@ public class Notification implements Parcelable /** * Use this constant as the value for audioStreamType to request that * the default stream type for notifications be used. Currently the - * default stream type is STREAM_RING. + * default stream type is {@link AudioManager#STREAM_NOTIFICATION}. */ public static final int STREAM_DEFAULT = -1; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3ae2b4e..471a496 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -628,6 +628,11 @@ android:permissionGroup="android.permission-group.SYSTEM_TOOLS" android:protectionLevel="signature" /> + <!-- Allows registration for remote audio playback. @hide --> + <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="signature" /> + <!-- =========================================== --> <!-- Permissions associated with telephony state --> <!-- =========================================== --> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2a006c6..f603525 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2306,4 +2306,12 @@ public class AudioManager { } } + /** {@hide} */ + public IRingtonePlayer getRingtonePlayer() { + try { + return getService().getRingtonePlayer(); + } catch (RemoteException e) { + return null; + } + } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 3e958dc..dc9496f 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -16,6 +16,7 @@ package android.media; +import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK; import static android.media.AudioManager.RINGER_MODE_NORMAL; import static android.media.AudioManager.RINGER_MODE_SILENT; import static android.media.AudioManager.RINGER_MODE_VIBRATE; @@ -360,7 +361,6 @@ public class AudioService extends IAudioService.Stub { private int mPrevVolDirection = AudioManager.ADJUST_SAME; // Keyguard manager proxy private KeyguardManager mKeyguardManager; - // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume // is controlled by Vol keys. private int mVolumeControlStream = -1; @@ -369,6 +369,8 @@ public class AudioService extends IAudioService.Stub { // server process so in theory it is not necessary to monitor the client death. // However it is good to be ready for future evolutions. private ForceControlStreamClient mForceControlStreamClient = null; + // Used to play ringtones outside system_server + private volatile IRingtonePlayer mRingtonePlayer; /////////////////////////////////////////////////////////////////////////// // Construction @@ -4231,6 +4233,17 @@ public class AudioService extends IAudioService.Stub { } @Override + public void setRingtonePlayer(IRingtonePlayer player) { + mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); + mRingtonePlayer = player; + } + + @Override + public IRingtonePlayer getRingtonePlayer() { + return mRingtonePlayer; + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); @@ -4238,6 +4251,4 @@ public class AudioService extends IAudioService.Stub { dumpFocusStack(pw); dumpRCStack(pw); } - - } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index df21040..1a2714e 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -21,6 +21,8 @@ import android.content.ComponentName; import android.media.IAudioFocusDispatcher; import android.media.IRemoteControlClient; import android.media.IRemoteControlDisplay; +import android.media.IRingtonePlayer; +import android.net.Uri; /** * {@hide} @@ -113,10 +115,11 @@ interface IAudioService { oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h); void startBluetoothSco(IBinder cb); - void stopBluetoothSco(IBinder cb); void forceVolumeControlStream(int streamType, IBinder cb); + void setRingtonePlayer(IRingtonePlayer player); + IRingtonePlayer getRingtonePlayer(); int getMasterStreamType(); } diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl new file mode 100644 index 0000000..44a0333 --- /dev/null +++ b/media/java/android/media/IRingtonePlayer.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.net.Uri; + +/** + * @hide + */ +interface IRingtonePlayer { + /** Used for Ringtone.java playback */ + void play(IBinder token, in Uri uri, int streamType); + void stop(IBinder token); + boolean isPlaying(IBinder token); + + /** Used for Notification sound playback. */ + void playAsync(in Uri uri, boolean looping, int streamType); + void stopAsync(); +} diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index f16ba36..57139d2 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -18,17 +18,15 @@ package android.media; import android.content.ContentResolver; import android.content.Context; -import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.media.AudioManager; -import android.media.MediaPlayer; import android.net.Uri; +import android.os.Binder; +import android.os.RemoteException; import android.provider.DrmStore; import android.provider.MediaStore; import android.provider.Settings; import android.util.Log; -import java.io.FileDescriptor; import java.io.IOException; /** @@ -41,7 +39,8 @@ import java.io.IOException; * @see RingtoneManager */ public class Ringtone { - private static String TAG = "Ringtone"; + private static final String TAG = "Ringtone"; + private static final boolean LOGD = true; private static final String[] MEDIA_COLUMNS = new String[] { MediaStore.Audio.Media._ID, @@ -55,21 +54,26 @@ public class Ringtone { DrmStore.Audio.TITLE }; - private MediaPlayer mAudio; + private final Context mContext; + private final AudioManager mAudioManager; + private final boolean mAllowRemote; + private final IRingtonePlayer mRemotePlayer; + private final Binder mRemoteToken; + + private MediaPlayer mLocalPlayer; private Uri mUri; private String mTitle; - private FileDescriptor mFileDescriptor; - private AssetFileDescriptor mAssetFileDescriptor; private int mStreamType = AudioManager.STREAM_RING; - private AudioManager mAudioManager; - - private Context mContext; - Ringtone(Context context) { + /** {@hide} */ + public Ringtone(Context context, boolean allowRemote) { mContext = context; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mAllowRemote = allowRemote; + mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null; + mRemoteToken = allowRemote ? new Binder() : null; } /** @@ -79,18 +83,10 @@ public class Ringtone { */ public void setStreamType(int streamType) { mStreamType = streamType; - - if (mAudio != null) { - /* - * The stream type has to be set before the media player is - * prepared. Re-initialize it. - */ - try { - openMediaPlayer(); - } catch (IOException e) { - Log.w(TAG, "Couldn't set the stream type", e); - } - } + + // The stream type has to be set before the media player is prepared. + // Re-initialize it. + setUri(mUri); } /** @@ -164,67 +160,75 @@ public class Ringtone { return title; } - - private void openMediaPlayer() throws IOException { - if (mAudio != null) { - mAudio.release(); + + /** + * Set {@link Uri} to be used for ringtone playback. Attempts to open + * locally, otherwise will delegate playback to remote + * {@link IRingtonePlayer}. + * + * @hide + */ + public void setUri(Uri uri) { + destroyLocalPlayer(); + + mUri = uri; + if (mUri == null) { + return; } - mAudio = new MediaPlayer(); - if (mUri != null) { - mAudio.setDataSource(mContext, mUri); - } else if (mFileDescriptor != null) { - mAudio.setDataSource(mFileDescriptor); - } else if (mAssetFileDescriptor != null) { - // Note: using getDeclaredLength so that our behavior is the same - // as previous versions when the content provider is returning - // a full file. - if (mAssetFileDescriptor.getDeclaredLength() < 0) { - mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor()); - } else { - mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(), - mAssetFileDescriptor.getStartOffset(), - mAssetFileDescriptor.getDeclaredLength()); + + // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing + + // try opening uri locally before delegating to remote player + mLocalPlayer = new MediaPlayer(); + try { + mLocalPlayer.setDataSource(mContext, mUri); + mLocalPlayer.setAudioStreamType(mStreamType); + mLocalPlayer.prepare(); + + } catch (SecurityException e) { + destroyLocalPlayer(); + if (!mAllowRemote) { + throw new IllegalStateException("Remote playback not allowed", e); + } + } catch (IOException e) { + destroyLocalPlayer(); + if (!mAllowRemote) { + throw new IllegalStateException("Remote playback not allowed", e); } - } else { - throw new IOException("No data source set."); } - mAudio.setAudioStreamType(mStreamType); - mAudio.prepare(); - } - - void open(FileDescriptor fd) throws IOException { - mFileDescriptor = fd; - openMediaPlayer(); - } - void open(AssetFileDescriptor fd) throws IOException { - mAssetFileDescriptor = fd; - openMediaPlayer(); + if (LOGD) { + if (mLocalPlayer != null) { + Log.d(TAG, "Successfully created local player"); + } else { + Log.d(TAG, "Problem opening; delegating to remote player"); + } + } } - void open(Uri uri) throws IOException { - mUri = uri; - openMediaPlayer(); + /** {@hide} */ + public Uri getUri() { + return mUri; } /** * Plays the ringtone. */ public void play() { - if (mAudio == null) { - try { - openMediaPlayer(); - } catch (Exception ex) { - Log.e(TAG, "play() caught ", ex); - mAudio = null; - } - } - if (mAudio != null) { - // do not ringtones if stream volume is 0 + if (mLocalPlayer != null) { + // do not play ringtones if stream volume is 0 // (typically because ringer mode is silent). if (mAudioManager.getStreamVolume(mStreamType) != 0) { - mAudio.start(); + mLocalPlayer.start(); + } + } else if (mAllowRemote) { + try { + mRemotePlayer.play(mRemoteToken, mUri, mStreamType); + } catch (RemoteException e) { + Log.w(TAG, "Problem playing ringtone: " + e); } + } else { + throw new IllegalStateException("Neither local nor remote playback available"); } } @@ -232,10 +236,22 @@ public class Ringtone { * Stops a playing ringtone. */ public void stop() { - if (mAudio != null) { - mAudio.reset(); - mAudio.release(); - mAudio = null; + if (mLocalPlayer != null) { + destroyLocalPlayer(); + } else if (mAllowRemote) { + try { + mRemotePlayer.stop(mRemoteToken); + } catch (RemoteException e) { + Log.w(TAG, "Problem stopping ringtone: " + e); + } + } + } + + private void destroyLocalPlayer() { + if (mLocalPlayer != null) { + mLocalPlayer.reset(); + mLocalPlayer.release(); + mLocalPlayer = null; } } @@ -245,7 +261,18 @@ public class Ringtone { * @return True if playing, false otherwise. */ public boolean isPlaying() { - return mAudio != null && mAudio.isPlaying(); + if (mLocalPlayer != null) { + return mLocalPlayer.isPlaying(); + } else if (mAllowRemote) { + try { + return mRemotePlayer.isPlaying(mRemoteToken); + } catch (RemoteException e) { + Log.w(TAG, "Problem checking ringtone: " + e); + return false; + } + } else { + throw new IllegalStateException("Neither local nor remote playback available"); + } } void setTitle(String title) { diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index a5b1f45..5e18bfa 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -606,16 +606,15 @@ public class RingtoneManager { * @see #getRingtone(Context, Uri) */ private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) { - try { - Ringtone r = new Ringtone(context); + final Ringtone r = new Ringtone(context, true); if (streamType >= 0) { r.setStreamType(streamType); } - r.open(ringtoneUri); + r.setUri(ringtoneUri); return r; } catch (Exception ex) { - Log.e(TAG, "Failed to open ringtone " + ringtoneUri); + Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex); } return null; diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index a31c264..cef21b0 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -5,6 +5,7 @@ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.INJECT_EVENTS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> @@ -12,6 +13,7 @@ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <uses-permission android:name="android.permission.STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> + <uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" /> <!-- Networking and telephony --> <uses-permission android:name="android.permission.BLUETOOTH" /> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java index ae568f8..0a57499 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java @@ -41,6 +41,7 @@ public class SystemUIService extends Service { final Object[] SERVICES = new Object[] { 0, // system bar or status bar, filled in below. com.android.systemui.power.PowerUI.class, + com.android.systemui.media.RingtonePlayer.class, }; /** diff --git a/services/java/com/android/server/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java index 52d2381..6a12eb1 100644 --- a/services/java/com/android/server/NotificationPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.systemui.media; import android.content.Context; import android.media.AudioManager; @@ -36,7 +36,7 @@ import java.util.LinkedList; /** * @hide * This class is provides the same interface and functionality as android.media.AsyncPlayer - * with the following differences: + * with the following differences: * - whenever audio is played, audio focus is requested, * - whenever audio playback is stopped or the playback completed, audio focus is abandoned. */ @@ -338,4 +338,3 @@ public class NotificationPlayer implements OnCompletionListener { } } } - diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java new file mode 100644 index 0000000..9e273d4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media; + +import android.content.Context; +import android.media.IAudioService; +import android.media.IRingtonePlayer; +import android.media.Ringtone; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; + +import com.android.systemui.SystemUI; +import com.google.android.collect.Maps; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; + +/** + * Service that offers to play ringtones by {@link Uri}, since our process has + * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}. + */ +public class RingtonePlayer extends SystemUI { + private static final String TAG = "RingtonePlayer"; + private static final boolean LOGD = true; + + // TODO: support Uri switching under same IBinder + + private IAudioService mAudioService; + + private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG); + private final HashMap<IBinder, Client> mClients = Maps.newHashMap(); + + @Override + public void start() { + mAsyncPlayer.setUsesWakeLock(mContext); + + mAudioService = IAudioService.Stub.asInterface( + ServiceManager.getService(Context.AUDIO_SERVICE)); + try { + mAudioService.setRingtonePlayer(mCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Problem registering RingtonePlayer: " + e); + } + } + + /** + * Represents an active remote {@link Ringtone} client. + */ + private class Client implements IBinder.DeathRecipient { + private final IBinder mToken; + private final Ringtone mRingtone; + + public Client(IBinder token, Uri uri, int streamType) { + mToken = token; + mRingtone = new Ringtone(mContext, false); + mRingtone.setStreamType(streamType); + mRingtone.setUri(uri); + } + + @Override + public void binderDied() { + if (LOGD) Slog.d(TAG, "binderDied() token=" + mToken); + synchronized (mClients) { + mClients.remove(mToken); + } + mRingtone.stop(); + } + } + + private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() { + @Override + public void play(IBinder token, Uri uri, int streamType) throws RemoteException { + if (LOGD) Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ")"); + Client client; + synchronized (mClients) { + client = mClients.get(token); + if (client == null) { + client = new Client(token, uri, streamType); + token.linkToDeath(client, 0); + mClients.put(token, client); + } + } + client.mRingtone.play(); + } + + @Override + public void stop(IBinder token) { + if (LOGD) Slog.d(TAG, "stop(token=" + token + ")"); + Client client; + synchronized (mClients) { + client = mClients.remove(token); + } + if (client != null) { + client.mToken.unlinkToDeath(client, 0); + client.mRingtone.stop(); + } + } + + @Override + public boolean isPlaying(IBinder token) { + if (LOGD) Slog.d(TAG, "isPlaying(token=" + token + ")"); + Client client; + synchronized (mClients) { + client = mClients.get(token); + } + if (client != null) { + return client.mRingtone.isPlaying(); + } else { + return false; + } + } + + @Override + public void playAsync(Uri uri, boolean looping, int streamType) { + if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ")"); + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Async playback only available from system UID."); + } + mAsyncPlayer.play(mContext, uri, looping, streamType); + } + + @Override + public void stopAsync() { + if (LOGD) Slog.d(TAG, "stopAsync()"); + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Async playback only available from system UID."); + } + mAsyncPlayer.stop(); + } + }; + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Clients:"); + synchronized (mClients) { + for (Client client : mClients.values()) { + pw.print(" mToken="); + pw.print(client.mToken); + pw.print(" mUri="); + pw.println(client.mRingtone.getUri()); + } + } + } +} diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 1ba7e79..663a031 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -16,16 +16,15 @@ package com.android.server; -import com.android.internal.os.AtomicFile; -import com.android.internal.statusbar.StatusBarNotification; -import com.android.internal.util.FastXmlSerializer; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; import android.app.Notification; -import android.app.NotificationManager; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; @@ -39,8 +38,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.database.ContentObserver; import android.media.AudioManager; -import android.net.NetworkPolicy; -import android.net.NetworkTemplate; +import android.media.IAudioService; +import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; import android.os.Handler; @@ -48,6 +47,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserId; import android.os.Vibrator; import android.provider.Settings; @@ -61,6 +61,14 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.Toast; +import com.android.internal.os.AtomicFile; +import com.android.internal.statusbar.StatusBarNotification; +import com.android.internal.util.FastXmlSerializer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -74,18 +82,6 @@ import java.util.HashSet; import libcore.io.IoUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import static android.net.NetworkPolicyManager.POLICY_NONE; -import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute; -import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute; -import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.START_TAG; - /** {@hide} */ public class NotificationManagerService extends INotificationManager.Stub @@ -126,12 +122,13 @@ public class NotificationManagerService extends INotificationManager.Stub private int mDefaultNotificationLedOn; private int mDefaultNotificationLedOff; - private NotificationRecord mSoundNotification; - private NotificationPlayer mSound; private boolean mSystemReady; private int mDisabledNotifications; + private NotificationRecord mSoundNotification; private NotificationRecord mVibrateNotification; + + private IAudioService mAudioService; private Vibrator mVibrator; // for enabling and disabling notification pulse behavior @@ -409,17 +406,19 @@ public class NotificationManagerService extends INotificationManager.Stub // cancel whatever's going on long identity = Binder.clearCallingIdentity(); try { - mSound.stop(); - } - finally { + final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + if (player != null) { + player.stopAsync(); + } + } catch (RemoteException e) { + } finally { Binder.restoreCallingIdentity(identity); } identity = Binder.clearCallingIdentity(); try { mVibrator.cancel(); - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } } @@ -445,11 +444,15 @@ public class NotificationManagerService extends INotificationManager.Stub synchronized (mNotificationList) { // sound mSoundNotification = null; + long identity = Binder.clearCallingIdentity(); try { - mSound.stop(); - } - finally { + final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + if (player != null) { + player.stopAsync(); + } + } catch (RemoteException e) { + } finally { Binder.restoreCallingIdentity(identity); } @@ -458,8 +461,7 @@ public class NotificationManagerService extends INotificationManager.Stub identity = Binder.clearCallingIdentity(); try { mVibrator.cancel(); - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } @@ -570,8 +572,6 @@ public class NotificationManagerService extends INotificationManager.Stub mContext = context; mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); mAm = ActivityManagerNative.getDefault(); - mSound = new NotificationPlayer(TAG); - mSound.setUsesWakeLock(context); mToastQueue = new ArrayList<ToastRecord>(); mHandler = new WorkerHandler(); @@ -622,6 +622,9 @@ public class NotificationManagerService extends INotificationManager.Stub } void systemReady() { + mAudioService = IAudioService.Stub.asInterface( + ServiceManager.getService(Context.AUDIO_SERVICE)); + // no beeping until we're basically done booting mSystemReady = true; } @@ -1026,11 +1029,14 @@ public class NotificationManagerService extends INotificationManager.Stub // do not play notifications if stream volume is 0 // (typically because ringer mode is silent). if (audioManager.getStreamVolume(audioStreamType) != 0) { - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { - mSound.play(mContext, uri, looping, audioStreamType); - } - finally { + final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + if (player != null) { + player.playAsync(uri, looping, audioStreamType); + } + } catch (RemoteException e) { + } finally { Binder.restoreCallingIdentity(identity); } } @@ -1121,11 +1127,14 @@ public class NotificationManagerService extends INotificationManager.Stub // sound if (mSoundNotification == r) { mSoundNotification = null; - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { - mSound.stop(); - } - finally { + final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + if (player != null) { + player.stopAsync(); + } + } catch (RemoteException e) { + } finally { Binder.restoreCallingIdentity(identity); } } @@ -1386,7 +1395,6 @@ public class NotificationManagerService extends INotificationManager.Stub } pw.println(" mSoundNotification=" + mSoundNotification); - pw.println(" mSound=" + mSound); pw.println(" mVibrateNotification=" + mVibrateNotification); pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications)); pw.println(" mSystemReady=" + mSystemReady); |