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