SystemUI接到通知播声音提示原理

在手机接收到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

你可能感兴趣的:(SystemUI,源码分析)