1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.telecom; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.content.Context; 22 import android.media.AudioAttributes; 23 import android.media.AudioManager; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.os.Vibrator; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 30 /** 31 * Controls the ringtone player. 32 */ 33 @VisibleForTesting 34 public class Ringer { 35 private static final long[] VIBRATION_PATTERN = new long[] { 36 0, // No delay before starting 37 1000, // How long to vibrate 38 1000, // How long to wait before vibrating again 39 }; 40 41 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 42 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 43 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 44 .build(); 45 46 /** Indicate that we want the pattern to repeat at the step which turns on vibration. */ 47 private static final int VIBRATION_PATTERN_REPEAT = 1; 48 49 /** 50 * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming 51 * calls and explicit ordering is useful for maintaining the proper state of the ringer. 52 */ 53 54 private final SystemSettingsUtil mSystemSettingsUtil; 55 private final InCallTonePlayer.Factory mPlayerFactory; 56 private final AsyncRingtonePlayer mRingtonePlayer; 57 private final Context mContext; 58 private final Vibrator mVibrator; 59 private final InCallController mInCallController; 60 61 private InCallTonePlayer mCallWaitingPlayer; 62 private RingtoneFactory mRingtoneFactory; 63 64 /** 65 * Call objects that are ringing or call-waiting. These are used only for logging purposes. 66 */ 67 private Call mRingingCall; 68 private Call mCallWaitingCall; 69 70 /** 71 * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls. 72 */ 73 private boolean mIsVibrating = false; 74 75 /** Initializes the Ringer. */ 76 @VisibleForTesting Ringer( InCallTonePlayer.Factory playerFactory, Context context, SystemSettingsUtil systemSettingsUtil, AsyncRingtonePlayer asyncRingtonePlayer, RingtoneFactory ringtoneFactory, Vibrator vibrator, InCallController inCallController)77 public Ringer( 78 InCallTonePlayer.Factory playerFactory, 79 Context context, 80 SystemSettingsUtil systemSettingsUtil, 81 AsyncRingtonePlayer asyncRingtonePlayer, 82 RingtoneFactory ringtoneFactory, 83 Vibrator vibrator, 84 InCallController inCallController) { 85 86 mSystemSettingsUtil = systemSettingsUtil; 87 mPlayerFactory = playerFactory; 88 mContext = context; 89 // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this 90 // vibrator object will be isolated from others. 91 mVibrator = vibrator; 92 mRingtonePlayer = asyncRingtonePlayer; 93 mRingtoneFactory = ringtoneFactory; 94 mInCallController = inCallController; 95 } 96 startRinging(Call foregroundCall)97 public void startRinging(Call foregroundCall) { 98 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 99 return; 100 } 101 102 if (foregroundCall == null) { 103 Log.wtf(this, "startRinging called with null foreground call."); 104 return; 105 } 106 107 if (mInCallController.doesConnectedDialerSupportRinging()) { 108 Log.event(foregroundCall, Log.Events.SKIP_RINGING); 109 return; 110 } 111 112 stopCallWaiting(); 113 114 if (!shouldRingForContact(foregroundCall.getContactUri())) { 115 return; 116 } 117 118 AudioManager audioManager = 119 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 120 if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) { 121 mRingingCall = foregroundCall; 122 Log.event(foregroundCall, Log.Events.START_RINGER); 123 // Because we wait until a contact info query to complete before processing a 124 // call (for the purposes of direct-to-voicemail), the information about custom 125 // ringtones should be available by the time this code executes. We can safely 126 // request the custom ringtone from the call and expect it to be current. 127 mRingtonePlayer.play(mRingtoneFactory, foregroundCall); 128 } else { 129 Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0"); 130 } 131 132 if (shouldVibrate(mContext) && !mIsVibrating) { 133 mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT, 134 VIBRATION_ATTRIBUTES); 135 mIsVibrating = true; 136 } 137 } 138 startCallWaiting(Call call)139 public void startCallWaiting(Call call) { 140 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 141 return; 142 } 143 144 if (mInCallController.doesConnectedDialerSupportRinging()) { 145 Log.event(call, Log.Events.SKIP_RINGING); 146 return; 147 } 148 149 Log.v(this, "Playing call-waiting tone."); 150 151 stopRinging(); 152 153 if (mCallWaitingPlayer == null) { 154 Log.event(call, Log.Events.START_CALL_WAITING_TONE); 155 mCallWaitingCall = call; 156 mCallWaitingPlayer = 157 mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING); 158 mCallWaitingPlayer.startTone(); 159 } 160 } 161 stopRinging()162 public void stopRinging() { 163 if (mRingingCall != null) { 164 Log.event(mRingingCall, Log.Events.STOP_RINGER); 165 mRingingCall = null; 166 } 167 168 mRingtonePlayer.stop(); 169 170 if (mIsVibrating) { 171 mVibrator.cancel(); 172 mIsVibrating = false; 173 } 174 } 175 stopCallWaiting()176 public void stopCallWaiting() { 177 Log.v(this, "stop call waiting."); 178 if (mCallWaitingPlayer != null) { 179 if (mCallWaitingCall != null) { 180 Log.event(mCallWaitingCall, Log.Events.STOP_CALL_WAITING_TONE); 181 mCallWaitingCall = null; 182 } 183 184 mCallWaitingPlayer.stopTone(); 185 mCallWaitingPlayer = null; 186 } 187 } 188 shouldRingForContact(Uri contactUri)189 private boolean shouldRingForContact(Uri contactUri) { 190 final NotificationManager manager = 191 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 192 final Bundle extras = new Bundle(); 193 if (contactUri != null) { 194 extras.putStringArray(Notification.EXTRA_PEOPLE, new String[] {contactUri.toString()}); 195 } 196 return manager.matchesCallFilter(extras); 197 } 198 shouldVibrate(Context context)199 private boolean shouldVibrate(Context context) { 200 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 201 int ringerMode = audioManager.getRingerModeInternal(); 202 if (getVibrateWhenRinging(context)) { 203 return ringerMode != AudioManager.RINGER_MODE_SILENT; 204 } else { 205 return ringerMode == AudioManager.RINGER_MODE_VIBRATE; 206 } 207 } 208 getVibrateWhenRinging(Context context)209 private boolean getVibrateWhenRinging(Context context) { 210 if (!mVibrator.hasVibrator()) { 211 return false; 212 } 213 return mSystemSettingsUtil.canVibrateWhenRinging(context); 214 } 215 } 216