在手机接收到notification的时候,有静音,震动,声音三种提示方式,特意说明下声音播放的触发流程:
在SystemUI启动的时候,会start()一个媒体播放类:
public class RingtonePlayer extends SystemUI {
private static final String TAG = "RingtonePlayer";
private static final String TAGG = "NotificationPlayer";
private static final boolean LOGD = false | (SystemProperties.getInt("ro.debuggable", 0) == 1);
// TODO: support Uri switching under same IBinder
private IAudioService mAudioService;
private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
private final HashMap mClients = new HashMap();
@Override
public void start() {
mAsyncPlayer.setUsesWakeLock(mContext);
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
try {
//将一个媒体播放回调实例mCallback传递给AudioService.java
mAudioService.setRingtonePlayer(mCallback);
} catch (RemoteException e) {
Log.e(TAG, "Problem registering RingtonePlayer: " + e);
}
}
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
@Override
public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
if (LOGD) {
Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ Binder.getCallingUid() + ")");
}
Client client;
synchronized (mClients) {
client = mClients.get(token);
if (client == null) {
final UserHandle user = Binder.getCallingUserHandle();
client = new Client(token, uri, user, streamType);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
}
client.mRingtone.play();
}
@Override
public void stop(IBinder token) {
if (LOGD) Log.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) Log.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, UserHandle user, boolean looping, int streamType) {
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.");
}
if (user.getIdentifier() == UserHandle.USER_DOPPELGANGER) {
user = UserHandle.OWNER;
}
mAsyncPlayer.play(getContextForUser(user), uri, looping, streamType);
}
@Override
public void stopAsync() {
if (LOGD) Log.d(TAG, "stopAsync()");
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
mAsyncPlayer.stop();
}
};
在start()中将媒体播放回调接口传递给
.frameworks/base/services/core/java/com/android/server/audio/AudioService.java”
@Override
public void setRingtonePlayer(IRingtonePlayer player) {
mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
mRingtonePlayer = player;
}
@Override
public IRingtonePlayer getRingtonePlayer() {
return mRingtonePlayer;
}
接到通知后
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java:
void buzzBeepBlinkLocked(NotificationRecord record) {
....
if (hasValidSound) {
mSoundNotificationKey = key;
beep = playSound(record, soundUri);
}
....
}
private boolean playSound(final NotificationRecord record, Uri soundUri) {
boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
// do not play notifications if there is a user of exclusive audio focus
// or the device is in vibrate mode
boolean muted = Settings.System.getInt(getContext().getContentResolver(),
SettingsSmt.System.VOLUME_PANEL_MUTE_ENABLE, 0) == 1 ? true : false;
int audioStreamType = AudioAttributes.toLegacyStreamType(record.getAudioAttributes());
if (DBG) Log.v(TAG, "system muted: " + muted+" audioStreamType:"+audioStreamType);
if ((((!muted || audioStreamType == AudioManager.STREAM_ALARM)
&& (mAudioManager.getStreamVolume(audioStreamType) != 0))
|| audioStreamType == AudioManager.STREAM_VOICE_CALL)
&& !mAudioManager.isAudioFocusExclusive()
&& mAudioManager.getRingerModeInternal() != AudioManager.RINGER_MODE_VIBRATE) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ " with attributes " + record.getAudioAttributes());
player.playAsync(soundUri, record.sbn.getUser(), looping,
record.getAudioAttributes());
return true;
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
return false;
}
然后通过回调接口player回调到systemUI播放声音:
@Override
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.");
}
if (UserHandle.ALL.equals(user)) {
user = UserHandle.OWNER;
} else if (user.getIdentifier() == UserHandle.USER_DOPPELGANGER) {
user = UserHandle.OWNER;
}
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
}
好了,如果对接到通知后systemui的处理流程不熟悉的话,
请参照这个大牛的杰作:https://blog.csdn.net/hy_cold/article/details/72824707