• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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