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