Platform Telecom Transactional APIs
Telecom Transactional APIs are defined as APIs that leverage
android.os.OutcomeReceivers. The receivers are to be completed by
Telecom for CallControl opertaions and the Client for CallEventCallback
operations. Doing so ensures the client and telecom are in sync with
call states. Also, these APIs are more lightweight than the
ConnectionService way of starting a self-managed call.
bug: 249779561
Test: atest android.telecom.cts.TransactionalApisTest
Change-Id: Icb09b2874d599a40afca8b7e960b14ca1bca606d
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index af37ed5..7c86a75a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -18,6 +18,7 @@
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +39,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.OutcomeReceiver;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -49,6 +51,8 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.telecom.ClientTransactionalServiceRepository;
+import com.android.internal.telecom.ClientTransactionalServiceWrapper;
import com.android.internal.telecom.ITelecomService;
import java.lang.annotation.Retention;
@@ -1056,6 +1060,14 @@
private final ITelecomService mTelecomServiceOverride;
+ /** @hide **/
+ private final ClientTransactionalServiceRepository mTransactionalServiceRepository =
+ new ClientTransactionalServiceRepository();
+ /** @hide **/
+ public static final int TELECOM_TRANSACTION_SUCCESS = 0;
+ /** @hide **/
+ public static final String TRANSACTION_CALL_ID_KEY = "TelecomCallId";
+
/**
* @hide
*/
@@ -2640,6 +2652,92 @@
}
/**
+ * Adds a new call with the specified {@link CallAttributes} to the telecom service. This method
+ * can be used to add both incoming and outgoing calls.
+ *
+ * <p>
+ * The difference between this API call and {@link TelecomManager#placeCall(Uri, Bundle)} or
+ * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)} is that this API
+ * will asynchronously provide an update on whether the new call was added successfully via
+ * an {@link OutcomeReceiver}. Additionally, callbacks will run on the executor thread that was
+ * passed in.
+ *
+ * <p>
+ * Note: Only packages that register with
+ * {@link PhoneAccount#CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS}
+ * can utilize this API. {@link PhoneAccount}s that set the capabilities
+ * {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION},
+ * {@link PhoneAccount#CAPABILITY_CALL_PROVIDER},
+ * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}
+ * are not supported and will cause an exception to be thrown.
+ *
+ * <p>
+ * Usage example:
+ * <pre>
+ *
+ * // An app should first define their own construct of a Call that overrides all the
+ * // {@link CallEventCallback}s
+ * private class MyVoipCall implements CallEventCallback {
+ * // override all the {@link CallEventCallback}s
+ * }
+ *
+ * PhoneAccountHandle handle = new PhoneAccountHandle(
+ * new ComponentName("com.example.voip.app",
+ * "com.example.voip.app.NewCallActivity"), "123");
+ *
+ * CallAttributes callAttributes = new CallAttributes.Builder(handle,
+ * CallAttributes.DIRECTION_OUTGOING,
+ * "John Smith", Uri.fromParts("tel", "123", null))
+ * .build();
+ *
+ * telecomManager.addCall(callAttributes, Runnable::run, new OutcomeReceiver() {
+ * public void onResult(CallControl callControl) {
+ * // The call has been added successfully
+ * }
+ * }, new MyVoipCall());
+ * </pre>
+ *
+ * @param callAttributes attributes of the new call (incoming or outgoing, address, etc. )
+ * @param executor thread to run background CallEventCallback updates on
+ * @param pendingControl OutcomeReceiver that receives the result of addCall transaction
+ * @param callEventCallback object that overrides CallEventCallback
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS)
+ @SuppressLint("SamShouldBeLast")
+ public void addCall(@NonNull CallAttributes callAttributes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<CallControl, CallException> pendingControl,
+ @NonNull CallEventCallback callEventCallback) {
+ Objects.requireNonNull(callAttributes);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(pendingControl);
+ Objects.requireNonNull(callEventCallback);
+
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ try {
+ // create or add the new call to a service wrapper w/ the same phoneAccountHandle
+ ClientTransactionalServiceWrapper transactionalServiceWrapper =
+ mTransactionalServiceRepository.addNewCallForTransactionalServiceWrapper(
+ callAttributes.getPhoneAccountHandle());
+
+ // couple all the args passed by the client
+ String newCallId = transactionalServiceWrapper.trackCall(callAttributes, executor,
+ pendingControl, callEventCallback);
+
+ // send args to server to process new call
+ service.addCall(callAttributes, transactionalServiceWrapper.getCallEventCallback(),
+ newCallId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException addCall: " + e);
+ e.rethrowFromSystemServer();
+ }
+ } else {
+ throw new IllegalStateException("Telecom service is not present");
+ }
+ }
+
+ /**
* Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
* @param intent The {@link Intent#ACTION_CALL} intent to handle.
* @param callingPackageProxy The original package that called this before it was trampolined.