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