1 /* 2 * Copyright (C) 2023 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.telecom.cts.apps; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.telecom.CallAttributes; 22 import android.telecom.CallControl; 23 import android.telecom.CallControlCallback; 24 import android.telecom.DisconnectCause; 25 import android.telecom.PhoneAccountHandle; 26 import android.util.Log; 27 28 import androidx.annotation.NonNull; 29 30 import java.util.function.Consumer; 31 32 public class TransactionalCall { 33 private static final String TAG = TransactionalCall.class.getSimpleName(); 34 private String mId = ""; 35 private Context mContext; 36 private boolean mIsOutgoingCall; 37 private CallResources mCallResources; 38 private final PhoneAccountHandle mPhoneAccountHandle; 39 private CallControl mCallControl; 40 41 // Delegates the completion of call state transition operations to potentially another entity 42 // to control the completion. 43 private Consumer<CallStateTransitionOperation> mOperationConsumer; 44 getCallResources()45 public CallResources getCallResources() { 46 return mCallResources; 47 } 48 isOutgoingCall()49 public boolean isOutgoingCall() { 50 return mIsOutgoingCall; 51 } 52 TransactionalCall(Context context, CallResources callResources)53 public TransactionalCall(Context context, CallResources callResources) { 54 mContext = context; 55 mIsOutgoingCall = callResources.getCallAttributes().getDirection() 56 == CallAttributes.DIRECTION_OUTGOING; 57 mCallResources = callResources; 58 mPhoneAccountHandle = callResources.getCallAttributes().getPhoneAccountHandle(); 59 } 60 getId()61 public String getId() { 62 return mId; 63 } 64 setId(String id)65 public void setId(String id) { 66 mId = id; 67 } 68 getCallControl()69 public CallControl getCallControl() { 70 return mCallControl; 71 } 72 getPhoneAccountHandle()73 public PhoneAccountHandle getPhoneAccountHandle() { 74 return mPhoneAccountHandle; 75 } 76 setCallControl(CallControl callControl)77 public void setCallControl(CallControl callControl) { 78 mCallControl = callControl; 79 } 80 81 /** 82 * Delegate operation completion to the test process so that it can control completion of the 83 * request. 84 */ setOperationConsumer(Consumer<CallStateTransitionOperation> consumer)85 public void setOperationConsumer(Consumer<CallStateTransitionOperation> consumer) { 86 mOperationConsumer = consumer; 87 } 88 setCallControlAndId(CallControl callControl)89 public void setCallControlAndId(CallControl callControl) { 90 mCallControl = callControl; 91 mId = callControl.getCallId().toString(); 92 mCallResources.setCallId(mId); 93 Log.i(TAG, String.format("setCallControlAndId: id=[%s], cc=[%s]", mId, callControl)); 94 } 95 setActive(LatchedOutcomeReceiver outcome, Bundle extras )96 public void setActive(LatchedOutcomeReceiver outcome, Bundle extras ){ 97 if (mIsOutgoingCall) { 98 Log.i(TAG, "transitionCallStateTo: setActive"); 99 mCallControl.setActive(Runnable::run, outcome); 100 } else { 101 Log.i(TAG, "transitionCallStateTo: setAnswer"); 102 int videoState = CallAttributes.AUDIO_CALL; 103 if (CallControlExtras.hasVideoStateExtra(extras)) { 104 CallControlExtras.getVideoStateFromExtras(extras); 105 } 106 mCallControl.answer(videoState, Runnable::run, outcome); 107 mCallResources.updateNotificationToOngoing(mContext); 108 } 109 } 110 setInactive(LatchedOutcomeReceiver outcome)111 public void setInactive(LatchedOutcomeReceiver outcome){ 112 Log.i(TAG, "transitionCallStateTo: setInactive"); 113 mCallControl.setInactive(Runnable::run, outcome); 114 } 115 disconnect(LatchedOutcomeReceiver outcome, Bundle extras )116 public void disconnect(LatchedOutcomeReceiver outcome, Bundle extras ) { 117 Log.i(TAG, "transitionCallStateTo: disconnect"); 118 int disconnectCause = DisconnectCause.LOCAL; 119 if (CallControlExtras.hasDisconnectCauseExtra(extras)) { 120 disconnectCause = CallControlExtras.getDisconnectCauseFromExtras( 121 extras); 122 } 123 mCallControl.disconnect( 124 new DisconnectCause(disconnectCause), 125 Runnable::run, 126 outcome); 127 mCallResources.destroyResources(mContext); 128 } 129 130 public CallControlCallback mHandshakes = new CallControlCallback() { 131 @Override 132 public void onSetActive(@NonNull Consumer<Boolean> wasCompleted) { 133 if (mOperationConsumer != null) { 134 mOperationConsumer.accept(new CallStateTransitionOperation( 135 CallStateTransitionOperation.OPERATION_UNHOLD, System.currentTimeMillis())); 136 } 137 wasCompleted.accept(true); 138 } 139 140 @Override 141 public void onSetInactive(@NonNull Consumer<Boolean> wasCompleted) { 142 Log.i(TAG, "onSetInactive: stopped recording ; callId"+ mId); 143 if (mOperationConsumer != null) { 144 mOperationConsumer.accept(new CallStateTransitionOperation( 145 CallStateTransitionOperation.OPERATION_HOLD, System.currentTimeMillis())); 146 } 147 wasCompleted.accept(true); 148 } 149 150 @Override 151 public void onAnswer(int videoState, @NonNull Consumer<Boolean> wasCompleted) { 152 Log.i(TAG, "onAnswer: started recording; callId" + mId); 153 if (mOperationConsumer != null) { 154 mOperationConsumer.accept(new CallStateTransitionOperation( 155 CallStateTransitionOperation.OPERATION_ANSWER, System.currentTimeMillis())); 156 } 157 mCallResources.updateNotificationToOngoing(mContext); 158 wasCompleted.accept(true); 159 } 160 161 @Override 162 public void onDisconnect(@NonNull DisconnectCause cause, 163 @NonNull Consumer<Boolean> wasCompleted) { 164 if (mOperationConsumer != null) { 165 mOperationConsumer.accept(new CallStateTransitionOperation( 166 CallStateTransitionOperation.OPERATION_DISCONNECT, 167 System.currentTimeMillis())); 168 } 169 mCallResources.destroyResources(mContext); 170 wasCompleted.accept(true); 171 } 172 173 @Override 174 public void onCallStreamingStarted(@NonNull Consumer<Boolean> wasCompleted) { 175 } 176 }; 177 178 public TransactionalCallEvents mEvents = new TransactionalCallEvents(); 179 } 180