Merge "Support for enhanced call/connection extras." into nyc-dev
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 3402cc4..4e3c79d 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -74,6 +74,11 @@
public static final int CALL_DIRECTION_INCOMING = 2;
public static final int CALL_DIRECTION_UNKNOWN = 3;
+ /** Identifies extras changes which originated from a connection service. */
+ public static final int SOURCE_CONNECTION_SERVICE = 1;
+ /** Identifies extras changes which originated from an incall service. */
+ public static final int SOURCE_INCALL_SERVICE = 2;
+
/**
* Listener for events on the call.
*/
@@ -95,7 +100,8 @@
void onCallerInfoChanged(Call call);
void onIsVoipAudioModeChanged(Call call);
void onStatusHintsChanged(Call call);
- void onExtrasChanged(Call call);
+ void onExtrasChanged(Call c, int source, Bundle extras);
+ void onExtrasRemoved(Call c, int source, List<String> keys);
void onHandleChanged(Call call);
void onCallerDisplayNameChanged(Call call);
void onVideoStateChanged(Call call);
@@ -144,7 +150,9 @@
@Override
public void onStatusHintsChanged(Call call) {}
@Override
- public void onExtrasChanged(Call call) {}
+ public void onExtrasChanged(Call c, int source, Bundle extras) {}
+ @Override
+ public void onExtrasRemoved(Call c, int source, List<String> keys) {}
@Override
public void onHandleChanged(Call call) {}
@Override
@@ -1069,7 +1077,7 @@
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
- setExtras(connection.getExtras());
+ putExtras(SOURCE_CONNECTION_SERVICE, connection.getExtras());
mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
@@ -1327,10 +1335,64 @@
return mExtras;
}
- void setExtras(Bundle extras) {
- mExtras = extras;
+ /**
+ * Adds extras to the extras bundle associated with this {@link Call}.
+ *
+ * Note: this method needs to know the source of the extras change (see
+ * {@link #SOURCE_CONNECTION_SERVICE}, {@link #SOURCE_INCALL_SERVICE}). Extras changes which
+ * originate from a connection service will only be notified to incall services. Likewise,
+ * changes originating from the incall services will only notify the connection service of the
+ * change.
+ *
+ * @param source The source of the extras addition.
+ * @param extras The extras.
+ */
+ void putExtras(int source, Bundle extras) {
+ if (extras == null) {
+ return;
+ }
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+
for (Listener l : mListeners) {
- l.onExtrasChanged(this);
+ l.onExtrasChanged(this, source, extras);
+ }
+
+ // If the change originated from an InCallService, notify the connection service.
+ if (source == SOURCE_INCALL_SERVICE) {
+ mConnectionService.onExtrasChanged(this, mExtras);
+ }
+ }
+
+ /**
+ * Removes extras from the extras bundle associated with this {@link Call}.
+ *
+ * Note: this method needs to know the source of the extras change (see
+ * {@link #SOURCE_CONNECTION_SERVICE}, {@link #SOURCE_INCALL_SERVICE}). Extras changes which
+ * originate from a connection service will only be notified to incall services. Likewise,
+ * changes originating from the incall services will only notify the connection service of the
+ * change.
+ *
+ * @param source The source of the extras removal.
+ * @param keys The extra keys to remove.
+ */
+ void removeExtras(int source, List<String> keys) {
+ if (mExtras == null) {
+ return;
+ }
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+
+ for (Listener l : mListeners) {
+ l.onExtrasRemoved(this, source, keys);
+ }
+
+ // If the change originated from an InCallService, notify the connection service.
+ if (source == SOURCE_INCALL_SERVICE) {
+ mConnectionService.onExtrasChanged(this, mExtras);
}
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 73d5556..16e8f92 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -1144,7 +1144,14 @@
}
@Override
- public void onExtrasChanged(Call call) {
+ public void onExtrasChanged(Call c, int source, Bundle extras) {
+ if (source != Call.SOURCE_CONNECTION_SERVICE) {
+ return;
+ }
+ handleCallTechnologyChange(c);
+ }
+
+ private void handleCallTechnologyChange(Call call) {
if (call.getExtras() != null
&& call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) {
@@ -1461,7 +1468,7 @@
call.setVideoState(parcelableConference.getVideoState());
call.setVideoProvider(parcelableConference.getVideoProvider());
call.setStatusHints(parcelableConference.getStatusHints());
- call.setExtras(parcelableConference.getExtras());
+ call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
// TODO: Move this to be a part of addCall()
call.addListener(this);
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 5543f9b..69c7573 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -487,16 +487,33 @@
}
@Override
- public void setExtras(String callId, Bundle extras) {
- Log.startSession("CSW.sE");
+ public void putExtras(String callId, Bundle extras) {
+ Log.startSession("CSW.pE");
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
Bundle.setDefusable(extras, true);
- logIncoming("setExtras %s %s", callId, extras);
Call call = mCallIdMapper.getCall(callId);
if (call != null) {
- call.setExtras(extras);
+ call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void removeExtras(String callId, List<String> keys) {
+ Log.startSession("CSW.rE");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ logIncoming("removeExtra %s %s", callId, keys);
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys);
}
}
} finally {
@@ -962,6 +979,17 @@
}
}
+ void onExtrasChanged(Call call, Bundle extras) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("onExtrasChanged")) {
+ try {
+ logOutgoing("onExtrasChanged %s %s", callId, extras);
+ mServiceInterface.onExtrasChanged(callId, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
/** {@inheritDoc} */
@Override
protected void setServiceInterface(IBinder binder) {
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 4dd06d2..31d268e 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -22,6 +22,8 @@
import com.android.internal.telecom.IInCallAdapter;
+import java.util.List;
+
/**
* Receives call commands and updates from in-call app and passes them through to CallsManager.
* {@link InCallController} creates an instance of this class and passes it to the in-call app after
@@ -415,6 +417,50 @@
}
@Override
+ public void putExtras(String callId, Bundle extras) {
+ try {
+ Log.startSession("ICA.pE", mOwnerComponentName);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.putExtras(Call.SOURCE_INCALL_SERVICE, extras);
+ } else {
+ Log.w(this, "putExtras, unknown call id: %s", callId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void removeExtras(String callId, List<String> keys) {
+ try {
+ Log.startSession("ICA.rE", mOwnerComponentName);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.removeExtras(Call.SOURCE_INCALL_SERVICE, keys);
+ } else {
+ Log.w(this, "removeExtra, unknown call id: %s", callId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void turnOnProximitySensor() {
try {
Log.startSession("ICA.tOnPS", mOwnerComponentName);
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 93589ed..4ee6c20 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -33,6 +33,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.telecom.CallAudioState;
+import android.telecom.ConnectionService;
import android.telecom.DefaultDialerManager;
import android.telecom.InCallService;
import android.telecom.ParcelableCall;
@@ -104,8 +105,44 @@
updateCall(call);
}
+ /**
+ * Listens for changes to extras reported by a Telecom {@link Call}.
+ *
+ * Extras changes can originate from a {@link ConnectionService} or an {@link InCallService}
+ * so we will only trigger an update of the call information if the source of the extras
+ * change was a {@link ConnectionService}.
+ *
+ * @param call The call.
+ * @param source The source of the extras change ({@link Call#SOURCE_CONNECTION_SERVICE} or
+ * {@link Call#SOURCE_INCALL_SERVICE}).
+ * @param extras The extras.
+ */
@Override
- public void onExtrasChanged(Call call) {
+ public void onExtrasChanged(Call call, int source, Bundle extras) {
+ // Do not inform InCallServices of changes which originated there.
+ if (source == Call.SOURCE_INCALL_SERVICE) {
+ return;
+ }
+ updateCall(call);
+ }
+
+ /**
+ * Listens for changes to extras reported by a Telecom {@link Call}.
+ *
+ * Extras changes can originate from a {@link ConnectionService} or an {@link InCallService}
+ * so we will only trigger an update of the call information if the source of the extras
+ * change was a {@link ConnectionService}.
+ * @param call The call.
+ * @param source The source of the extras change ({@link Call#SOURCE_CONNECTION_SERVICE} or
+ * {@link Call#SOURCE_INCALL_SERVICE}).
+ * @param keys The extra key removed
+ */
+ @Override
+ public void onExtrasRemoved(Call call, int source, List<String> keys) {
+ // Do not inform InCallServices of changes which originated there.
+ if (source == Call.SOURCE_INCALL_SERVICE) {
+ return;
+ }
updateCall(call);
}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index c819838..b30e372 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -374,7 +374,7 @@
connectionExtras.putString(Connection.EXTRA_CALL_SUBJECT,
"This is a test of call subject lines.");
}
- connection.setExtras(connectionExtras);
+ connection.putExtras(connectionExtras);
setAddress(connection, address);
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index ac080ae..6279c5e 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -585,33 +585,6 @@
assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
}
- private ParcelableCall makeConferenceCall() throws Exception {
- IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212",
- mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
-
- IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213",
- mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
-
- IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter();
- inCallAdapter.conference(callId1.mCallId, callId2.mCallId);
- // Wait for wacky non-deterministic behavior
- Thread.sleep(200);
- ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId);
- ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId);
- // Check that the two calls end up with a parent in the end
- assertNotNull(call1.getParentCallId());
- assertNotNull(call2.getParentCallId());
- assertEquals(call1.getParentCallId(), call2.getParentCallId());
-
- // Check to make sure that the parent call made it to the in-call service
- String parentCallId = call1.getParentCallId();
- ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId);
- assertEquals(2, conferenceCall.getChildCallIds().size());
- assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId));
- assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId));
- return conferenceCall;
- }
-
/**
* Tests the {@link Call#pullExternalCall()} API. Verifies that if a call is not an external
* call, no pull call request is made to the connection service.
diff --git a/tests/src/com/android/server/telecom/tests/CallExtrasTest.java b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java
new file mode 100644
index 0000000..e9cd733
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.tests;
+
+import android.os.Bundle;
+import android.telecom.Call;
+import android.telecom.Conference;
+import android.telecom.Connection;
+import android.telecom.InCallService;
+import android.telecom.ParcelableCall;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Tests the {@link Connection} and {@link Call} extras functionality.
+ */
+public class CallExtrasTest extends TelecomSystemTest {
+
+ public final static String EXTRA_KEY_STR = "STRINGKEY";
+ public final static String EXTRA_KEY_STR2 = "BLAHTEST";
+ public final static String EXTRA_KEY_INT = "INTKEY";
+ public final static String EXTRA_KEY_BOOL = "BOOLKEY";
+ public final static String EXTRA_VALUE_STR = "socks";
+ public final static String EXTRA_VALUE2_STR = "mozzarella";
+ public final static int EXTRA_VALUE_INT = 1234;
+
+ /**
+ * Tests setting extras on the connection side and ensuring they are propagated through to
+ * the InCallService.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsPutExtras() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ // Communicate extras from the ConnectionService to the InCallService.
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ extras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ connection.putExtras(extras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(
+ EXTRA_KEY_STR));
+ assertTrue(mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(
+ EXTRA_KEY_INT));
+ }
+
+ /**
+ * Tests setting extras on the connection side and ensuring they are propagated through to
+ * the InCallService.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsPutBooleanExtra() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ connection.putExtra(EXTRA_KEY_BOOL, true);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(mInCallServiceFixtureX.getCall(ids.mCallId).getExtras()
+ .containsKey(EXTRA_KEY_BOOL));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().getBoolean(EXTRA_KEY_BOOL));
+ }
+
+ /**
+ * Tests setting extras on the connection side and ensuring they are propagated through to
+ * the InCallService.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsPutIntExtra() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ connection.putExtra(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+ assertEquals(EXTRA_VALUE_INT,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().getInt(EXTRA_KEY_INT));
+ }
+
+ /**
+ * Tests setting extras on the connection side and ensuring they are propagated through to
+ * the InCallService.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsPutStringExtra() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ connection.putExtra(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertEquals(EXTRA_VALUE_STR,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().getString(EXTRA_KEY_STR));
+ }
+
+ /**
+ * Tests remove extras on the connection side and ensuring the removal is reflected in the
+ * InCallService.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsRemoveExtra() throws Exception {
+ // Get a call up and running."STRING"
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ // Add something.
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ connection.putExtra(EXTRA_KEY_STR2, EXTRA_VALUE_STR);
+ connection.putExtra(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertEquals(EXTRA_VALUE_STR,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().getString(EXTRA_KEY_STR));
+
+ // Take it away.
+ connection.removeExtras(new ArrayList<String>(Arrays.asList(EXTRA_KEY_STR)));
+ mInCallServiceFixtureX.waitForUpdate();
+ assertFalse(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(mInCallServiceFixtureX.getCall(ids.mCallId).getExtras()
+ .containsKey(EXTRA_KEY_STR2));
+ }
+
+ /**
+ * Tests putting a new value for an existing extras key.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsUpdateExisting() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+
+ // Communicate extras from the ConnectionService to the InCallService.
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ extras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ connection.putExtras(extras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+
+ connection.putExtra(EXTRA_KEY_STR, EXTRA_VALUE2_STR);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertEquals(EXTRA_VALUE2_STR,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().getString(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+ }
+
+ /**
+ * Tests ability of the deprecated setExtras method to detect changes to the extras bundle
+ * and merge these changes into the telecom extras. The old setExtras worked by just replacing
+ * the entire extras bundle, so we need to ensure that we can properly handle cases where an
+ * API user has added or removed items from the extras, but still gracefully merge this into the
+ * extras maintained for the connection.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testCsSetExtras() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+
+ // Set the initial bundle.
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ extras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ connection.setExtras(extras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+
+ // Modify the initial bundle to add a value and remove another.
+ extras.putString(EXTRA_KEY_STR2, EXTRA_VALUE2_STR);
+ extras.remove(EXTRA_KEY_STR);
+ connection.setExtras(extras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertFalse(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras()
+ .containsKey(EXTRA_KEY_STR2));
+ }
+
+ /**
+ * Tests that additions to the extras via an {@link InCallService} are propagated back down to
+ * the {@link Connection}.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testICSPutExtras() throws Exception {
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ extras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+ mInCallServiceFixtureX.mInCallAdapter.putExtras(ids.mCallId, extras);
+ mConnectionServiceFixtureA.waitForExtras();
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+ assertNotNull(connection);
+ Bundle connectionExtras = connection.getExtras();
+ assertTrue(connectionExtras.containsKey(EXTRA_KEY_STR));
+ assertEquals(EXTRA_VALUE_STR, extras.getString(EXTRA_KEY_STR));
+ assertTrue(connectionExtras.containsKey(EXTRA_KEY_INT));
+ assertEquals(EXTRA_VALUE_INT, extras.getInt(EXTRA_KEY_INT));
+ }
+
+ /**
+ * A bi-directional test of the extras. Tests setting extras from both the ConnectionService
+ * and InCall side and ensuring the bundles are merged appropriately.
+ *
+ * @throws Exception
+ */
+ @LargeTest
+ public void testExtrasBidirectional() throws Exception {
+ // Get a call up and running.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ Connection connection = mConnectionServiceFixtureA.mLatestConnection;
+
+ // Set the initial bundle.
+ Bundle someExtras = new Bundle();
+ someExtras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ someExtras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ connection.setExtras(someExtras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+
+ // From the InCall side, add another key
+ Bundle someMoreExtras = new Bundle();
+ someMoreExtras.putBoolean(EXTRA_KEY_BOOL, true);
+ mInCallServiceFixtureX.mInCallAdapter.putExtras(ids.mCallId, someMoreExtras);
+ mConnectionServiceFixtureA.waitForExtras();
+ Bundle connectionExtras = connection.getExtras();
+ assertTrue(connectionExtras.containsKey(EXTRA_KEY_STR));
+ assertTrue(connectionExtras.containsKey(EXTRA_KEY_INT));
+ assertTrue(connectionExtras.containsKey(EXTRA_KEY_BOOL));
+
+ // Modify the initial bundle to add a value and remove another.
+ someExtras.putString(EXTRA_KEY_STR2, EXTRA_VALUE2_STR);
+ someExtras.remove(EXTRA_KEY_STR);
+ connection.setExtras(someExtras);
+ mInCallServiceFixtureX.waitForUpdate();
+ assertFalse(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras().containsKey(EXTRA_KEY_INT));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras()
+ .containsKey(EXTRA_KEY_STR2));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(ids.mCallId).getExtras()
+ .containsKey(EXTRA_KEY_BOOL));
+ }
+
+ /**
+ * Similar to {@link #testCsSetExtras()}, tests to ensure the existing setExtras functionality
+ * is maintained.
+ *
+ * @throws Exception
+ */
+ @LargeTest
+ public void testConferenceSetExtras() throws Exception {
+ ParcelableCall call = makeConferenceCall();
+ String conferenceId = call.getId();
+
+ Conference conference = mConnectionServiceFixtureA.mLatestConference;
+ assertNotNull(conference);
+
+ Bundle someExtras = new Bundle();
+ someExtras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ someExtras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ conference.setExtras(someExtras);
+
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_INT));
+
+ someExtras.putString(EXTRA_KEY_STR2, EXTRA_VALUE2_STR);
+ someExtras.remove(EXTRA_KEY_INT);
+ conference.setExtras(someExtras);
+
+ mInCallServiceFixtureX.waitForUpdate();
+ assertTrue(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_STR));
+ assertFalse(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_INT));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_STR2));
+ }
+
+ /**
+ * Tests putExtras for conferences.
+ *
+ * @throws Exception
+ */
+ @LargeTest
+ public void testConferenceExtraOperations() throws Exception {
+ ParcelableCall call = makeConferenceCall();
+ String conferenceId = call.getId();
+ Conference conference = mConnectionServiceFixtureA.mLatestConference;
+ assertNotNull(conference);
+
+ conference.putExtra(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ conference.putExtra(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ conference.putExtra(EXTRA_KEY_BOOL, true);
+ mInCallServiceFixtureX.waitForUpdate();
+
+ assertTrue(mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_STR));
+ assertEquals(EXTRA_VALUE_STR,
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras().get(EXTRA_KEY_STR));
+ assertTrue(
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_INT));
+ assertEquals(EXTRA_VALUE_INT,
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras().get(EXTRA_KEY_INT));
+ assertEquals(true,
+ mInCallServiceFixtureX.getCall(conferenceId).getExtras().get(EXTRA_KEY_BOOL));
+
+ conference.removeExtras(new ArrayList<String>(Arrays.asList(EXTRA_KEY_STR)));
+ mInCallServiceFixtureX.waitForUpdate();
+ assertFalse(mInCallServiceFixtureX.getCall(conferenceId).getExtras()
+ .containsKey(EXTRA_KEY_STR));
+ }
+
+ /**
+ * Tests communication of extras from an InCallService to a Conference.
+ *
+ * @throws Exception
+ */
+ @LargeTest
+ public void testConferenceICS() throws Exception {
+ ParcelableCall call = makeConferenceCall();
+ String conferenceId = call.getId();
+ Conference conference = mConnectionServiceFixtureA.mLatestConference;
+
+ Bundle someExtras = new Bundle();
+ someExtras.putString(EXTRA_KEY_STR, EXTRA_VALUE_STR);
+ mInCallServiceFixtureX.mInCallAdapter.putExtras(conferenceId, someExtras);
+ mConnectionServiceFixtureA.waitForExtras();
+
+ Bundle conferenceExtras = conference.getExtras();
+ assertTrue(conferenceExtras.containsKey(EXTRA_KEY_STR));
+
+ Bundle someMoreExtras = new Bundle();
+ someMoreExtras.putString(EXTRA_KEY_STR2, EXTRA_VALUE_STR);
+ someMoreExtras.putInt(EXTRA_KEY_INT, EXTRA_VALUE_INT);
+ someMoreExtras.putBoolean(EXTRA_KEY_BOOL, true);
+ mInCallServiceFixtureX.mInCallAdapter.putExtras(conferenceId, someMoreExtras);
+ mConnectionServiceFixtureA.waitForExtras();
+ conferenceExtras = conference.getExtras();
+ assertTrue(conferenceExtras.containsKey(EXTRA_KEY_STR));
+ assertTrue(conferenceExtras.containsKey(EXTRA_KEY_STR2));
+ assertTrue(conferenceExtras.containsKey(EXTRA_KEY_INT));
+ assertTrue(conferenceExtras.containsKey(EXTRA_KEY_BOOL));
+
+ mInCallServiceFixtureX.mInCallAdapter.removeExtras(conferenceId,
+ new ArrayList<String>(Arrays.asList(EXTRA_KEY_STR)));
+ mConnectionServiceFixtureA.waitForExtras();
+ conferenceExtras = conference.getExtras();
+ assertFalse(conferenceExtras.containsKey(EXTRA_KEY_STR));
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 27f169d..8d78f3d 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -48,11 +48,14 @@
import java.lang.Override;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Controls a test {@link IConnectionService} as would be provided by a source of connectivity
@@ -61,6 +64,7 @@
public class ConnectionServiceFixture implements TestFixture<IConnectionService> {
static int INVALID_VIDEO_STATE = -1;
static int CAPABILITIES_NOT_SPECIFIED = 0;
+ public CountDownLatch mExtrasLock = new CountDownLatch(1);
/**
* Implementation of ConnectionService that performs no-ops for tasks normally meant for
@@ -73,7 +77,8 @@
@Override
public Connection onCreateUnknownConnection(
PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
- return new FakeConnection(request.getVideoState(), request.getAddress());
+ mLatestConnection = new FakeConnection(request.getVideoState(), request.getAddress());
+ return mLatestConnection;
}
@Override
@@ -82,6 +87,7 @@
FakeConnection fakeConnection = new FakeConnection(
mVideoState == INVALID_VIDEO_STATE ? request.getVideoState() : mVideoState,
request.getAddress());
+ mLatestConnection = fakeConnection;
if (mCapabilities != CAPABILITIES_NOT_SPECIFIED) {
fakeConnection.setConnectionCapabilities(mCapabilities);
}
@@ -92,7 +98,8 @@
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
- return new FakeConnection(request.getVideoState(), request.getAddress());
+ mLatestConnection = new FakeConnection(request.getVideoState(), request.getAddress());
+ return mLatestConnection;
}
@Override
@@ -103,6 +110,7 @@
Conference fakeConference = new FakeConference();
fakeConference.addConnection(cxn1);
fakeConference.addConnection(cxn2);
+ mLatestConference = fakeConference;
addConference(fakeConference);
}
}
@@ -119,6 +127,11 @@
setActive();
setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
}
+
+ @Override
+ public void onExtrasChanged(Bundle extras) {
+ mExtrasLock.countDown();
+ }
}
public class FakeConference extends Conference {
@@ -136,6 +149,12 @@
// Do nothing besides inform the connection that it was merged into this conference.
connection.setConference(this);
}
+
+ @Override
+ public void onExtrasChanged(Bundle extras) {
+ Log.w(this, "FakeConference onExtrasChanged");
+ mExtrasLock.countDown();
+ }
}
public class FakeConnectionService extends IConnectionService.Stub {
@@ -248,6 +267,10 @@
public void sendCallEvent(String callId, String event, Bundle extras) throws RemoteException
{}
+ public void onExtrasChanged(String callId, Bundle extras) throws RemoteException {
+ mConnectionServiceDelegateAdapter.onExtrasChanged(callId, extras);
+ }
+
@Override
public IBinder asBinder() {
return this;
@@ -304,6 +327,8 @@
}
public String mLatestConnectionId;
+ public Connection mLatestConnection;
+ public Conference mLatestConference;
public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>();
public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>();
public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>();
@@ -491,6 +516,18 @@
}
}
+ /**
+ * Waits until the {@link Connection#onExtrasChanged(Bundle)} API has been called on a
+ * {@link Connection} or {@link Conference}.
+ */
+ public void waitForExtras() {
+ try {
+ mExtrasLock.await(TelecomSystemTest.TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ie) {
+ }
+ mExtrasLock = new CountDownLatch(1);
+ }
+
private ParcelableConference parcelable(ConferenceInfo c) {
return new ParcelableConference(
c.phoneAccount,
diff --git a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
index eb007a3..bf12411 100644
--- a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
@@ -31,6 +31,8 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Controls a test {@link IInCallService} as would be provided by an InCall UI on a system.
@@ -47,6 +49,7 @@
public boolean mShowDialpad;
public boolean mCanAddCall;
public boolean mSilenceRinger;
+ public CountDownLatch mLock = new CountDownLatch(1);
public class FakeInCallService extends IInCallService.Stub {
@Override
@@ -76,6 +79,7 @@
}
mCallById.put(call.getId(), call);
mLatestCallId = call.getId();
+ mLock.countDown();
}
@Override
@@ -144,4 +148,13 @@
public IInCallAdapter getInCallAdapter() {
return mInCallAdapter;
}
+
+ public void waitForUpdate() {
+ try {
+ mLock.await(5000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ie) {
+ return;
+ }
+ mLock = new CountDownLatch(1);
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 12d82b3..eeacd84 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -249,6 +249,33 @@
super.tearDown();
}
+ protected ParcelableCall makeConferenceCall() throws Exception {
+ IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+
+ IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter();
+ inCallAdapter.conference(callId1.mCallId, callId2.mCallId);
+ // Wait for wacky non-deterministic behavior
+ Thread.sleep(200);
+ ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId);
+ ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId);
+ // Check that the two calls end up with a parent in the end
+ assertNotNull(call1.getParentCallId());
+ assertNotNull(call2.getParentCallId());
+ assertEquals(call1.getParentCallId(), call2.getParentCallId());
+
+ // Check to make sure that the parent call made it to the in-call service
+ String parentCallId = call1.getParentCallId();
+ ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId);
+ assertEquals(2, conferenceCall.getChildCallIds().size());
+ assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId));
+ assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId));
+ return conferenceCall;
+ }
+
private void setupTelecomSystem() throws Exception {
// Use actual implementations instead of mocking the interface out.
HeadsetMediaButtonFactory headsetMediaButtonFactory =