Android学习 ——SystemUIService之RingtonePlayer分析

来源:互联网 发布:矩阵奖金制度 编辑:程序博客网 时间:2024/06/03 07:05

在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(); 执行播放

阅读全文
0 0
原创粉丝点击