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.app.Person; 22 import android.content.Context; 23 import android.os.VibrationEffect; 24 import android.telecom.Log; 25 import android.telecom.TelecomManager; 26 import android.media.AudioAttributes; 27 import android.media.AudioManager; 28 import android.media.Ringtone; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.os.Vibrator; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 35 import java.util.ArrayList; 36 37 /** 38 * Controls the ringtone player. 39 */ 40 @VisibleForTesting 41 public class Ringer { 42 @VisibleForTesting 43 public VibrationEffect mDefaultVibrationEffect; 44 45 private static final long[] PULSE_PATTERN = {0,12,250,12,500, // priming + interval 46 50,50,50,50,50,50,50,50,50,50,50,50,50,50, // ease-in 47 300, // Peak 48 1000}; // pause before repetition 49 50 private static final int[] PULSE_AMPLITUDE = {0,255,0,255,0, // priming + interval 51 77,77,78,79,81,84,87,93,101,114,133,162,205,255, // ease-in (min amplitude = 30%) 52 255, // Peak 53 0}; // pause before repetition 54 55 private static final long[] SIMPLE_VIBRATION_PATTERN = { 56 0, // No delay before starting 57 1000, // How long to vibrate 58 1000, // How long to wait before vibrating again 59 }; 60 61 private static final int[] SIMPLE_VIBRATION_AMPLITUDE = { 62 0, // No delay before starting 63 255, // Vibrate full amplitude 64 0, // No amplitude while waiting 65 }; 66 67 /** 68 * Indicates that vibration should be repeated at element 5 in the {@link #PULSE_AMPLITUDE} and 69 * {@link #PULSE_PATTERN} arrays. This means repetition will happen for the main ease-in/peak 70 * pattern, but the priming + interval part will not be repeated. 71 */ 72 private static final int REPEAT_VIBRATION_AT = 5; 73 74 private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; 75 76 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 77 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 78 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 79 .build(); 80 81 /** 82 * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming 83 * calls and explicit ordering is useful for maintaining the proper state of the ringer. 84 */ 85 86 private final SystemSettingsUtil mSystemSettingsUtil; 87 private final InCallTonePlayer.Factory mPlayerFactory; 88 private final AsyncRingtonePlayer mRingtonePlayer; 89 private final Context mContext; 90 private final Vibrator mVibrator; 91 private final InCallController mInCallController; 92 93 private InCallTonePlayer mCallWaitingPlayer; 94 private RingtoneFactory mRingtoneFactory; 95 96 /** 97 * Call objects that are ringing, vibrating or call-waiting. These are used only for logging 98 * purposes. 99 */ 100 private Call mRingingCall; 101 private Call mVibratingCall; 102 private Call mCallWaitingCall; 103 104 /** 105 * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls. 106 */ 107 private boolean mIsVibrating = false; 108 109 /** Initializes the Ringer. */ 110 @VisibleForTesting Ringer( InCallTonePlayer.Factory playerFactory, Context context, SystemSettingsUtil systemSettingsUtil, AsyncRingtonePlayer asyncRingtonePlayer, RingtoneFactory ringtoneFactory, Vibrator vibrator, InCallController inCallController)111 public Ringer( 112 InCallTonePlayer.Factory playerFactory, 113 Context context, 114 SystemSettingsUtil systemSettingsUtil, 115 AsyncRingtonePlayer asyncRingtonePlayer, 116 RingtoneFactory ringtoneFactory, 117 Vibrator vibrator, 118 InCallController inCallController) { 119 120 mSystemSettingsUtil = systemSettingsUtil; 121 mPlayerFactory = playerFactory; 122 mContext = context; 123 // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this 124 // vibrator object will be isolated from others. 125 mVibrator = vibrator; 126 mRingtonePlayer = asyncRingtonePlayer; 127 mRingtoneFactory = ringtoneFactory; 128 mInCallController = inCallController; 129 130 if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { 131 mDefaultVibrationEffect = VibrationEffect.createWaveform(SIMPLE_VIBRATION_PATTERN, 132 SIMPLE_VIBRATION_AMPLITUDE, REPEAT_SIMPLE_VIBRATION_AT); 133 } else { 134 mDefaultVibrationEffect = VibrationEffect.createWaveform(PULSE_PATTERN, 135 PULSE_AMPLITUDE, REPEAT_VIBRATION_AT); 136 } 137 } 138 startRinging(Call foregroundCall, boolean isHfpDeviceAttached)139 public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { 140 if (foregroundCall == null) { 141 Log.wtf(this, "startRinging called with null foreground call."); 142 return false; 143 } 144 145 AudioManager audioManager = 146 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 147 boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; 148 boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri()); 149 boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null); 150 boolean isSelfManaged = foregroundCall.isSelfManaged(); 151 152 boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; 153 boolean hasExternalRinger = hasExternalRinger(foregroundCall); 154 // Acquire audio focus under any of the following conditions: 155 // 1. Should ring for contact and there's an HFP device attached 156 // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone 157 // present. 158 // 3. The call is self-managed. 159 boolean shouldAcquireAudioFocus = 160 isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; 161 162 // Don't do call waiting operations or vibration unless these are false. 163 boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); 164 boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); 165 boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || 166 hasExternalRinger; 167 168 if (endEarly) { 169 if (letDialerHandleRinging) { 170 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING); 171 } 172 Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + 173 "isSelfManaged=%s, hasExternalRinger=%s", isTheaterModeOn, 174 letDialerHandleRinging, isSelfManaged, hasExternalRinger); 175 return shouldAcquireAudioFocus; 176 } 177 178 stopCallWaiting(); 179 180 VibrationEffect effect; 181 if (isRingerAudible) { 182 mRingingCall = foregroundCall; 183 Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); 184 // Because we wait until a contact info query to complete before processing a 185 // call (for the purposes of direct-to-voicemail), the information about custom 186 // ringtones should be available by the time this code executes. We can safely 187 // request the custom ringtone from the call and expect it to be current. 188 mRingtonePlayer.play(mRingtoneFactory, foregroundCall); 189 effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); 190 } else { 191 Log.i(this, "startRinging: skipping because ringer would not be audible. " + 192 "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", 193 isVolumeOverZero, shouldRingForContact, isRingtonePresent); 194 effect = mDefaultVibrationEffect; 195 } 196 197 if (shouldVibrate(mContext, foregroundCall) && !mIsVibrating && shouldRingForContact) { 198 mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES); 199 mIsVibrating = true; 200 } else if (mIsVibrating) { 201 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, "already vibrating"); 202 } 203 204 return shouldAcquireAudioFocus; 205 } 206 getVibrationEffectForCall(RingtoneFactory factory, Call call)207 private VibrationEffect getVibrationEffectForCall(RingtoneFactory factory, Call call) { 208 VibrationEffect effect = null; 209 Ringtone ringtone = factory.getRingtone(call); 210 Uri ringtoneUri = ringtone != null ? ringtone.getUri() : null; 211 if (ringtoneUri != null) { 212 effect = VibrationEffect.get(ringtoneUri, mContext); 213 } 214 215 if (effect == null) { 216 effect = mDefaultVibrationEffect; 217 } 218 return effect; 219 } 220 startCallWaiting(Call call)221 public void startCallWaiting(Call call) { 222 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 223 return; 224 } 225 226 if (mInCallController.doesConnectedDialerSupportRinging()) { 227 Log.addEvent(call, LogUtils.Events.SKIP_RINGING); 228 return; 229 } 230 231 if (call.isSelfManaged()) { 232 Log.addEvent(call, LogUtils.Events.SKIP_RINGING, "Self-managed"); 233 return; 234 } 235 236 Log.v(this, "Playing call-waiting tone."); 237 238 stopRinging(); 239 240 if (mCallWaitingPlayer == null) { 241 Log.addEvent(call, LogUtils.Events.START_CALL_WAITING_TONE); 242 mCallWaitingCall = call; 243 mCallWaitingPlayer = 244 mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING); 245 mCallWaitingPlayer.startTone(); 246 } 247 } 248 stopRinging()249 public void stopRinging() { 250 if (mRingingCall != null) { 251 Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER); 252 mRingingCall = null; 253 } 254 255 mRingtonePlayer.stop(); 256 257 if (mIsVibrating) { 258 Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR); 259 mVibrator.cancel(); 260 mIsVibrating = false; 261 mVibratingCall = null; 262 } 263 } 264 stopCallWaiting()265 public void stopCallWaiting() { 266 Log.v(this, "stop call waiting."); 267 if (mCallWaitingPlayer != null) { 268 if (mCallWaitingCall != null) { 269 Log.addEvent(mCallWaitingCall, LogUtils.Events.STOP_CALL_WAITING_TONE); 270 mCallWaitingCall = null; 271 } 272 273 mCallWaitingPlayer.stopTone(); 274 mCallWaitingPlayer = null; 275 } 276 } 277 shouldRingForContact(Uri contactUri)278 private boolean shouldRingForContact(Uri contactUri) { 279 final NotificationManager manager = 280 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 281 final Bundle peopleExtras = new Bundle(); 282 if (contactUri != null) { 283 ArrayList<Person> personList = new ArrayList<>(); 284 personList.add(new Person.Builder().setUri(contactUri.toString()).build()); 285 peopleExtras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, personList); 286 } 287 return manager.matchesCallFilter(peopleExtras); 288 } 289 hasExternalRinger(Call foregroundCall)290 private boolean hasExternalRinger(Call foregroundCall) { 291 Bundle intentExtras = foregroundCall.getIntentExtras(); 292 if (intentExtras != null) { 293 return intentExtras.getBoolean(TelecomManager.EXTRA_CALL_EXTERNAL_RINGER, false); 294 } else { 295 return false; 296 } 297 } 298 shouldVibrate(Context context, Call call)299 private boolean shouldVibrate(Context context, Call call) { 300 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 301 int ringerMode = audioManager.getRingerModeInternal(); 302 boolean shouldVibrate; 303 if (getVibrateWhenRinging(context)) { 304 shouldVibrate = ringerMode != AudioManager.RINGER_MODE_SILENT; 305 } else { 306 shouldVibrate = ringerMode == AudioManager.RINGER_MODE_VIBRATE; 307 } 308 309 // Technically this should be in the calling method, but it seemed a little odd to pass 310 // around a whole bunch of state just for logging purposes. 311 if (shouldVibrate) { 312 Log.addEvent(call, LogUtils.Events.START_VIBRATOR, 313 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", 314 mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), 315 ringerMode, mIsVibrating); 316 } else { 317 Log.addEvent(call, LogUtils.Events.SKIP_VIBRATION, 318 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", 319 mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), 320 ringerMode, mIsVibrating); 321 } 322 323 return shouldVibrate; 324 } 325 getVibrateWhenRinging(Context context)326 private boolean getVibrateWhenRinging(Context context) { 327 if (!mVibrator.hasVibrator()) { 328 return false; 329 } 330 return mSystemSettingsUtil.canVibrateWhenRinging(context); 331 } 332 } 333