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