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 static android.provider.CallLog.Calls.USER_MISSED_DND_MODE; 20 import static android.provider.CallLog.Calls.USER_MISSED_LOW_RING_VOLUME; 21 import static android.provider.CallLog.Calls.USER_MISSED_NO_VIBRATE; 22 import static android.provider.Settings.Global.ZEN_MODE_OFF; 23 24 import android.annotation.NonNull; 25 import android.app.Notification; 26 import android.app.NotificationManager; 27 import android.app.Person; 28 import android.content.Context; 29 import android.media.AudioManager; 30 import android.media.Ringtone; 31 import android.media.VolumeShaper; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.HandlerThread; 36 import android.os.UserHandle; 37 import android.os.UserManager; 38 import android.os.VibrationAttributes; 39 import android.os.VibrationEffect; 40 import android.os.Vibrator; 41 import android.telecom.Log; 42 import android.telecom.TelecomManager; 43 import android.view.accessibility.AccessibilityManager; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.server.telecom.LogUtils.EventTimer; 47 48 import java.util.ArrayList; 49 import java.util.concurrent.CompletableFuture; 50 import java.util.concurrent.CountDownLatch; 51 import java.util.concurrent.ExecutionException; 52 import java.util.concurrent.TimeUnit; 53 import java.util.concurrent.TimeoutException; 54 import java.util.function.BiConsumer; 55 import java.util.function.Supplier; 56 57 /** 58 * Controls the ringtone player. 59 */ 60 @VisibleForTesting 61 public class Ringer { 62 public interface AccessibilityManagerAdapter { startFlashNotificationSequence(@onNull Context context, @AccessibilityManager.FlashNotificationReason int reason)63 boolean startFlashNotificationSequence(@NonNull Context context, 64 @AccessibilityManager.FlashNotificationReason int reason); stopFlashNotificationSequence(@onNull Context context)65 boolean stopFlashNotificationSequence(@NonNull Context context); 66 } 67 /** 68 * Flag only for local debugging. Do not submit enabled. 69 */ 70 private static final boolean DEBUG_RINGER = false; 71 72 public static class VibrationEffectProxy { createWaveform(long[] timings, int[] amplitudes, int repeat)73 public VibrationEffect createWaveform(long[] timings, int[] amplitudes, int repeat) { 74 return VibrationEffect.createWaveform(timings, amplitudes, repeat); 75 } 76 get(Uri ringtoneUri, Context context)77 public VibrationEffect get(Uri ringtoneUri, Context context) { 78 return VibrationEffect.get(ringtoneUri, context); 79 } 80 } 81 @VisibleForTesting 82 public VibrationEffect mDefaultVibrationEffect; 83 84 // Used for test to notify the completion of RingerAttributes 85 private CountDownLatch mAttributesLatch; 86 87 private static final long[] PULSE_PRIMING_PATTERN = {0,12,250,12,500}; // priming + interval 88 89 private static final int[] PULSE_PRIMING_AMPLITUDE = {0,255,0,255,0}; // priming + interval 90 91 // ease-in + peak + pause 92 private static final long[] PULSE_RAMPING_PATTERN = { 93 50,50,50,50,50,50,50,50,50,50,50,50,50,50,300,1000}; 94 95 // ease-in (min amplitude = 30%) + peak + pause 96 private static final int[] PULSE_RAMPING_AMPLITUDE = { 97 77,77,78,79,81,84,87,93,101,114,133,162,205,255,255,0}; 98 99 private static final long[] PULSE_PATTERN; 100 101 private static final int[] PULSE_AMPLITUDE; 102 103 private static final int RAMPING_RINGER_VIBRATION_DURATION = 5000; 104 private static final int RAMPING_RINGER_DURATION = 10000; 105 106 static { 107 // construct complete pulse pattern 108 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)109 System.arraycopy( 110 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)111 System.arraycopy(PULSE_RAMPING_PATTERN, 0, PULSE_PATTERN, 112 PULSE_PRIMING_PATTERN.length, PULSE_RAMPING_PATTERN.length); 113 114 // construct complete pulse amplitude 115 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)116 System.arraycopy( 117 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)118 System.arraycopy(PULSE_RAMPING_AMPLITUDE, 0, PULSE_AMPLITUDE, 119 PULSE_PRIMING_AMPLITUDE.length, PULSE_RAMPING_AMPLITUDE.length); 120 } 121 122 private static final long[] SIMPLE_VIBRATION_PATTERN = { 123 0, // No delay before starting 124 1000, // How long to vibrate 125 1000, // How long to wait before vibrating again 126 }; 127 128 private static final int[] SIMPLE_VIBRATION_AMPLITUDE = { 129 0, // No delay before starting 130 255, // Vibrate full amplitude 131 0, // No amplitude while waiting 132 }; 133 134 /** 135 * Indicates that vibration should be repeated at element 5 in the {@link #PULSE_AMPLITUDE} and 136 * {@link #PULSE_PATTERN} arrays. This means repetition will happen for the main ease-in/peak 137 * pattern, but the priming + interval part will not be repeated. 138 */ 139 private static final int REPEAT_VIBRATION_AT = 5; 140 141 private static final int REPEAT_SIMPLE_VIBRATION_AT = 1; 142 143 private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds 144 145 private static final float EPSILON = 1e-6f; 146 147 private static final VibrationAttributes VIBRATION_ATTRIBUTES = 148 new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_RINGTONE).build(); 149 150 private static VolumeShaper.Configuration mVolumeShaperConfig; 151 152 /** 153 * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming 154 * calls and explicit ordering is useful for maintaining the proper state of the ringer. 155 */ 156 157 private final SystemSettingsUtil mSystemSettingsUtil; 158 private final InCallTonePlayer.Factory mPlayerFactory; 159 private final AsyncRingtonePlayer mRingtonePlayer; 160 private final Context mContext; 161 private final Vibrator mVibrator; 162 private final InCallController mInCallController; 163 private final VibrationEffectProxy mVibrationEffectProxy; 164 private final boolean mIsHapticPlaybackSupportedByDevice; 165 /** 166 * For unit testing purposes only; when set, {@link #startRinging(Call, boolean)} will complete 167 * the future provided by the test using {@link #setBlockOnRingingFuture(CompletableFuture)}. 168 */ 169 private CompletableFuture<Void> mBlockOnRingingFuture = null; 170 171 private InCallTonePlayer mCallWaitingPlayer; 172 private RingtoneFactory mRingtoneFactory; 173 private AudioManager mAudioManager; 174 private NotificationManager mNotificationManager; 175 private AccessibilityManagerAdapter mAccessibilityManagerAdapter; 176 177 /** 178 * Call objects that are ringing, vibrating or call-waiting. These are used only for logging 179 * purposes (except mVibratingCall is also used to ensure consistency). 180 */ 181 private Call mRingingCall; 182 private Call mVibratingCall; 183 private Call mCallWaitingCall; 184 185 /** 186 * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls. 187 */ 188 private boolean mIsVibrating = false; 189 190 private Handler mHandler = null; 191 192 /** 193 * Use lock different from the Telecom sync because ringing process is asynchronous outside that 194 * lock 195 */ 196 private final Object mLock; 197 198 /** Initializes the Ringer. */ 199 @VisibleForTesting Ringer( InCallTonePlayer.Factory playerFactory, Context context, SystemSettingsUtil systemSettingsUtil, AsyncRingtonePlayer asyncRingtonePlayer, RingtoneFactory ringtoneFactory, Vibrator vibrator, VibrationEffectProxy vibrationEffectProxy, InCallController inCallController, NotificationManager notificationManager, AccessibilityManagerAdapter accessibilityManagerAdapter)200 public Ringer( 201 InCallTonePlayer.Factory playerFactory, 202 Context context, 203 SystemSettingsUtil systemSettingsUtil, 204 AsyncRingtonePlayer asyncRingtonePlayer, 205 RingtoneFactory ringtoneFactory, 206 Vibrator vibrator, 207 VibrationEffectProxy vibrationEffectProxy, 208 InCallController inCallController, 209 NotificationManager notificationManager, 210 AccessibilityManagerAdapter accessibilityManagerAdapter) { 211 212 mLock = new Object(); 213 mSystemSettingsUtil = systemSettingsUtil; 214 mPlayerFactory = playerFactory; 215 mContext = context; 216 // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this 217 // vibrator object will be isolated from others. 218 mVibrator = vibrator; 219 mRingtonePlayer = asyncRingtonePlayer; 220 mRingtoneFactory = ringtoneFactory; 221 mInCallController = inCallController; 222 mVibrationEffectProxy = vibrationEffectProxy; 223 mNotificationManager = notificationManager; 224 mAccessibilityManagerAdapter = accessibilityManagerAdapter; 225 226 if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { 227 mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN, 228 SIMPLE_VIBRATION_AMPLITUDE, REPEAT_SIMPLE_VIBRATION_AT); 229 } else { 230 mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(PULSE_PATTERN, 231 PULSE_AMPLITUDE, REPEAT_VIBRATION_AT); 232 } 233 234 mIsHapticPlaybackSupportedByDevice = 235 mSystemSettingsUtil.isHapticPlaybackSupported(mContext); 236 237 mAudioManager = mContext.getSystemService(AudioManager.class); 238 } 239 240 @VisibleForTesting setBlockOnRingingFuture(CompletableFuture<Void> future)241 public void setBlockOnRingingFuture(CompletableFuture<Void> future) { 242 mBlockOnRingingFuture = future; 243 } 244 245 @VisibleForTesting setNotificationManager(NotificationManager notificationManager)246 public void setNotificationManager(NotificationManager notificationManager) { 247 mNotificationManager = notificationManager; 248 } 249 startRinging(Call foregroundCall, boolean isHfpDeviceAttached)250 public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { 251 boolean deferBlockOnRingingFuture = false; 252 // try-finally to ensure that the block on ringing future is always called. 253 try { 254 if (foregroundCall == null) { 255 Log.wtf(this, "startRinging called with null foreground call."); 256 return false; 257 } 258 259 if (foregroundCall.getState() != CallState.RINGING 260 && foregroundCall.getState() != CallState.SIMULATED_RINGING) { 261 // It's possible for bluetooth to connect JUST as a call goes active, which would 262 // mean the call would start ringing again. 263 Log.i(this, "startRinging called for non-ringing foreground callid=%s", 264 foregroundCall.getId()); 265 return false; 266 } 267 268 // Use completable future to establish a timeout, not intent to make these work outside 269 // the main thread asynchronously 270 // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking 271 CompletableFuture<RingerAttributes> ringerAttributesFuture = CompletableFuture 272 .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached), 273 new LoggedHandlerExecutor(getHandler(), "R.sR", null)); 274 275 RingerAttributes attributes = null; 276 try { 277 mAttributesLatch = new CountDownLatch(1); 278 attributes = ringerAttributesFuture.get( 279 RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); 280 } catch (ExecutionException | InterruptedException | TimeoutException e) { 281 // Keep attributes as null 282 Log.i(this, "getAttributes error: " + e); 283 } 284 285 if (attributes == null) { 286 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, 287 "RingerAttributes error"); 288 return false; 289 } 290 291 if (attributes.isEndEarly()) { 292 boolean acquireAudioFocus = attributes.shouldAcquireAudioFocus(); 293 if (attributes.letDialerHandleRinging()) { 294 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles"); 295 // Dialer will setup a ringtone, provide the audio focus if its audible. 296 acquireAudioFocus |= attributes.isRingerAudible(); 297 } 298 299 if (attributes.isSilentRingingRequested()) { 300 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing " 301 + "requested"); 302 } 303 if (attributes.isWorkProfileInQuietMode()) { 304 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, 305 "Work profile in quiet mode"); 306 } 307 return acquireAudioFocus; 308 } 309 310 stopCallWaiting(); 311 312 final boolean shouldFlash = attributes.shouldRingForContact(); 313 if (mAccessibilityManagerAdapter != null && shouldFlash) { 314 Log.addEvent(foregroundCall, LogUtils.Events.FLASH_NOTIFICATION_START); 315 getHandler().post(() -> 316 mAccessibilityManagerAdapter.startFlashNotificationSequence(mContext, 317 AccessibilityManager.FLASH_REASON_CALL)); 318 } 319 320 // Determine if the settings and DND mode indicate that the vibrator can be used right 321 // now. 322 final boolean isVibratorEnabled = 323 isVibratorEnabled(mContext, attributes.shouldRingForContact()); 324 boolean shouldApplyRampingRinger = 325 isVibratorEnabled && mSystemSettingsUtil.isRampingRingerEnabled(mContext); 326 327 boolean isHapticOnly = false; 328 boolean useCustomVibrationEffect = false; 329 330 mVolumeShaperConfig = null; 331 332 if (attributes.isRingerAudible()) { 333 mRingingCall = foregroundCall; 334 Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); 335 // Because we wait until a contact info query to complete before processing a 336 // call (for the purposes of direct-to-voicemail), the information about custom 337 // ringtones should be available by the time this code executes. We can safely 338 // request the custom ringtone from the call and expect it to be current. 339 if (shouldApplyRampingRinger) { 340 Log.i(this, "create ramping ringer."); 341 float silencePoint = (float) (RAMPING_RINGER_VIBRATION_DURATION) 342 / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION); 343 mVolumeShaperConfig = 344 new VolumeShaper.Configuration.Builder() 345 .setDuration(RAMPING_RINGER_VIBRATION_DURATION 346 + RAMPING_RINGER_DURATION) 347 .setCurve( 348 new float[]{0.f, silencePoint + EPSILON 349 /*keep monotonicity*/, 1.f}, 350 new float[]{0.f, 0.f, 1.f}) 351 .setInterpolatorType( 352 VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR) 353 .build(); 354 if (mSystemSettingsUtil.isAudioCoupledVibrationForRampingRingerEnabled()) { 355 useCustomVibrationEffect = true; 356 } 357 } else { 358 if (DEBUG_RINGER) { 359 Log.i(this, "Create ringer with custom vibration effect"); 360 } 361 // Ramping ringtone is not enabled. 362 useCustomVibrationEffect = true; 363 } 364 } else { 365 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, 366 "Inaudible: " + attributes.getInaudibleReason() 367 + " isVibratorEnabled=" + isVibratorEnabled); 368 369 if (isVibratorEnabled) { 370 // If ringer is not audible for this call, then the phone is in "Vibrate" mode. 371 // Use haptic-only ringtone or do not play anything. 372 isHapticOnly = true; 373 if (DEBUG_RINGER) { 374 Log.i(this, "Set ringtone as haptic only: " + isHapticOnly); 375 } 376 } else { 377 foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE); 378 return attributes.shouldAcquireAudioFocus(); // ringer not audible 379 } 380 } 381 382 boolean hapticChannelsMuted = !isVibratorEnabled || !mIsHapticPlaybackSupportedByDevice; 383 if (shouldApplyRampingRinger 384 && !mSystemSettingsUtil.isAudioCoupledVibrationForRampingRingerEnabled() 385 && isVibratorEnabled) { 386 Log.i(this, "Muted haptic channels since audio coupled ramping ringer is disabled"); 387 hapticChannelsMuted = true; 388 } else if (hapticChannelsMuted) { 389 Log.i(this, 390 "Muted haptic channels isVibratorEnabled=%s, hapticPlaybackSupported=%s", 391 isVibratorEnabled, mIsHapticPlaybackSupportedByDevice); 392 } 393 // Defer ringtone creation to the async player thread. 394 Supplier<Ringtone> ringtoneSupplier; 395 final boolean finalHapticChannelsMuted = hapticChannelsMuted; 396 if (isHapticOnly) { 397 if (hapticChannelsMuted) { 398 Log.i(this, 399 "want haptic only ringtone but haptics are muted, skip ringtone play"); 400 ringtoneSupplier = null; 401 } else { 402 ringtoneSupplier = mRingtoneFactory::getHapticOnlyRingtone; 403 } 404 } else { 405 ringtoneSupplier = () -> mRingtoneFactory.getRingtone( 406 foregroundCall, mVolumeShaperConfig, finalHapticChannelsMuted); 407 } 408 409 // If vibration will be done, reserve the vibrator. 410 boolean vibratorReserved = isVibratorEnabled && attributes.shouldRingForContact() 411 && tryReserveVibration(foregroundCall); 412 if (!vibratorReserved) { 413 foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE); 414 Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, 415 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, " 416 + "isVibratorEnabled=%b", 417 mVibrator.hasVibrator(), 418 mSystemSettingsUtil.isRingVibrationEnabled(mContext), 419 mAudioManager.getRingerMode(), isVibratorEnabled); 420 } 421 422 // The vibration logic depends on the loaded ringtone, but we need to defer the ringtone 423 // load to the async ringtone thread. Hence, we bundle up the final part of this method 424 // for that thread to run after loading the ringtone. This logic is intended to run even 425 // if the loaded ringtone is null. However if a stop event arrives before the ringtone 426 // creation finishes, then this consumer can be skipped. 427 final boolean finalUseCustomVibrationEffect = useCustomVibrationEffect; 428 BiConsumer<Ringtone, Boolean> afterRingtoneLogic = 429 (Ringtone ringtone, Boolean stopped) -> { 430 try { 431 if (stopped.booleanValue() || !vibratorReserved) { 432 // don't start vibration if the ringing is already abandoned, or the 433 // vibrator wasn't reserved. This still triggers the mBlockOnRingingFuture. 434 return; 435 } 436 final VibrationEffect vibrationEffect; 437 if (ringtone != null && finalUseCustomVibrationEffect) { 438 if (DEBUG_RINGER) { 439 Log.d(this, "Using ringtone defined vibration effect."); 440 } 441 vibrationEffect = getVibrationEffectForRingtone(ringtone); 442 } else { 443 vibrationEffect = mDefaultVibrationEffect; 444 } 445 446 boolean isUsingAudioCoupledHaptics = 447 !finalHapticChannelsMuted && ringtone != null 448 && ringtone.hasHapticChannels(); 449 vibrateIfNeeded(isUsingAudioCoupledHaptics, foregroundCall, vibrationEffect); 450 } finally { 451 // This is used to signal to tests that the async play() call has completed. 452 if (mBlockOnRingingFuture != null) { 453 mBlockOnRingingFuture.complete(null); 454 } 455 } 456 }; 457 deferBlockOnRingingFuture = true; // Run in vibrationLogic. 458 if (ringtoneSupplier != null) { 459 mRingtonePlayer.play(ringtoneSupplier, afterRingtoneLogic, isHfpDeviceAttached); 460 } else { 461 afterRingtoneLogic.accept(/* ringtone= */ null, /* stopped= */ false); 462 } 463 464 // shouldAcquireAudioFocus is meant to be true, but that check is deferred to here 465 // because until now is when we actually know if the ringtone loading worked. 466 return attributes.shouldAcquireAudioFocus() 467 || (!isHapticOnly && attributes.isRingerAudible()); 468 } finally { 469 // This is used to signal to tests that the async play() call has completed. It can 470 // be deferred into AsyncRingtonePlayer 471 if (mBlockOnRingingFuture != null && !deferBlockOnRingingFuture) { 472 mBlockOnRingingFuture.complete(null); 473 } 474 } 475 } 476 477 /** 478 * Try to reserve the vibrator for this call, returning false if it's already committed. 479 * The vibration will be started by AsyncRingtonePlayer to ensure timing is aligned with the 480 * audio. The logic uses mVibratingCall to say which call is currently getting ready to vibrate, 481 * or actually vibrating (indicated by mIsVibrating). 482 * 483 * Once reserved, the vibrateIfNeeded method is expected to be called. Note that if 484 * audio-coupled haptics were used instead of vibrator, the reservation still stays until 485 * ringing is stopped, because the vibrator is exclusive to a single vibration source. 486 * 487 * Note that this "reservation" is only local to the Ringer - it's not locking the vibrator, so 488 * if it's busy with some other important vibration, this ringer's one may not displace it. 489 */ tryReserveVibration(Call foregroundCall)490 private boolean tryReserveVibration(Call foregroundCall) { 491 synchronized (mLock) { 492 if (mVibratingCall != null || mIsVibrating) { 493 return false; 494 } 495 mVibratingCall = foregroundCall; 496 return true; 497 } 498 } 499 vibrateIfNeeded(boolean isUsingAudioCoupledHaptics, Call foregroundCall, VibrationEffect effect)500 private void vibrateIfNeeded(boolean isUsingAudioCoupledHaptics, Call foregroundCall, 501 VibrationEffect effect) { 502 if (isUsingAudioCoupledHaptics) { 503 Log.addEvent( 504 foregroundCall, LogUtils.Events.SKIP_VIBRATION, "using audio-coupled haptics"); 505 return; 506 } 507 508 synchronized (mLock) { 509 // Ensure the reservation is live. The mIsVibrating check should be redundant. 510 if (foregroundCall == mVibratingCall && !mIsVibrating) { 511 Log.addEvent(foregroundCall, LogUtils.Events.START_VIBRATOR, 512 "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", 513 mVibrator.hasVibrator(), mSystemSettingsUtil.isRingVibrationEnabled(mContext), 514 mAudioManager.getRingerMode(), mIsVibrating); 515 mIsVibrating = true; 516 mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES); 517 Log.i(this, "start vibration."); 518 } 519 // else stopped already: this isn't started unless a reservation was made. 520 } 521 } 522 getVibrationEffectForRingtone(@onNull Ringtone ringtone)523 private VibrationEffect getVibrationEffectForRingtone(@NonNull Ringtone ringtone) { 524 Uri ringtoneUri = ringtone.getUri(); 525 if (ringtoneUri == null) { 526 return mDefaultVibrationEffect; 527 } 528 try { 529 VibrationEffect effect = mVibrationEffectProxy.get(ringtoneUri, mContext); 530 if (effect == null) { 531 Log.i(this, "did not find vibration effect, falling back to default vibration"); 532 return mDefaultVibrationEffect; 533 } 534 return effect; 535 } catch (IllegalArgumentException iae) { 536 // Deep in the bowels of the VibrationEffect class it is possible for an 537 // IllegalArgumentException to be thrown if there is an invalid URI specified in the 538 // device config, or a content provider failure. Rather than crashing the Telecom 539 // process we will just use the default vibration effect. 540 Log.e(this, iae, "getVibrationEffectForRingtone: failed to get vibration effect"); 541 return mDefaultVibrationEffect; 542 } 543 } 544 startCallWaiting(Call call)545 public void startCallWaiting(Call call) { 546 startCallWaiting(call, null); 547 } 548 startCallWaiting(Call call, String reason)549 public void startCallWaiting(Call call, String reason) { 550 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 551 return; 552 } 553 554 if (mInCallController.doesConnectedDialerSupportRinging( 555 call.getAssociatedUser())) { 556 Log.addEvent(call, LogUtils.Events.SKIP_RINGING, "Dialer handles"); 557 return; 558 } 559 560 if (call.isSelfManaged()) { 561 Log.addEvent(call, LogUtils.Events.SKIP_RINGING, "Self-managed"); 562 return; 563 } 564 565 Log.v(this, "Playing call-waiting tone."); 566 567 stopRinging(); 568 569 if (mCallWaitingPlayer == null) { 570 Log.addEvent(call, LogUtils.Events.START_CALL_WAITING_TONE, reason); 571 mCallWaitingCall = call; 572 mCallWaitingPlayer = 573 mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING); 574 mCallWaitingPlayer.startTone(); 575 } 576 } 577 stopRinging()578 public void stopRinging() { 579 final Call foregroundCall = mRingingCall != null ? mRingingCall : mVibratingCall; 580 if (mAccessibilityManagerAdapter != null) { 581 Log.addEvent(foregroundCall, LogUtils.Events.FLASH_NOTIFICATION_STOP); 582 getHandler().post(() -> 583 mAccessibilityManagerAdapter.stopFlashNotificationSequence(mContext)); 584 } 585 586 synchronized (mLock) { 587 if (mRingingCall != null) { 588 Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER); 589 mRingingCall = null; 590 } 591 592 mRingtonePlayer.stop(); 593 594 if (mIsVibrating) { 595 Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR); 596 mVibrator.cancel(); 597 mIsVibrating = false; 598 } 599 mVibratingCall = null; // Prevents vibrations from starting via AsyncRingtonePlayer. 600 } 601 } 602 stopCallWaiting()603 public void stopCallWaiting() { 604 Log.v(this, "stop call waiting."); 605 if (mCallWaitingPlayer != null) { 606 if (mCallWaitingCall != null) { 607 Log.addEvent(mCallWaitingCall, LogUtils.Events.STOP_CALL_WAITING_TONE); 608 mCallWaitingCall = null; 609 } 610 611 mCallWaitingPlayer.stopTone(); 612 mCallWaitingPlayer = null; 613 } 614 } 615 isRinging()616 public boolean isRinging() { 617 return mRingtonePlayer.isPlaying(); 618 } 619 620 /** 621 * shouldRingForContact checks if the caller matches one of the Do Not Disturb bypass 622 * settings (ex. A contact or repeat caller might be able to bypass DND settings). If 623 * matchesCallFilter returns true, this means the caller can bypass the Do Not Disturb settings 624 * and interrupt the user; otherwise call is suppressed. 625 */ shouldRingForContact(Call call)626 public boolean shouldRingForContact(Call call) { 627 // avoid re-computing manager.matcherCallFilter(Bundle) 628 if (call.wasDndCheckComputedForCall()) { 629 Log.i(this, "shouldRingForContact: returning computation from DndCallFilter."); 630 return !call.isCallSuppressedByDoNotDisturb(); 631 } 632 final Uri contactUri = call.getHandle(); 633 final Bundle peopleExtras = new Bundle(); 634 if (contactUri != null) { 635 ArrayList<Person> personList = new ArrayList<>(); 636 personList.add(new Person.Builder().setUri(contactUri.toString()).build()); 637 peopleExtras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, personList); 638 } 639 return mNotificationManager.matchesCallFilter(peopleExtras); 640 } 641 hasExternalRinger(Call foregroundCall)642 private boolean hasExternalRinger(Call foregroundCall) { 643 Bundle intentExtras = foregroundCall.getIntentExtras(); 644 if (intentExtras != null) { 645 return intentExtras.getBoolean(TelecomManager.EXTRA_CALL_HAS_IN_BAND_RINGTONE, false); 646 } else { 647 return false; 648 } 649 } 650 isVibratorEnabled(Context context, boolean shouldRingForContact)651 private boolean isVibratorEnabled(Context context, boolean shouldRingForContact) { 652 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 653 // Use AudioManager#getRingerMode for more accurate result, instead of 654 // AudioManager#getRingerModeInternal which only useful for volume controllers 655 boolean zenModeOn = mNotificationManager != null 656 && mNotificationManager.getZenMode() != ZEN_MODE_OFF; 657 return mVibrator.hasVibrator() 658 && mSystemSettingsUtil.isRingVibrationEnabled(context) 659 && (audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT 660 || (zenModeOn && shouldRingForContact)); 661 } 662 getRingerAttributes(Call call, boolean isHfpDeviceAttached)663 private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) { 664 mAudioManager = mContext.getSystemService(AudioManager.class); 665 RingerAttributes.Builder builder = new RingerAttributes.Builder(); 666 667 LogUtils.EventTimer timer = new EventTimer(); 668 669 boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; 670 timer.record("isVolumeOverZero"); 671 boolean shouldRingForContact = shouldRingForContact(call); 672 timer.record("shouldRingForContact"); 673 boolean isSelfManaged = call.isSelfManaged(); 674 timer.record("isSelfManaged"); 675 boolean isSilentRingingRequested = call.isSilentRingingRequested(); 676 timer.record("isSilentRingRequested"); 677 678 boolean isRingerAudible = isVolumeOverZero && shouldRingForContact; 679 timer.record("isRingerAudible"); 680 String inaudibleReason = ""; 681 if (!isRingerAudible) { 682 inaudibleReason = String.format("isVolumeOverZero=%s, shouldRingForContact=%s", 683 isVolumeOverZero, shouldRingForContact); 684 } 685 686 boolean hasExternalRinger = hasExternalRinger(call); 687 timer.record("hasExternalRinger"); 688 // Don't do call waiting operations or vibration unless these are false. 689 boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); 690 timer.record("isTheaterModeOn"); 691 boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging( 692 call.getAssociatedUser()); 693 timer.record("letDialerHandleRinging"); 694 boolean isWorkProfileInQuietMode = 695 isProfileInQuietMode(call.getAssociatedUser()); 696 timer.record("isWorkProfileInQuietMode"); 697 698 Log.i(this, "startRinging timings: " + timer); 699 boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || 700 hasExternalRinger || isSilentRingingRequested || isWorkProfileInQuietMode; 701 702 if (endEarly) { 703 Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + 704 "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s, " + 705 "isWorkProfileInQuietMode=%s", 706 isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, 707 isSilentRingingRequested, isWorkProfileInQuietMode); 708 } 709 710 // Acquire audio focus under any of the following conditions: 711 // 1. Should ring for contact and there's an HFP device attached 712 // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone 713 // present. (This check is deferred until ringer knows the ringtone) 714 // 3. The call is self-managed. 715 boolean shouldAcquireAudioFocus = !isWorkProfileInQuietMode && 716 ((isHfpDeviceAttached && shouldRingForContact) || isSelfManaged); 717 718 // Set missed reason according to attributes 719 if (!isVolumeOverZero) { 720 call.setUserMissed(USER_MISSED_LOW_RING_VOLUME); 721 } 722 if (!shouldRingForContact) { 723 call.setUserMissed(USER_MISSED_DND_MODE); 724 } 725 726 mAttributesLatch.countDown(); 727 return builder.setEndEarly(endEarly) 728 .setLetDialerHandleRinging(letDialerHandleRinging) 729 .setAcquireAudioFocus(shouldAcquireAudioFocus) 730 .setRingerAudible(isRingerAudible) 731 .setInaudibleReason(inaudibleReason) 732 .setShouldRingForContact(shouldRingForContact) 733 .setSilentRingingRequested(isSilentRingingRequested) 734 .setWorkProfileQuietMode(isWorkProfileInQuietMode) 735 .build(); 736 } 737 isProfileInQuietMode(UserHandle user)738 private boolean isProfileInQuietMode(UserHandle user) { 739 UserManager um = mContext.getSystemService(UserManager.class); 740 return um.isManagedProfile(user.getIdentifier()) && um.isQuietModeEnabled(user); 741 } 742 getHandler()743 private Handler getHandler() { 744 if (mHandler == null) { 745 HandlerThread handlerThread = new HandlerThread("Ringer"); 746 handlerThread.start(); 747 mHandler = handlerThread.getThreadHandler(); 748 } 749 return mHandler; 750 } 751 752 @VisibleForTesting waitForAttributesCompletion()753 public boolean waitForAttributesCompletion() throws InterruptedException { 754 if (mAttributesLatch != null) { 755 return mAttributesLatch.await(RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); 756 } else { 757 return false; 758 } 759 } 760 } 761