InCallTonePlayer
packages/services/Telecomm/src/com/Android/server/telecom/InCallTonePlayer.Java,该类用于通话中提示音的播放。
- public static class Factory {
- private final CallAudioManager mCallAudioManager;
- private final TelecomSystem.SyncRoot mLock;
- Factory(CallAudioManager callAudioManager, TelecomSystem.SyncRoot lock) {
- mCallAudioManager = callAudioManager;
- mLock = lock;
- }
- InCallTonePlayer createPlayer(int tone) {
- return new InCallTonePlayer(tone, mCallAudioManager, mLock);
- }
- }
- /** The ID of the tone to play. */
- private final int mToneId;
- public static final int TONE_INVALID = 0;
- public static final int TONE_BUSY = 1;
- public static final int TONE_CALL_ENDED = 2;
- ...
- public static final int TONE_VOICE_PRIVACY = 13;
- public static final int TONE_VIDEO_UPGRADE = 14;
- public final class InCallTonePlayer extends Thread
- @Override
- public void run() {
- ToneGenerator toneGenerator = null;
- try {
- Log.d(this, "run(toneId = %s)", mToneId);
- final int toneType; // Passed to ToneGenerator.startTone.
- final int toneVolume; // Passed to the ToneGenerator constructor.
- final int toneLengthMillis;
- switch (mToneId) {
- case TONE_BUSY:
- // TODO: CDMA-specific tones
- toneType = ToneGenerator.TONE_SUP_BUSY; //依据id获取tone的类型、音量和时长,可见tone类型是在framework中定义的
- toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMillis = 4000;
- break;
- ...
- default:
- throw new IllegalStateException("Bad toneId: " + mToneId);
- }
- int stream = AudioManager.STREAM_VOICE_CALL;
- if (mCallAudioManager.isBluetoothAudioOn()) {
- stream = AudioManager.STREAM_BLUETOOTH_SCO; //设置音频stream,有蓝牙连接就切换到蓝牙设备播放
- ...
- toneGenerator = new ToneGenerator(stream, toneVolume); //初始化ToneGenerator
- ...
- synchronized (this) {
- if (mState != STATE_STOPPED) {
- mState = STATE_ON;
- toneGenerator.startTone(toneType); //播放
- try {
- Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
- toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
- wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS); //阻塞直到停止播放
- } catch (InterruptedException e) {
- Log.w(this, "wait interrupted", e);
- }
- }
- }
- mState = STATE_OFF;
- } finally {
- if (toneGenerator != null) { //资源释放
- toneGenerator.release();
- }
- cleanUpTonePlayer();
- }
- }
- void stopTone() { //停止tone播放
- synchronized (this) {
- if (mState == STATE_ON) {
- Log.d(this, "Stopping the tone %d.", mToneId);
- notify(); //由于run中最后是调用wait阻塞,所以这里notify就是通知线程可以结束运行了。
- }
- mState = STATE_STOPPED;
- }
- }
- /**
- * Proprietary tone, prompt tone: 400Hz+1200Hz, 200ms ON
- *
- * @see #ToneGenerator(int, int)
- */
- public static final int TONE_PROP_PROMPT = 27;
AsyncRingtonePlayer
packages/services/Telecomm/src/com/android/server/telecom/AsyncRingtonePlayer.java
- private static final int EVENT_PLAY = 1;
- private static final int EVENT_STOP = 2;
- private static final int EVENT_REPEAT = 3;
- private Handler getNewHandler() {
- Preconditions.checkState(mHandler == null);
- HandlerThread thread = new HandlerThread("ringtone-player");
- thread.start();
- return new Handler(thread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case EVENT_PLAY:
- handlePlay((Uri) msg.obj);
- break;
- case EVENT_REPEAT:
- handleRepeat();
- break;
- case EVENT_STOP:
- handleStop();
- break;
- }
- }
- };
- }
Ringer
packages/services/Telecomm/src/com/android/server/telecom/Ringer.java,负责来电时候铃声和振动处理
- private void startRingingOrCallWaiting(Call call) { //响铃的入口
- Call foregroundCall = mCallsManager.getForegroundCall();
- Log.v(this, "startRingingOrCallWaiting, foregroundCall: %s.", foregroundCall);
- if (mRingingCalls.contains(foregroundCall)
- && !mCallsManager.hasActiveOrHoldingCall()) { //普通来电状态
- ...
- AudioManager audioManager =
- (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
- if (mState != STATE_RINGING) {
- Log.event(call, Log.Events.START_RINGER);
- mState = STATE_RINGING;
- }
- mCallAudioManager.setIsRinging(call, true);
- ...
- mRingtonePlayer.play(foregroundCall.getRingtone()); //使用AsyncRingtonePlayer响铃
- ...
- } else {
- Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0");
- }
- if (shouldVibrate(mContext) && !mIsVibrating) { //振动
- mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT,
- VIBRATION_ATTRIBUTES);
- mIsVibrating = true;
- }
- } else if (foregroundCall != null) { //通话中来电
- ...
- // All incoming calls are in background so play call waiting.
- stopRinging(call, "Stop for call-waiting");
- if (mState != STATE_CALL_WAITING) {
- Log.event(call, Log.Events.START_CALL_WAITING_TONE);
- mState = STATE_CALL_WAITING;
- }
- if (mCallWaitingPlayer == null) {
- mCallWaitingPlayer =
- mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
- mCallWaitingPlayer.startTone(); //使用InCallTonePlayer响起提示音
- }
- }
- }
音量键和电源键停止响铃
系统按键会先在PhoneWindowManager中处理然后再发送到app窗口去处理,关于铃声的PhoneWindowManager会处理,所以不会发送到app再去处理,这个对要修改这个逻辑的同学来说不大友好,不过一般厂商也不改这些默认动作。
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
- ...
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_MUTE: {
- ...
- TelecomManager telecomManager = getTelecommService();
- if (telecomManager != null) {
- if (telecomManager.isRinging()) {
- telecomManager.silenceRinger();
- ...
- }
- private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
- ...
- if (telecomManager != null) {
- if (telecomManager.isRinging()) {
- // Pressing Power while there's a ringing incoming
- // call should silence the ringer.
- telecomManager.silenceRinger();
- } else if ((mIncallPowerBehavior
- & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
- && telecomManager.isInCall() && interactive) {
- // Otherwise, if "Power button ends call" is enabled,
- // the Power button will hang up any current active call.
- hungUp = telecomManager.endCall();
- }
- }
- ...
- }