您的位置:首页 > 产品设计 > UI/UE

Android学习 ——SystemUIService之RingtonePlayer分析

2017-11-21 10:40 429 查看
在android API 的media包中有三种方式可供我们选择,它们分别是Ringtone,SoundPool,MediaPlayer。

MediaPlayer 适合比较长且对时间要求不高的情况

Ringtone 铃声,闹钟,提示音等

SoundPool 适合短促且对反应速度比较高的情况(游戏音效或按键声等,音频流组合音)

RingtonePlayer.java 分析

首先看start()函数

@Override
public void start() {
mAsyncPlayer.setUsesWakeLock(mContext);

mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
try {
mAudioService.setRingtonePlayer(mCallback);
} catch (RemoteException e) {
Log.e(TAG, "Problem registering RingtonePlayer: " + e);
}
}

mAsyncPlayer 是NotificationPlayer的实例。调用 setUsesWakeLock()设置休眠状态

public void setUsesWakeLock(Context context) {
if (mWakeLock != null || mThread != null) {
// if either of these has happened, we've already played something.
// and our releases will be out of sync.
throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
+ " mThread=" + mThread);
}
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);//屏幕关,键盘灯关,不休眠
}


mAudioService 音频服务。调用 setRingtonePlayer()设置播放 mCallback

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.");
}

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();
}
};

在mCallback 中主要方法有

play() // 使用Ringtone播放
stop() // 使用Ringtone停止

isPlaying() // 是否正在播放

playAsync() // 使用MediaPlayer播放(NotificationPlayer 类实现)
stopAsync() // 使用MediaPlayer停止(NotificationPlayer 类实现)

当使用RingtonePlayer操作时主要使用到Client 类

private class Client implements IBinder.DeathRecipient {
private final IBinder mToken;
private final Ringtone mRingtone;

public Client(IBinder token, Uri uri, UserHandle user, int streamType) {
mToken = token;

mRingtone = new Ringtone(getContextForUser(user), false);
mRingtone.setStreamType(streamType);
mRingtone.setUri(uri);
}

@Override
public void binderDied() {
if (LOGD) Log.d(TAG, "binderDied() token=" + mToken);
synchronized (mClients) {
mClients.remove(mToken);
}
mRingtone.stop();
}
}


在Client中 new Ringtone() 并设置type 和URI

Client 实现了 DeathRecipient 死亡通知 重写 binderDied() 从 mClients 中移除对应的token 并调用 mRingtone.stop() 停止铃声播放

再看play() 函数中client 的实现

当play()函数调用后根据token从 mClients 这个Map 中获取Client ,如果为空则new Client()  并linkToDeath() 同时添加到mClients 中

最后 client.mRingtone.play(); 执行播放
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: