Home | History | Annotate | Download | only in telecom
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.server.telecom;
     18 
     19 import android.app.Notification;
     20 import android.app.NotificationManager;
     21 import android.content.Context;
     22 import android.media.AudioAttributes;
     23 import android.media.AudioManager;
     24 import android.net.Uri;
     25 import android.os.Bundle;
     26 import android.os.Vibrator;
     27 
     28 import com.android.internal.annotations.VisibleForTesting;
     29 
     30 /**
     31  * Controls the ringtone player.
     32  */
     33 @VisibleForTesting
     34 public class Ringer {
     35     private static final long[] VIBRATION_PATTERN = new long[] {
     36         0, // No delay before starting
     37         1000, // How long to vibrate
     38         1000, // How long to wait before vibrating again
     39     };
     40 
     41     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
     42             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
     43             .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
     44             .build();
     45 
     46     /** Indicate that we want the pattern to repeat at the step which turns on vibration. */
     47     private static final int VIBRATION_PATTERN_REPEAT = 1;
     48 
     49     /**
     50      * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming
     51      * calls and explicit ordering is useful for maintaining the proper state of the ringer.
     52      */
     53 
     54     private final SystemSettingsUtil mSystemSettingsUtil;
     55     private final InCallTonePlayer.Factory mPlayerFactory;
     56     private final AsyncRingtonePlayer mRingtonePlayer;
     57     private final Context mContext;
     58     private final Vibrator mVibrator;
     59     private final InCallController mInCallController;
     60 
     61     private InCallTonePlayer mCallWaitingPlayer;
     62     private RingtoneFactory mRingtoneFactory;
     63 
     64     /**
     65      * Call objects that are ringing or call-waiting. These are used only for logging purposes.
     66      */
     67     private Call mRingingCall;
     68     private Call mCallWaitingCall;
     69 
     70     /**
     71      * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls.
     72      */
     73     private boolean mIsVibrating = false;
     74 
     75     /** Initializes the Ringer. */
     76     @VisibleForTesting
     77     public Ringer(
     78             InCallTonePlayer.Factory playerFactory,
     79             Context context,
     80             SystemSettingsUtil systemSettingsUtil,
     81             AsyncRingtonePlayer asyncRingtonePlayer,
     82             RingtoneFactory ringtoneFactory,
     83             Vibrator vibrator,
     84             InCallController inCallController) {
     85 
     86         mSystemSettingsUtil = systemSettingsUtil;
     87         mPlayerFactory = playerFactory;
     88         mContext = context;
     89         // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this
     90         // vibrator object will be isolated from others.
     91         mVibrator = vibrator;
     92         mRingtonePlayer = asyncRingtonePlayer;
     93         mRingtoneFactory = ringtoneFactory;
     94         mInCallController = inCallController;
     95     }
     96 
     97     public void startRinging(Call foregroundCall) {
     98         if (mSystemSettingsUtil.isTheaterModeOn(mContext)) {
     99             return;
    100         }
    101 
    102         if (foregroundCall == null) {
    103             Log.wtf(this, "startRinging called with null foreground call.");
    104             return;
    105         }
    106 
    107         if (mInCallController.doesConnectedDialerSupportRinging()) {
    108             Log.event(foregroundCall, Log.Events.SKIP_RINGING);
    109             return;
    110         }
    111 
    112         stopCallWaiting();
    113 
    114         if (!shouldRingForContact(foregroundCall.getContactUri())) {
    115             return;
    116         }
    117 
    118         AudioManager audioManager =
    119                 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
    120         if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
    121             mRingingCall = foregroundCall;
    122             Log.event(foregroundCall, Log.Events.START_RINGER);
    123             // Because we wait until a contact info query to complete before processing a
    124             // call (for the purposes of direct-to-voicemail), the information about custom
    125             // ringtones should be available by the time this code executes. We can safely
    126             // request the custom ringtone from the call and expect it to be current.
    127             mRingtonePlayer.play(mRingtoneFactory, foregroundCall);
    128         } else {
    129             Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0");
    130         }
    131 
    132         if (shouldVibrate(mContext) && !mIsVibrating) {
    133             mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT,
    134                     VIBRATION_ATTRIBUTES);
    135             mIsVibrating = true;
    136         }
    137     }
    138 
    139     public void startCallWaiting(Call call) {
    140         if (mSystemSettingsUtil.isTheaterModeOn(mContext)) {
    141             return;
    142         }
    143 
    144         if (mInCallController.doesConnectedDialerSupportRinging()) {
    145             Log.event(call, Log.Events.SKIP_RINGING);
    146             return;
    147         }
    148 
    149         Log.v(this, "Playing call-waiting tone.");
    150 
    151         stopRinging();
    152 
    153         if (mCallWaitingPlayer == null) {
    154             Log.event(call, Log.Events.START_CALL_WAITING_TONE);
    155             mCallWaitingCall = call;
    156             mCallWaitingPlayer =
    157                     mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
    158             mCallWaitingPlayer.startTone();
    159         }
    160     }
    161 
    162     public void stopRinging() {
    163         if (mRingingCall != null) {
    164             Log.event(mRingingCall, Log.Events.STOP_RINGER);
    165             mRingingCall = null;
    166         }
    167 
    168         mRingtonePlayer.stop();
    169 
    170         if (mIsVibrating) {
    171             mVibrator.cancel();
    172             mIsVibrating = false;
    173         }
    174     }
    175 
    176     public void stopCallWaiting() {
    177         Log.v(this, "stop call waiting.");
    178         if (mCallWaitingPlayer != null) {
    179             if (mCallWaitingCall != null) {
    180                 Log.event(mCallWaitingCall, Log.Events.STOP_CALL_WAITING_TONE);
    181                 mCallWaitingCall = null;
    182             }
    183 
    184             mCallWaitingPlayer.stopTone();
    185             mCallWaitingPlayer = null;
    186         }
    187     }
    188 
    189     private boolean shouldRingForContact(Uri contactUri) {
    190         final NotificationManager manager =
    191                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    192         final Bundle extras = new Bundle();
    193         if (contactUri != null) {
    194             extras.putStringArray(Notification.EXTRA_PEOPLE, new String[] {contactUri.toString()});
    195         }
    196         return manager.matchesCallFilter(extras);
    197     }
    198 
    199     private boolean shouldVibrate(Context context) {
    200         AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    201         int ringerMode = audioManager.getRingerModeInternal();
    202         if (getVibrateWhenRinging(context)) {
    203             return ringerMode != AudioManager.RINGER_MODE_SILENT;
    204         } else {
    205             return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
    206         }
    207     }
    208 
    209     private boolean getVibrateWhenRinging(Context context) {
    210         if (!mVibrator.hasVibrator()) {
    211             return false;
    212         }
    213         return mSystemSettingsUtil.canVibrateWhenRinging(context);
    214     }
    215 }
    216