Merge "IMS: Explicit Call transfer APIS." am: 9f28d84c96 am: 129308a66f
Change-Id: Ic6e71454ce0399f268f9718da47dcc8f1c1b27fa
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
old mode 100644
new mode 100755
index 9a36d3e..52112b1
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -2306,6 +2306,45 @@
}
/**
+ * Transfers the call if it is active or held.
+ *
+ * @param number number to be transferred to.
+ * @param isConfirmationRequired whether for blind or assured transfer.
+ */
+ @VisibleForTesting
+ public void transfer(Uri number, boolean isConfirmationRequired) {
+ if (mState == CallState.ACTIVE || mState == CallState.ON_HOLD) {
+ if (mConnectionService != null) {
+ mConnectionService.transfer(this, number, isConfirmationRequired);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "transfer call failed due to null CS callId=%s", getId());
+ }
+ Log.addEvent(this, LogUtils.Events.REQUEST_TRANSFER, Log.pii(number));
+ }
+ }
+
+ /**
+ * Transfers the call when this call is active and the other call is held.
+ * This is for Consultative call transfer.
+ *
+ * @param otherCall The other {@link Call} to which this call will be transferred.
+ */
+ @VisibleForTesting
+ public void transfer(Call otherCall) {
+ if (mState == CallState.ACTIVE &&
+ (otherCall != null && otherCall.getState() == CallState.ON_HOLD)) {
+ if (mConnectionService != null) {
+ mConnectionService.transfer(this, otherCall);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "transfer call failed due to null CS callId=%s", getId());
+ }
+ Log.addEvent(this, LogUtils.Events.REQUEST_CONSULTATIVE_TRANSFER, otherCall);
+ }
+ }
+
+ /**
* Puts the call on hold if it is currently active.
*/
@VisibleForTesting
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
old mode 100644
new mode 100755
index 64bbe99..495dcb4
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -2381,6 +2381,32 @@
}
}
+ /**
+ * Instructs Telecom to transfer the specified call. Intended to be invoked by the in-call
+ * app through {@link InCallAdapter} after the user opts to transfer the said call.
+ */
+ @VisibleForTesting
+ public void transferCall(Call call, Uri number, boolean isConfirmationRequired) {
+ if (!mCalls.contains(call)) {
+ Log.i(this, "transferCall - Request to transfer a non-existent call %s", call);
+ } else {
+ call.transfer(number, isConfirmationRequired);
+ }
+ }
+
+ /**
+ * Instructs Telecom to transfer the specified call to another ongoing call.
+ * Intended to be invoked by the in-call app through {@link InCallAdapter} after the user opts
+ * to transfer the said call (consultative transfer).
+ */
+ @VisibleForTesting
+ public void transferCall(Call call, Call otherCall) {
+ if (!mCalls.contains(call) || !mCalls.contains(otherCall)) {
+ Log.i(this, "transferCall - Non-existent call %s or %s", call, otherCall);
+ } else {
+ call.transfer(otherCall);
+ }
+ }
/**
* Instructs Telecom to play the specified DTMF tone within the specified call.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
old mode 100644
new mode 100755
index a3b23af..3ae00aa
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1614,6 +1614,33 @@
}
}
+ /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */
+ void transfer(Call call, Uri number, boolean isConfirmationRequired) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("transfer")) {
+ try {
+ logOutgoing("transfer %s", callId);
+ mServiceInterface.transfer(callId, number, isConfirmationRequired,
+ Log.getExternalSession());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */
+ void transfer(Call call, Call otherCall) {
+ final String callId = mCallIdMapper.getCallId(call);
+ final String otherCallId = mCallIdMapper.getCallId(otherCall);
+ if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) {
+ try {
+ logOutgoing("consultativeTransfer %s", callId);
+ mServiceInterface.consultativeTransfer(callId, otherCallId,
+ Log.getExternalSession());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/** @see IConnectionService#playDtmfTone(String, char, Session.Info) */
void playDtmfTone(Call call, char digit) {
final String callId = mCallIdMapper.getCallId(call);
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
old mode 100644
new mode 100755
index f47f212..d25665f
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -151,6 +151,54 @@
}
}
+ public void transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired) {
+ try {
+ Log.startSession(LogUtils.Sessions.ICA_TRANSFER_CALL, mOwnerPackageName);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "transferCall - %s, %s, %b", callId, Log.pii(targetNumber),
+ isConfirmationRequired);
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ mCallsManager.transferCall(call, targetNumber, isConfirmationRequired);
+ } else {
+ Log.w(this, "transferCall, unknown call id: %s", callId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void consultativeTransfer(String callId, String otherCallId) {
+ try {
+ Log.startSession(LogUtils.Sessions.ICA_CONSULTATIVE_TRANSFER, mOwnerPackageName);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "consultativeTransfer - %s, %s", callId, otherCallId);
+ Call call = mCallIdMapper.getCall(callId);
+ Call otherCall = mCallIdMapper.getCall(otherCallId);
+ if (call != null && otherCall != null) {
+ mCallsManager.transferCall(call, otherCall);
+ } else {
+ Log.w(this, "consultativeTransfer, unknown call id: %s or %s",
+ callId, otherCallId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
@Override
public void playDtmfTone(String callId, char digit) {
try {
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index 0b7a1b5..280b2a8 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -63,6 +63,8 @@
public static final String ICA_ANSWER_CALL = "ICA.aC";
public static final String ICA_DEFLECT_CALL = "ICA.defC";
public static final String ICA_REJECT_CALL = "ICA.rC";
+ public static final String ICA_TRANSFER_CALL = "ICA.tC";
+ public static final String ICA_CONSULTATIVE_TRANSFER = "ICA.cT";
public static final String ICA_DISCONNECT_CALL = "ICA.dC";
public static final String ICA_HOLD_CALL = "ICA.hC";
public static final String ICA_UNHOLD_CALL = "ICA.uC";
@@ -108,6 +110,8 @@
"REQUEST_PICKUP_FOR_AUDIO_PROCESSING";
public static final String REQUEST_DEFLECT = "REQUEST_DEFLECT";
public static final String REQUEST_REJECT = "REQUEST_REJECT";
+ public static final String REQUEST_TRANSFER = "REQUEST_TRANSFER";
+ public static final String REQUEST_CONSULTATIVE_TRANSFER = "REQUEST_CONSULTATIVE_TRANSFER";
public static final String START_DTMF = "START_DTMF";
public static final String STOP_DTMF = "STOP_DTMF";
public static final String START_RINGER = "START_RINGER";
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 3b77621..aae3e36 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -515,8 +515,15 @@
Connection.CAPABILITY_SUPPORT_DEFLECT,
android.telecom.Call.Details.CAPABILITY_SUPPORT_DEFLECT,
+
Connection.CAPABILITY_ADD_PARTICIPANT,
- android.telecom.Call.Details.CAPABILITY_ADD_PARTICIPANT
+ android.telecom.Call.Details.CAPABILITY_ADD_PARTICIPANT,
+
+ Connection.CAPABILITY_TRANSFER,
+ android.telecom.Call.Details.CAPABILITY_TRANSFER,
+
+ Connection.CAPABILITY_TRANSFER_CONSULTATIVE,
+ android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE
};
private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
old mode 100644
new mode 100755
index fb04577..c1a3b80
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -302,6 +302,14 @@
throws RemoteException { }
@Override
+ public void transfer(String callId, Uri number, boolean isConfirmationRequired,
+ Session.Info info) throws RemoteException { }
+
+ @Override
+ public void consultativeTransfer(String callId, String otherCallId,
+ Session.Info info) throws RemoteException { }
+
+ @Override
public void reject(String callId, Session.Info info) throws RemoteException {
rejectedCallIds.add(callId);
}