1 /* 2 * Copyright (C) 2024 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 android.media.projection.cts.helper; 18 19 import android.app.Service; 20 import android.content.ComponentName; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.os.IBinder; 25 import android.os.OutcomeReceiver; 26 import android.telecom.CallAttributes; 27 import android.telecom.CallControl; 28 import android.telecom.CallControlCallback; 29 import android.telecom.CallEndpoint; 30 import android.telecom.CallEventCallback; 31 import android.telecom.CallException; 32 import android.telecom.ConnectionService; 33 import android.telecom.DisconnectCause; 34 import android.telecom.PhoneAccount; 35 import android.telecom.PhoneAccountHandle; 36 import android.telecom.TelecomManager; 37 38 import java.util.List; 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.TimeUnit; 41 import java.util.function.Consumer; 42 43 /** Activity used for testing (phone) call related features */ 44 public class CallHelperService extends Service { 45 46 private static final String CALL_HELPER_START_CALL = "start_call"; 47 static final String CALL_HELPER_STOP_CALL = "stop_call"; 48 49 private int mTimeoutMs; 50 private TelecomManager mTelecomManager; 51 private PhoneAccountHandle mPhoneAccountHandle; 52 private PhoneAccount mPhoneAccount; 53 private CallControl mCallControl; 54 private OutcomeReceiver<CallControl, CallException> mOutcomeReceiver; 55 56 @Override onCreate()57 public void onCreate() { 58 super.onCreate(); 59 mTimeoutMs = 1000; 60 mTelecomManager = getSystemService(TelecomManager.class); 61 } 62 63 @Override onBind(Intent intent)64 public IBinder onBind(Intent intent) { 65 return null; 66 } 67 68 @Override onStartCommand(Intent intent, int flags, int startId)69 public int onStartCommand(Intent intent, int flags, int startId) { 70 String action = intent.getAction(); 71 72 if (CALL_HELPER_START_CALL.equals(action)) { 73 try { 74 startPhoneCall(); 75 } catch (InterruptedException e) { 76 throw new RuntimeException(e); 77 } 78 } 79 if (CALL_HELPER_STOP_CALL.equals(action)) { 80 endPhoneCall(); 81 stopSelf(); 82 } 83 84 return super.onStartCommand(intent, flags, startId); 85 } 86 87 @Override onDestroy()88 public void onDestroy() { 89 endPhoneCall(); 90 super.onDestroy(); 91 } 92 startPhoneCall()93 private void startPhoneCall() throws InterruptedException { 94 mPhoneAccountHandle = 95 new PhoneAccountHandle( 96 new ComponentName(this, PhoneConnectionService.class), 97 "test_phone_account_handle"); 98 mPhoneAccount = 99 new PhoneAccount.Builder(mPhoneAccountHandle, "test_phone_account") 100 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) 101 .build(); 102 mTelecomManager.registerPhoneAccount(mPhoneAccount); 103 CallAttributes attributes = 104 new CallAttributes.Builder( 105 mPhoneAccountHandle, 106 CallAttributes.DIRECTION_INCOMING, 107 "a call!", 108 Uri.parse("tel:555-5555")) 109 .build(); 110 111 CountDownLatch latch = new CountDownLatch(1); 112 mOutcomeReceiver = 113 result -> { 114 mCallControl = result; 115 latch.countDown(); 116 }; 117 mTelecomManager.addCall( 118 attributes, 119 getMainExecutor(), 120 mOutcomeReceiver, 121 new HelperCallControlCallback(), 122 new HelperCallEventCallback()); 123 124 boolean mCallAdded = latch.await(mTimeoutMs, TimeUnit.MILLISECONDS); 125 if (mCallAdded) { 126 mCallControl.answer(CallAttributes.AUDIO_CALL, getMainExecutor(), result -> {}); 127 } 128 } 129 endPhoneCall()130 private void endPhoneCall() { 131 if (mCallControl != null) { 132 mCallControl.disconnect( 133 new DisconnectCause(DisconnectCause.LOCAL), getMainExecutor(), result -> {}); 134 } 135 if (mPhoneAccountHandle != null) { 136 mTelecomManager.unregisterPhoneAccount(mPhoneAccountHandle); 137 mPhoneAccountHandle = null; 138 mPhoneAccount = null; 139 } 140 } 141 142 private static final class HelperCallEventCallback implements CallEventCallback { 143 @Override onCallEndpointChanged(CallEndpoint newCallEndpoint)144 public void onCallEndpointChanged(CallEndpoint newCallEndpoint) {} 145 146 @Override onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints)147 public void onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints) {} 148 149 @Override onMuteStateChanged(boolean isMuted)150 public void onMuteStateChanged(boolean isMuted) {} 151 152 @Override onCallStreamingFailed(int reason)153 public void onCallStreamingFailed(int reason) {} 154 155 @Override onEvent(String event, Bundle extras)156 public void onEvent(String event, Bundle extras) {} 157 } 158 159 private static final class HelperCallControlCallback implements CallControlCallback { 160 @Override onSetActive(Consumer<Boolean> wasCompleted)161 public void onSetActive(Consumer<Boolean> wasCompleted) {} 162 163 @Override onSetInactive(Consumer<Boolean> wasCompleted)164 public void onSetInactive(Consumer<Boolean> wasCompleted) {} 165 166 @Override onAnswer(int videoState, Consumer<Boolean> wasCompleted)167 public void onAnswer(int videoState, Consumer<Boolean> wasCompleted) {} 168 169 @Override onDisconnect(DisconnectCause disconnectCause, Consumer<Boolean> wasCompleted)170 public void onDisconnect(DisconnectCause disconnectCause, Consumer<Boolean> wasCompleted) {} 171 172 @Override onCallStreamingStarted(Consumer<Boolean> wasCompleted)173 public void onCallStreamingStarted(Consumer<Boolean> wasCompleted) {} 174 } 175 176 private static final class PhoneConnectionService extends ConnectionService {} 177 } 178