RingerTest.java revision e091ab90e37845cf4771051a6d2ce0ebadee4fe7
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 17package com.android.server.telecom; 18 19import android.app.Notification; 20import android.app.NotificationManager; 21import android.content.Context; 22import android.media.AudioAttributes; 23import android.media.AudioManager; 24import android.net.Uri; 25import android.os.Bundle; 26import android.os.Vibrator; 27 28import com.android.internal.annotations.VisibleForTesting; 29 30/** 31 * Controls the ringtone player. 32 */ 33@VisibleForTesting 34public final 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 60 private InCallTonePlayer mCallWaitingPlayer; 61 private RingtoneFactory mRingtoneFactory; 62 63 /** 64 * Call objects that are ringing or call-waiting. These are used only for logging purposes. 65 */ 66 private Call mRingingCall; 67 private Call mCallWaitingCall; 68 69 /** 70 * Used to track the status of {@link #mVibrator} in the case of simultaneous incoming calls. 71 */ 72 private boolean mIsVibrating = false; 73 74 /** Initializes the Ringer. */ 75 @VisibleForTesting 76 public Ringer( 77 InCallTonePlayer.Factory playerFactory, 78 Context context, 79 SystemSettingsUtil systemSettingsUtil, 80 AsyncRingtonePlayer asyncRingtonePlayer, 81 RingtoneFactory ringtoneFactory, 82 Vibrator vibrator) { 83 84 mSystemSettingsUtil = systemSettingsUtil; 85 mPlayerFactory = playerFactory; 86 mContext = context; 87 // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this 88 // vibrator object will be isolated from others. 89 mVibrator = vibrator; 90 mRingtonePlayer = asyncRingtonePlayer; 91 mRingtoneFactory = ringtoneFactory; 92 } 93 94 public void startRinging(Call foregroundCall) { 95 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 96 return; 97 } 98 99 stopCallWaiting(); 100 101 if (!shouldRingForContact(foregroundCall.getContactUri())) { 102 return; 103 } 104 105 AudioManager audioManager = 106 (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 107 if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) { 108 mRingingCall = foregroundCall; 109 Log.event(foregroundCall, Log.Events.START_RINGER); 110 // Because we wait until a contact info query to complete before processing a 111 // call (for the purposes of direct-to-voicemail), the information about custom 112 // ringtones should be available by the time this code executes. We can safely 113 // request the custom ringtone from the call and expect it to be current. 114 mRingtonePlayer.play( 115 mRingtoneFactory.getRingtone(foregroundCall.getRingtone())); 116 } else { 117 Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0"); 118 } 119 120 if (shouldVibrate(mContext) && !mIsVibrating) { 121 mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT, 122 VIBRATION_ATTRIBUTES); 123 mIsVibrating = true; 124 } 125 } 126 127 public void startCallWaiting(Call call) { 128 if (mSystemSettingsUtil.isTheaterModeOn(mContext)) { 129 return; 130 } 131 132 Log.v(this, "Playing call-waiting tone."); 133 134 stopRinging(); 135 136 if (mCallWaitingPlayer == null) { 137 Log.event(call, Log.Events.START_CALL_WAITING_TONE); 138 mCallWaitingCall = call; 139 mCallWaitingPlayer = 140 mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING); 141 mCallWaitingPlayer.startTone(); 142 } 143 } 144 145 public void stopRinging() { 146 if (mRingingCall != null) { 147 Log.event(mRingingCall, Log.Events.STOP_RINGER); 148 mRingingCall = null; 149 } 150 151 mRingtonePlayer.stop(); 152 153 if (mIsVibrating) { 154 mVibrator.cancel(); 155 mIsVibrating = false; 156 } 157 } 158 159 public void stopCallWaiting() { 160 Log.v(this, "stop call waiting."); 161 if (mCallWaitingPlayer != null) { 162 if (mCallWaitingCall != null) { 163 Log.event(mCallWaitingCall, Log.Events.STOP_CALL_WAITING_TONE); 164 mCallWaitingCall = null; 165 } 166 167 mCallWaitingPlayer.stopTone(); 168 mCallWaitingPlayer = null; 169 } 170 } 171 172 private boolean shouldRingForContact(Uri contactUri) { 173 final NotificationManager manager = 174 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 175 final Bundle extras = new Bundle(); 176 if (contactUri != null) { 177 extras.putStringArray(Notification.EXTRA_PEOPLE, new String[] {contactUri.toString()}); 178 } 179 return manager.matchesCallFilter(extras); 180 } 181 182 private boolean shouldVibrate(Context context) { 183 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 184 int ringerMode = audioManager.getRingerModeInternal(); 185 if (getVibrateWhenRinging(context)) { 186 return ringerMode != AudioManager.RINGER_MODE_SILENT; 187 } else { 188 return ringerMode == AudioManager.RINGER_MODE_VIBRATE; 189 } 190 } 191 192 private boolean getVibrateWhenRinging(Context context) { 193 if (!mVibrator.hasVibrator()) { 194 return false; 195 } 196 return mSystemSettingsUtil.canVibrateWhenRinging(context); 197 } 198} 199