Commit 098d580c authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

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
parent f5d70fd2
......@@ -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 \
......
......@@ -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;
......
......@@ -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 -->
<!-- =========================================== -->
......
......@@ -2306,4 +2306,12 @@ public class AudioManager {
}
}
/** {@hide} */
public IRingtonePlayer getRingtonePlayer() {
try {
return getService().getRingtonePlayer();
} catch (RemoteException e) {
return null;
}
}
}
......@@ -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
......@@ -4230,6 +4232,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);
}
}
......@@ -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();
}
/*
* 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();
}
......@@ -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) {
......
......@@ -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;
......
......@@ -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" />
......
......@@ -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,
};
/**
......
......@@ -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 {
}
}
}
/*
* 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());
}
}
}
}
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment