1 /* 2 * Copyright (C) 2022 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.server.telecom.callsequencing.voip; 18 19 import static android.telecom.TelecomManager.TELECOM_TRANSACTION_SUCCESS; 20 import static android.telecom.CallException.CODE_OPERATION_TIMED_OUT; 21 22 import android.os.Bundle; 23 import android.os.RemoteException; 24 import android.os.ResultReceiver; 25 import android.telecom.CallAttributes; 26 import android.telecom.DisconnectCause; 27 import android.util.Log; 28 29 import com.android.internal.telecom.ICallEventCallback; 30 import com.android.server.telecom.TelecomSystem; 31 import com.android.server.telecom.TransactionalServiceWrapper; 32 import com.android.server.telecom.callsequencing.CallTransaction; 33 import com.android.server.telecom.callsequencing.CallTransactionResult; 34 35 import java.util.concurrent.CompletableFuture; 36 import java.util.concurrent.CompletionStage; 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.TimeUnit; 39 40 /** 41 * SRP: using the ICallEventCallback binder, reach out to the client for the pending call event and 42 * get an acknowledgement that the call event can be completed. 43 */ 44 public class CallEventCallbackAckTransaction extends CallTransaction { 45 private static final String TAG = CallEventCallbackAckTransaction.class.getSimpleName(); 46 private final ICallEventCallback mICallEventCallback; 47 private final String mAction; 48 private final String mCallId; 49 // optional values 50 private int mVideoState = CallAttributes.AUDIO_CALL; 51 private DisconnectCause mDisconnectCause = null; 52 53 private final CallTransactionResult TRANSACTION_FAILED = new CallTransactionResult( 54 CODE_OPERATION_TIMED_OUT, "failed to complete the operation before timeout"); 55 56 private static class AckResultReceiver extends ResultReceiver { 57 CompletableFuture<Boolean> mCompletableFuture; 58 AckResultReceiver(CompletableFuture<Boolean> future)59 public AckResultReceiver(CompletableFuture<Boolean> future) { 60 super(null); 61 mCompletableFuture = future; 62 } 63 64 @Override onReceiveResult(int resultCode, Bundle resultData)65 protected void onReceiveResult(int resultCode, Bundle resultData) { 66 if (resultCode == TELECOM_TRANSACTION_SUCCESS) { 67 mCompletableFuture.complete(true); 68 } 69 } 70 } 71 CallEventCallbackAckTransaction(ICallEventCallback service, String action, String callId, TelecomSystem.SyncRoot lock)72 public CallEventCallbackAckTransaction(ICallEventCallback service, String action, 73 String callId, TelecomSystem.SyncRoot lock) { 74 super(lock); 75 mICallEventCallback = service; 76 mAction = action; 77 mCallId = callId; 78 } 79 80 CallEventCallbackAckTransaction(ICallEventCallback service, String action, String callId, int videoState, TelecomSystem.SyncRoot lock)81 public CallEventCallbackAckTransaction(ICallEventCallback service, String action, String callId, 82 int videoState, TelecomSystem.SyncRoot lock) { 83 super(lock); 84 mICallEventCallback = service; 85 mAction = action; 86 mCallId = callId; 87 mVideoState = videoState; 88 } 89 CallEventCallbackAckTransaction(ICallEventCallback service, String action, String callId, DisconnectCause cause, TelecomSystem.SyncRoot lock)90 public CallEventCallbackAckTransaction(ICallEventCallback service, String action, String callId, 91 DisconnectCause cause, TelecomSystem.SyncRoot lock) { 92 super(lock); 93 mICallEventCallback = service; 94 mAction = action; 95 mCallId = callId; 96 mDisconnectCause = cause; 97 } 98 99 100 @Override processTransaction(Void v)101 public CompletionStage<CallTransactionResult> processTransaction(Void v) { 102 Log.d(TAG, "processTransaction: action [" + mAction + "]"); 103 CompletableFuture<Boolean> future = new CompletableFuture<Boolean>() 104 .completeOnTimeout(false, mTransactionTimeoutMs, TimeUnit.MILLISECONDS); 105 ResultReceiver receiver = new AckResultReceiver(future); 106 107 try { 108 switch (mAction) { 109 case TransactionalServiceWrapper.ON_SET_INACTIVE: 110 mICallEventCallback.onSetInactive(mCallId, receiver); 111 break; 112 case TransactionalServiceWrapper.ON_DISCONNECT: 113 mICallEventCallback.onDisconnect(mCallId, mDisconnectCause, receiver); 114 break; 115 case TransactionalServiceWrapper.ON_SET_ACTIVE: 116 mICallEventCallback.onSetActive(mCallId, receiver); 117 break; 118 case TransactionalServiceWrapper.ON_ANSWER: 119 mICallEventCallback.onAnswer(mCallId, mVideoState, receiver); 120 break; 121 case TransactionalServiceWrapper.ON_STREAMING_STARTED: 122 mICallEventCallback.onCallStreamingStarted(mCallId, receiver); 123 break; 124 } 125 } catch (RemoteException remoteException) { 126 return CompletableFuture.completedFuture(TRANSACTION_FAILED); 127 } 128 129 return future.thenCompose((success) -> { 130 if (!success) { 131 // client send onError and failed to complete transaction 132 Log.i(TAG, String.format("CallEventCallbackAckTransaction:" 133 + " client failed to complete the [%s] transaction", mAction)); 134 return CompletableFuture.completedFuture(TRANSACTION_FAILED); 135 } else { 136 // success 137 return CompletableFuture.completedFuture( 138 new CallTransactionResult(CallTransactionResult.RESULT_SUCCEED, 139 "success")); 140 } 141 }); 142 } 143 } 144