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 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 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 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 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 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 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 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 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 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 326 private boolean getVibrateWhenRinging(Context context) { 327 if (!mVibrator.hasVibrator()) { 328 return false; 329 } 330 return mSystemSettingsUtil.canVibrateWhenRinging(context); 331 } 332 } 333