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.media.AudioAttributes; 24 import android.media.AudioManager; 25 import android.media.Ringtone; 26 import android.media.VolumeShaper; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.HandlerThread; 31 import android.os.VibrationEffect; 32 import android.os.Vibrator; 33 import android.telecom.Log; 34 import android.telecom.TelecomManager; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.server.telecom.LogUtils.EventTimer; 38 39 import java.util.ArrayList; 40 import java.util.concurrent.CompletableFuture; 41 import java.util.concurrent.ExecutionException; 42 import java.util.concurrent.TimeUnit; 43 import java.util.concurrent.TimeoutException; 44 45 /** 46 * Controls the ringtone player. 47 */ 48 @VisibleForTesting 49 public class Ringer { 50 public static class VibrationEffectProxy { createWaveform(long[] timings, int[] amplitudes, int repeat)51 public VibrationEffect createWaveform(long[] timings, int[] amplitudes, int repeat) { 52 return VibrationEffect.createWaveform(timings, amplitudes, repeat); 53 } 54 get(Uri ringtoneUri, Context context)55 public VibrationEffect get(Uri ringtoneUri, Context context) { 56 return VibrationEffect.get(ringtoneUri, context); 57 } 58 } 59 @VisibleForTesting 60 public VibrationEffect mDefaultVibrationEffect; 61 62 private static final long[] PULSE_PRIMING_PATTERN = {0,12,250,12,500}; // priming + interval 63 64 private static final int[] PULSE_PRIMING_AMPLITUDE = {0,255,0,255,0}; // priming + interval 65 66 // ease-in + peak + pause 67 private static final long[] PULSE_RAMPING_PATTERN = { 68 50,50,50,50,50,50,50,50,50,50,50,50,50,50,300,1000}; 69 70 // ease-in (min amplitude = 30%) + peak + pause 71 private static final int[] PULSE_RAMPING_AMPLITUDE = { 72 77,77,78,79,81,84,87,93,101,114,133,162,205,255,255,0}; 73 74 private static final long[] PULSE_PATTERN; 75 76 private static final int[] PULSE_AMPLITUDE; 77 78 static { 79 // construct complete pulse pattern 80 PULSE_PATTERN = new long[PULSE_PRIMING_PATTERN.length + PULSE_RAMPING_PATTERN.length]; System.arraycopy( PULSE_PRIMING_PATTERN, 0, PULSE_PATTERN, 0, PULSE_PRIMING_PATTERN.length)81 System.arraycopy( 82 PULSE_PRIMING_PATTERN, 0, PULSE_PATTERN, 0, PULSE_PRIMING_PATTERN.length); System.arraycopy(PULSE_RAMPING_PATTERN, 0, PULSE_PATTERN, PULSE_PRIMING_PATTERN.length, PULSE_RAMPING_PATTERN.length)83 System.arraycopy(PULSE_RAMPING_PATTERN, 0, PULSE_PATTERN, 84 PULSE_PRIMING_PATTERN.length, PULSE_RAMPING_PATTERN.length); 85 86 // construct complete pulse amplitude 87 PULSE_AMPLITUDE = new int[PULSE_PRIMING_AMPLITUDE.length + PULSE_RAMPING_AMPLITUDE.length]; System.arraycopy( PULSE_PRIMING_AMPLITUDE, 0, PULSE_AMPLITUDE, 0, PULSE_PRIMING_AMPLITUDE.length)88 System.arraycopy( 89 PULSE_PRIMING_AMPLITUDE, 0, PULSE_AMPLITUDE, 0, PULSE_PRIMING_AMPLITUDE.length); System.arraycopy(PULSE_RAMPING_AMPLITUDE, 0, PULSE_AMPLITUDE, PULSE_PRIMING_AMPLITUDE.length, PULSE_RAMPING_AMPLITUDE.length)90 System.arraycopy(PULSE_RAMPING_AMPLITUDE, 0, PULSE_AMPLITUDE, 91 PULSE_PRIMING_AMPLITUDE.length, PULSE_RAMPING_AMPLITUDE.length); 92 } 93 94 private static final long[] SIMPLE_VIBRATION_PATTERN = { 95 0, // No delay before starting 96 1000, // How long to vibrate 97 1000, // How long to wait before vibrating again 98 }; 99 100 private static final int[] SIMPLE_VIBRATION_AMPLITUDE = { 101 0, // No delay before starting 102 255, // Vibrate full amplitude 103 0, // No amplitude while waiting 104 }; 105 106 /** 107 * Indicates that vibration should be repeated at element 5 in the {@link #PULSE_AMPLITUDE} and 108 * {@link #PULSE_PATTERN} arrays. This means repetition will happen for the main ease-in/peak 109 * pattern, but the priming + interval part will not be repeated. 110 */ 111 private static final int REPEAT_VIBRATION_AT = 5; 112 113 private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; 114 115 private static final int DEFAULT_RAMPING_RINGER_DURATION = 10000; // 10 seconds 116 117 private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds 118 119 private int mRampingRingerDuration = -1; // ramping ringer duration in millisecond 120 121 // vibration duration before ramping ringer in second 122 private int mRampingRingerVibrationDuration = 0; 123 124 private static final float EPSILON = 1e-6f; 125 126 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 127 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 128 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 129 .build(); 130 131 private static VibrationEffect mRampingRingerVibrationEffect; 132 private static VolumeShaper.Configuration mVolumeShaperConfig; 133 134 /** 135 * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming 136 * calls and explicit ordering is useful for maintaining the proper state of the ringer. 137 */ 138 139 private final SystemSettingsUtil mSystemSettingsUtil; 140 private final InCallTonePlayer.Factory mPlayerFactory; 141 private final AsyncRingtonePlayer mRingtonePlayer; 142 private final Context mContext; 143 private final Vibrator mVibrator; 144 private final InCallController mInCallController; 145 private final VibrationEffectProxy mVibrationEffectProxy; 146 private final boolean mIsHapticPlaybackSupportedByDevice; 147 /** 148 * For unit testing purposes only; when set, {@link #startRinging(Call, boolean)} will complete 149 * the future provided by the test using {@link #setBlockOnRingingFuture(CompletableFuture)}. 150 */ 151 private CompletableFuture<Void> mBlockOnRingingFuture = null; 152 153 private CompletableFuture<Void> mVibrateFuture = CompletableFuture.completedFuture(null); 154 155 private InCallTonePlayer mCallWaitingPlayer; 156 private RingtoneFactory mRingtoneFactory; 157 private AudioManager mAudioManager; 158 159 /** 160 * Call objects that are ringing, vibrating or call-waiting. These are used only for logging 161 * purposes. 162 */ 163 private Call mRingingCall; 164 private Call mVibratingCall; 165 private Call mCallWaitingCall; 166 167 /** 168 * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls. 169 */ 170 private boolean mIsVibrating = false; 171 172 private Handler mHandler = null; 173 174 /** Initializes the Ringer. */ 175 @VisibleForTesting Ringer( InCallTonePlayer.Factory playerFactory, Context context, SystemSettingsUtil systemSettingsUtil, AsyncRingtonePlayer asyncRingtonePlayer, RingtoneFactory ringtoneFactory, Vibrator vibrator, VibrationEffectProxy vibrationEffectProxy, InCallController inCallController)176 public Ringer( 177 InCallTonePlayer.Factory playerFactory, 178 Context context, 179 SystemSettingsUtil systemSettingsUtil, 180 AsyncRingtonePlayer asyncRingtonePlayer, 181 RingtoneFactory ringtoneFactory, 182 Vibrator vibrator, 183 VibrationEffectProxy vibrationEffectProxy, 184 InCallController inCallController) { 185 186 mSystemSettingsUtil = systemSettingsUtil; 187 mPlayerFactory = playerFactory; 188 mContext = context; 189 // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this 190 // vibrator object will be isolated from others. 191 mVibrator = vibrator; 192 mRingtonePlayer = asyncRingtonePlayer; 193 mRingtoneFactory = ringtoneFactory; 194 mInCallController = inCallController; 195 mVibrationEffectProxy = vibrationEffectProxy; 196 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 197 198 if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { 199 mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN, 200 SIMPLE_VIBRATION_AMPLITUDE, REPEAT_SIMPLE_VIBRATION_AT); 201 } else { 202 mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(PULSE_PATTERN, 203 PULSE_AMPLITUDE, REPEAT_VIBRATION_AT); 204 } 205 206 mIsHapticPlaybackSupportedByDevice = 207 mSystemSettingsUtil.isHapticPlaybackSupported(mContext); 208 } 209 210 @VisibleForTesting setBlockOnRingingFuture(CompletableFuture<Void> future)211 public void setBlockOnRingingFuture(CompletableFuture<Void> future) { 212 mBlockOnRingingFuture = future; 213 } 214 startRinging(Call foregroundCall, boolean isHfpDeviceAttached)215 public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { 216 if (foregroundCall == null) { 217 Log.wtf(this, "startRinging called with null foreground call."); 218 return false; 219 } 220 221 if (foregroundCall.getState() != CallState.RINGING 222 && foregroundCall.getState() != CallState.SIMULATED_RINGING) { 223 // Its possible for bluetooth to connect JUST as a call goes active, which would mean 224 // the call would start ringing again. 225 Log.i(this, "startRinging called for non-ringing foreground callid=%s", 226 foregroundCall.getId()); 227 return false; 228 } 229 230 // Use completable future to establish a timeout, not intent to make these work outside the 231 // main thread asynchronously 232 // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking. 233 CompletableFuture<RingerAttributes> ringerAttributesFuture = CompletableFuture 234 .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached), 235 new LoggedHandlerExecutor(getHandler(), "R.sR", null)); 236 237 RingerAttributes attributes = null; 238 try { 239 attributes = ringerAttributesFuture.get( 240 RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); 241 } catch (ExecutionException | InterruptedException | TimeoutException e) { 242 // Keep attributs as null 243 Log.i(this, "getAttributes error: " + e); 244 } 245 246 if (attributes == null) { 247 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "RingerAttributes error"); 248 return false; 249 } 250 251 if (attributes.isEndEarly()) { 252 if (attributes.letDialerHandleRinging()) { 253 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles"); 254 } 255 if (attributes.isSilentRingingRequested()) { 256 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing " 257 + "requested"); 258 } 259 if (mBlockOnRingingFuture != null) { 260 mBlockOnRingingFuture.complete(null); 261 } 262 return attributes.shouldAcquireAudioFocus(); 263 } 264 265 stopCallWaiting(); 266 267 VibrationEffect effect; 268 CompletableFuture<Boolean> hapticsFuture = null; 269 // Determine if the settings and DND mode indicate that the vibrator can be used right now. 270 boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall); 271 if (attributes.isRingerAudible()) { 272 mRingingCall = foregroundCall; 273 Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); 274 // Because we wait until a contact info query to complete before processing a 275 // call (for the purposes of direct-to-voicemail), the information about custom 276 // ringtones should be available by the time this code executes. We can safely 277 // request the custom ringtone from the call and expect it to be current. 278 if (mSystemSettingsUtil.applyRampingRinger(mContext) 279 && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) { 280 Log.i(this, "start ramping ringer."); 281 // configure vibration effect for ramping ringer. 282 int previousRampingRingerVibrationDuration = mRampingRingerVibrationDuration; 283 // get vibration duration in millisecond and round down to second. 284 mRampingRingerVibrationDuration = 285 mSystemSettingsUtil.getRampingRingerVibrationDuration() >= 0 286 ? mSystemSettingsUtil.getRampingRingerVibrationDuration() / 1000 287 : 0; 288 if (mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) { 289 effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); 290 } else { 291 effect = mDefaultVibrationEffect; 292 } 293 294 // configure volume shaper for ramping ringer 295 int previousRampingRingerDuration = mRampingRingerDuration; 296 mRampingRingerDuration = 297 mSystemSettingsUtil.getRampingRingerDuration() > 0 298 ? mSystemSettingsUtil.getRampingRingerDuration() 299 : DEFAULT_RAMPING_RINGER_DURATION; 300 if (mRampingRingerDuration != previousRampingRingerDuration 301 || mRampingRingerVibrationDuration != previousRampingRingerVibrationDuration 302 || mVolumeShaperConfig == null) { 303 float silencePoint = (float) (mRampingRingerVibrationDuration * 1000) 304 / (float) (mRampingRingerVibrationDuration * 1000 + mRampingRingerDuration); 305 mVolumeShaperConfig = new VolumeShaper.Configuration.Builder() 306 .setDuration(mRampingRingerVibrationDuration * 1000 307 + mRampingRingerDuration) 308 .setCurve(new float[] {0.f, silencePoint + EPSILON /*keep monotonicity*/, 309 1.f}, new float[] {0.f, 0.f, 1.f}) 310 .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR) 311 .build(); 312 } 313 hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, 314 mVolumeShaperConfig, isVibratorEnabled); 315 } else { 316 // Ramping ringtone is not enabled. 317 hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null, 318 isVibratorEnabled); 319 effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); 320 } 321 } else { 322 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " 323 + attributes.getInaudibleReason()); 324 effect = mDefaultVibrationEffect; 325 } 326 327 if (hapticsFuture != null) { 328 final boolean shouldRingForContact = attributes.shouldRingForContact(); 329 final boolean isRingerAudible = attributes.isRingerAudible(); 330 mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> { 331 if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) { 332 Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b", 333 isUsingAudioCoupledHaptics, mIsHapticPlaybackSupportedByDevice); 334 maybeStartVibration(foregroundCall, shouldRingForContact, effect, 335 isVibratorEnabled, isRingerAudible); 336 } else if (mSystemSettingsUtil.applyRampingRinger(mContext) 337 && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig() 338 && !mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) { 339 Log.i(this, "startRinging: apply ramping ringer vibration"); 340 maybeStartVibration(foregroundCall, shouldRingForContact, effect, 341 isVibratorEnabled, isRingerAudible); 342 } else { 343 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, 344 "using audio-coupled haptics"); 345 } 346 }); 347 if (mBlockOnRingingFuture != null) { 348 mVibrateFuture.whenComplete((v, e) -> mBlockOnRingingFuture.complete(null)); 349 } 350 } else { 351 if (mBlockOnRingingFuture != null) { 352 mBlockOnRingingFuture.complete(null); 353 } 354 Log.w(this, "startRinging: No haptics future; fallback to default behavior"); 355 maybeStartVibration(foregroundCall, attributes.shouldRingForContact(), effect, 356 isVibratorEnabled, attributes.isRingerAudible()); 357 } 358 359 return attributes.shouldAcquireAudioFocus(); 360 } 361 maybeStartVibration(Call foregroundCall, boolean shouldRingForContact, VibrationEffect effect, boolean isVibrationEnabled, boolean isRingerAudible)362 private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact, 363 VibrationEffect effect, boolean isVibrationEnabled, boolean isRingerAudible) { 364 if (isVibrationEnabled 365 && !mIsVibrating && shouldRingForContact) { 366 if (mSystemSettingsUtil.applyRampingRinger(mContext) 367 && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig() 368 && isRingerAudible) { 369 Log.i(this, "start vibration for ramping ringer."); 370 mIsVibrating = true; 371 mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES); 372 } else { 373 Log.i(this, "start normal vibration."); 374 mIsVibrating = true; 375 mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES); 376 } 377 } else if (mIsVibrating) { 378 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, "already vibrating"); 379 } 380 } 381 getVibrationEffectForCall(RingtoneFactory factory, Call call)382 private VibrationEffect getVibrationEffectForCall(RingtoneFactory factory, Call call) { 383 VibrationEffect effect = null; 384 Ringtone ringtone = factory.getRingtone(call); 385 Uri ringtoneUri = ringtone != null ? ringtone.getUri() : null; 386 if (ringtoneUri != null) { 387 try { 388 effect = mVibrationEffectProxy.get(ringtoneUri, mContext); 389 } catch (IllegalArgumentException iae) { 390 // Deep in the bowels of the VibrationEffect class it is possible for an 391 // IllegalArgumentException to be thrown if there is an invalid URI specified in the 392 // device config, or a content provider failure. Rather than crashing the Telecom 393 // process we will just use the default vibration effect. 394 Log.e(this, iae, "getVibrationEffectForCall: failed to get vibration effect"); 395 effect = null; 396 } 397 } 398 399 if (effect == null) { 400 effect = mDefaultVibrationEffect; 401 } 402 return effect; 403 } 404 startCallWaiting(Call call)405 public void startCallWaiting(Call call) { 406 startCallWaiting(call, null); 407 } 408 startCallWaiting(Call call, String reason)409 public void startCallWaiting(Call call, String reason) { 410 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 411 return; 412 } 413 414 if (mInCallController.doesConnectedDialerSupportRinging()) { 415 Log.addEvent(call, LogUtils.Events.SKIP_RINGING, "Dialer handles"); 416 return; 417 } 418 419 if (call.isSelfManaged()) { 420 Log.addEvent(call, LogUtils.Events.SKIP_RINGING, "Self-managed"); 421 return; 422 } 423 424 Log.v(this, "Playing call-waiting tone."); 425 426 stopRinging(); 427 428 if (mCallWaitingPlayer == null) { 429 Log.addEvent(call, LogUtils.Events.START_CALL_WAITING_TONE, reason); 430 mCallWaitingCall = call; 431 mCallWaitingPlayer = 432 mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING); 433 mCallWaitingPlayer.startTone(); 434 } 435 } 436 stopRinging()437 public void stopRinging() { 438 if (mRingingCall != null) { 439 Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER); 440 mRingingCall = null; 441 } 442 443 mRingtonePlayer.stop(); 444 445 // If we haven't started vibrating because we were waiting for the haptics info, cancel 446 // it and don't vibrate at all. 447 if (mVibrateFuture != null) { 448 mVibrateFuture.cancel(true); 449 } 450 451 if (mIsVibrating) { 452 Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR); 453 mVibrator.cancel(); 454 mIsVibrating = false; 455 mVibratingCall = null; 456 } 457 } 458 stopCallWaiting()459 public void stopCallWaiting() { 460 Log.v(this, "stop call waiting."); 461 if (mCallWaitingPlayer != null) { 462 if (mCallWaitingCall != null) { 463 Log.addEvent(mCallWaitingCall, LogUtils.Events.STOP_CALL_WAITING_TONE); 464 mCallWaitingCall = null; 465 } 466 467 mCallWaitingPlayer.stopTone(); 468 mCallWaitingPlayer = null; 469 } 470 } 471 shouldRingForContact(Uri contactUri)472 private boolean shouldRingForContact(Uri contactUri) { 473 final NotificationManager manager = 474 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 475 final Bundle peopleExtras = new Bundle(); 476 if (contactUri != null) { 477 ArrayList<Person> personList = new ArrayList<>(); 478 personList.add(new Person.Builder().setUri(contactUri.toString()).build()); 479 peopleExtras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, personList); 480 } 481 return manager.matchesCallFilter(peopleExtras); 482 } 483 hasExternalRinger(Call foregroundCall)484 private boolean hasExternalRinger(Call foregroundCall) { 485 Bundle intentExtras = foregroundCall.getIntentExtras(); 486 if (intentExtras != null) { 487 return intentExtras.getBoolean(TelecomManager.EXTRA_CALL_EXTERNAL_RINGER, false); 488 } else { 489 return false; 490 } 491 } 492 isVibratorEnabled(Context context, Call call)493 private boolean isVibratorEnabled(Context context, Call call) { 494 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 495 int ringerMode = audioManager.getRingerModeInternal(); 496 boolean shouldVibrate; 497 if (getVibrateWhenRinging(context)) { 498 shouldVibrate = ringerMode != AudioManager.RINGER_MODE_SILENT; 499 } else { 500 shouldVibrate = ringerMode == AudioManager.RINGER_MODE_VIBRATE; 501 } 502 503 // Technically this should be in the calling method, but it seemed a little odd to pass 504 // around a whole bunch of state just for logging purposes. 505 if (shouldVibrate) { 506 Log.addEvent(call, LogUtils.Events.START_VIBRATOR, 507 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", 508 mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), 509 ringerMode, mIsVibrating); 510 } else { 511 Log.addEvent(call, LogUtils.Events.SKIP_VIBRATION, 512 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", 513 mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), 514 ringerMode, mIsVibrating); 515 } 516 517 return shouldVibrate; 518 } 519 getVibrateWhenRinging(Context context)520 private boolean getVibrateWhenRinging(Context context) { 521 if (!mVibrator.hasVibrator()) { 522 return false; 523 } 524 return mSystemSettingsUtil.canVibrateWhenRinging(context) 525 || (mSystemSettingsUtil.applyRampingRinger(context) 526 && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()); 527 } 528 getRingerAttributes(Call call, boolean isHfpDeviceAttached)529 private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) { 530 RingerAttributes.Builder builder = new RingerAttributes.Builder(); 531 532 LogUtils.EventTimer timer = new EventTimer(); 533 534 boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; 535 timer.record("isVolumeOverZero"); 536 boolean shouldRingForContact = shouldRingForContact(call.getContactUri()); 537 timer.record("shouldRingForContact"); 538 boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(call) == null); 539 timer.record("getRingtone"); 540 boolean isSelfManaged = call.isSelfManaged(); 541 timer.record("isSelfManaged"); 542 boolean isSilentRingingRequested = call.isSilentRingingRequested(); 543 timer.record("isSilentRingRequested"); 544 545 boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; 546 timer.record("isRingerAudible"); 547 String inaudibleReason = ""; 548 if (!isRingerAudible) { 549 inaudibleReason = String.format( 550 "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", 551 isVolumeOverZero, shouldRingForContact, isRingtonePresent); 552 } 553 554 boolean hasExternalRinger = hasExternalRinger(call); 555 timer.record("hasExternalRinger"); 556 // Don't do call waiting operations or vibration unless these are false. 557 boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); 558 timer.record("isTheaterModeOn"); 559 boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); 560 timer.record("letDialerHandleRinging"); 561 562 Log.i(this, "startRinging timings: " + timer); 563 boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || 564 hasExternalRinger || isSilentRingingRequested; 565 566 if (endEarly) { 567 Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + 568 "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", 569 isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, 570 isSilentRingingRequested); 571 } 572 573 // Acquire audio focus under any of the following conditions: 574 // 1. Should ring for contact and there's an HFP device attached 575 // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone 576 // present. 577 // 3. The call is self-managed. 578 boolean shouldAcquireAudioFocus = 579 isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; 580 581 return builder.setEndEarly(endEarly) 582 .setLetDialerHandleRinging(letDialerHandleRinging) 583 .setAcquireAudioFocus(shouldAcquireAudioFocus) 584 .setRingerAudible(isRingerAudible) 585 .setInaudibleReason(inaudibleReason) 586 .setShouldRingForContact(shouldRingForContact) 587 .setSilentRingingRequested(isSilentRingingRequested) 588 .build(); 589 } 590 getHandler()591 private Handler getHandler() { 592 if (mHandler == null) { 593 HandlerThread handlerThread = new HandlerThread("Ringer"); 594 handlerThread.start(); 595 mHandler = handlerThread.getThreadHandler(); 596 } 597 return mHandler; 598 } 599 } 600