1 /*
2  * Copyright (C) 2017 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.cts.verifier.telecom;
18 
19 import android.content.Context;
20 import android.media.AudioAttributes;
21 import android.media.AudioManager;
22 import android.media.MediaPlayer;
23 import android.telecom.CallAudioState;
24 import android.telecom.Connection;
25 import android.telecom.DisconnectCause;
26 import android.telecom.VideoProfile;
27 import android.util.ArraySet;
28 
29 import com.android.cts.verifier.R;
30 
31 import java.util.Set;
32 import java.util.concurrent.CountDownLatch;
33 import java.util.concurrent.TimeUnit;
34 
35 /**
36  * An implementation of the {@link android.telecom.Connection} class used by the
37  * {@link CtsConnectionService}.
38  */
39 public class CtsConnection extends Connection {
40     /**
41      * Listener used to inform the CtsVerifier app of changes to a connection.
42      */
43     public static abstract class Listener {
onDestroyed(CtsConnection connection)44         void onDestroyed(CtsConnection connection) { };
onDisconnect(CtsConnection connection)45         void onDisconnect(CtsConnection connection) { };
onHold(CtsConnection connection)46         void onHold(CtsConnection connection) { };
onUnhold(CtsConnection connection)47         void onUnhold(CtsConnection connection) { };
onAnswer(CtsConnection connection, int videoState)48         void onAnswer(CtsConnection connection, int videoState) { };
onReject(CtsConnection connection)49         void onReject(CtsConnection connection) { };
onShowIncomingCallUi(CtsConnection connection)50         void onShowIncomingCallUi(CtsConnection connection) { };
51     }
52 
53     public static final String EXTRA_PLAY_CS_AUDIO =
54             "com.android.cts.verifier.telecom.PLAY_CS_AUDIO";
55 
56     private final boolean mIsIncomingCall;
57     private final Set<Listener> mListener = new ArraySet<>();
58     private final MediaPlayer mMediaPlayer;
59     private final Context mContext;
60     private CountDownLatch mWaitForCallAudioStateChanged = new CountDownLatch(1);
61 
CtsConnection(Context context, boolean isIncomingCall, Listener listener, boolean hasAudio)62     public CtsConnection(Context context, boolean isIncomingCall,
63             Listener listener, boolean hasAudio) {
64         mContext = context;
65         mIsIncomingCall = isIncomingCall;
66         mListener.add(listener);
67         if (hasAudio) {
68             mMediaPlayer = createMediaPlayer();
69         } else {
70             mMediaPlayer = null;
71         }
72     }
73 
isIncomingCall()74     public boolean isIncomingCall() {
75         return mIsIncomingCall;
76     }
77 
addListener(Listener listener)78     public void addListener(Listener listener) {
79         mListener.add(listener);
80     }
81 
82     @Override
onDisconnect()83     public void onDisconnect() {
84         setDisconnectedAndDestroy(new DisconnectCause(DisconnectCause.LOCAL));
85 
86         if (mListener != null) {
87             mListener.forEach(l -> l.onDisconnect(CtsConnection.this));
88         }
89     }
90 
91 
92     @Override
onHold()93     public void onHold() {
94         setOnHold();
95 
96         if (mListener != null) {
97             mListener.forEach(l -> l.onHold(CtsConnection.this));
98         }
99     }
100 
101     @Override
onUnhold()102     public void onUnhold() {
103         setActive();
104 
105         if (mListener != null) {
106             mListener.forEach(l -> l.onUnhold(CtsConnection.this));
107         }
108     }
109 
110     @Override
onAnswer(int videoState)111     public void onAnswer(int videoState) {
112         setVideoState(videoState);
113         setActive();
114 
115         if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
116             mMediaPlayer.start();
117         }
118 
119         if (mListener != null) {
120             mListener.forEach(l -> l.onAnswer(CtsConnection.this, videoState));
121         }
122     }
123 
124     @Override
onAnswer()125     public void onAnswer() {
126         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
127     }
128 
129     @Override
onReject()130     public void onReject() {
131         setDisconnectedAndDestroy(new DisconnectCause(DisconnectCause.REJECTED));
132 
133         if (mListener != null) {
134             mListener.forEach(l -> l.onReject(CtsConnection.this));
135         }
136     }
137 
138     @Override
onShowIncomingCallUi()139     public void onShowIncomingCallUi() {
140         if (mListener != null) {
141             mListener.forEach(l -> l.onShowIncomingCallUi(CtsConnection.this));
142         }
143     }
144 
onCallAudioStateChanged(CallAudioState state)145     public void onCallAudioStateChanged(CallAudioState state) {
146         mWaitForCallAudioStateChanged.countDown();
147         mWaitForCallAudioStateChanged = new CountDownLatch(1);
148 
149     }
150 
waitForAudioStateChanged()151     public void waitForAudioStateChanged() {
152         try {
153             mWaitForCallAudioStateChanged.await(CtsConnectionService.TIMEOUT_MILLIS,
154                     TimeUnit.MILLISECONDS);
155         } catch (InterruptedException e) {
156         }
157     }
158 
setDisconnectedAndDestroy(DisconnectCause cause)159     private void setDisconnectedAndDestroy(DisconnectCause cause) {
160         setDisconnected(cause);
161         destroy();
162 
163         if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
164             mMediaPlayer.stop();
165         }
166 
167         if (mListener != null) {
168             mListener.forEach(l -> l.onDestroyed(CtsConnection.this));
169         }
170     }
171 
createMediaPlayer()172     private MediaPlayer createMediaPlayer() {
173         AudioAttributes voiceCallAttributes = new AudioAttributes.Builder()
174                 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
175                 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
176                 .build();
177         int audioSessionId = ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
178                 .generateAudioSessionId();
179         // Prepare the media player to play a tone when there is a call.
180         MediaPlayer mediaPlayer = MediaPlayer.create(mContext, R.raw.telecom_test_call_audio,
181                 voiceCallAttributes, audioSessionId);
182         mediaPlayer.setLooping(true);
183         return mediaPlayer;
184     }
185 }
186