Merge "Binds to 3rd-party InCallService with MANAGE_ONGOING_CALL permission" into rvc-qpr-dev-plus-aosp
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 9c227a6..8b7c37d 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -208,6 +208,9 @@
public void setCallSource(int callSource) {
}
+
+ public void setMissedReason(long missedReason) {
+ }
}
/**
@@ -242,6 +245,7 @@
public List<TelecomLogClass.InCallServiceInfo> inCallServiceInfos;
public int callProperties = 0;
public int callSource = CALL_SOURCE_UNSPECIFIED;
+ public long missedReason;
private long mTimeOfLastVideoEvent = -1;
@@ -254,6 +258,7 @@
connectionService = "";
videoEvents = new LinkedList<>();
inCallServiceInfos = new LinkedList<>();
+ missedReason = 0;
}
CallInfoImpl(CallInfoImpl other) {
@@ -272,6 +277,7 @@
this.videoEvents = other.videoEvents;
this.callProperties = other.callProperties;
this.callSource = other.callSource;
+ this.missedReason = other.missedReason;
if (other.callTerminationReason != null) {
this.callTerminationReason = new DisconnectCause(
@@ -342,6 +348,13 @@
}
@Override
+ public void setMissedReason(long missedReason) {
+ Log.d(TAG, "setting missedReason for call " + callId + ": "
+ + missedReason);
+ this.missedReason = missedReason;
+ }
+
+ @Override
public void setCallEvents(EventManager.EventRecord records) {
this.callEvents = records;
}
@@ -399,6 +412,7 @@
+ " isEmergency: " + isEmergency + '\n'
+ " callTechnologies: " + getCallTechnologiesAsString() + '\n'
+ " callTerminationReason: " + getCallDisconnectReasonString() + '\n'
+ + " missedReason: " + getMissedReasonString() + '\n'
+ " connectionService: " + connectionService + '\n'
+ " isVideoCall: " + isVideo + '\n'
+ " inCallServices: " + getInCallServicesString() + '\n'
@@ -526,6 +540,11 @@
}
}
+ private String getMissedReasonString() {
+ //TODO: Implement this
+ return null;
+ }
+
private String getInCallServicesString() {
StringBuilder s = new StringBuilder();
s.append("[\n");
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 6af999e..fb4f58d 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -16,6 +16,8 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -33,6 +35,7 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.CallLog;
import android.provider.ContactsContract.Contacts;
import android.telecom.CallAudioState;
import android.telecom.CallerInfo;
@@ -588,7 +591,7 @@
/**
* Indicates whether this call is using one of the
- * {@link com.android.server.telecom.callfiltering.IncomingCallFilter.CallFilter} modules.
+ * {@link com.android.server.telecom.callfiltering.CallFilter} modules.
*/
private boolean mIsUsingCallFiltering = false;
@@ -611,6 +614,16 @@
private String mPostCallPackageName;
/**
+ * Call missed information code.
+ */
+ @CallLog.Calls.MissedReason private long mMissedReason;
+
+ /**
+ * Time that this call start ringing or simulated ringing.
+ */
+ private long mStartRingTime;
+
+ /**
* Persists the specified parameters and initializes the new instance.
* @param context The context.
* @param repository The connection service repository.
@@ -692,6 +705,8 @@
mClockProxy = clockProxy;
mToastFactory = toastFactory;
mCreationTimeMillis = mClockProxy.currentTimeMillis();
+ mMissedReason = MISSED_REASON_NOT_MISSED;
+ mStartRingTime = 0;
}
/**
@@ -3870,4 +3885,20 @@
public String getPostCallPackageName() {
return mPostCallPackageName;
}
+
+ public long getMissedReason() {
+ return mMissedReason;
+ }
+
+ public void setMissedReason(long missedReason) {
+ mMissedReason = missedReason;
+ }
+
+ public long getStartRingTime() {
+ return mStartRingTime;
+ }
+
+ public void setStartRingTime(long startRingTime) {
+ mStartRingTime = startRingTime;
+ }
}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index b19e269..cedd41c 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
import static android.telephony.CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL;
import android.annotation.Nullable;
@@ -84,7 +85,8 @@
int features, PhoneAccountHandle accountHandle, long creationDate,
long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
@Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
- CharSequence callScreeningAppName, String callScreeningComponentName) {
+ CharSequence callScreeningAppName, String callScreeningComponentName,
+ long missedReason) {
this.context = context;
this.callerInfo = callerInfo;
this.number = number;
@@ -103,6 +105,7 @@
this.callBockReason = callBlockReason;
this.callScreeningAppName = callScreeningAppName;
this.callScreeningComponentName = callScreeningComponentName;
+ this.missedReason = missedReason;
}
// Since the members are accessed directly, we don't use the
// mXxxx notation.
@@ -127,6 +130,7 @@
public final int callBockReason;
public final CharSequence callScreeningAppName;
public final String callScreeningComponentName;
+ public final long missedReason;
}
private static final String TAG = CallLogManager.class.getSimpleName();
@@ -353,20 +357,25 @@
call.wasEverRttCall(),
call.wasVolte());
- if (callLogType == Calls.BLOCKED_TYPE) {
+ if (result == null) {
+ // Call auto missed before filtered
+ result = new CallFilteringResult.Builder().build();
+ }
+
+ if (callLogType == Calls.BLOCKED_TYPE || callLogType == Calls.MISSED_TYPE) {
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
creationTime, age, callDataUsage, call.isEmergencyCall(),
call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
result.mCallBlockReason, result.mCallScreeningAppName,
- result.mCallScreeningComponentName);
+ result.mCallScreeningComponentName, call.getMissedReason());
} else {
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
creationTime, age, callDataUsage, call.isEmergencyCall(),
call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
Calls.BLOCK_REASON_NOT_BLOCKED, null /*callScreeningAppName*/,
- null /*callScreeningComponentName*/);
+ null /*callScreeningComponentName*/, call.getMissedReason());
}
}
@@ -390,6 +399,7 @@
* @param callBlockReason The reason why the call is blocked.
* @param callScreeningAppName The call screening application name which block the call.
* @param callScreeningComponentName The call screening component name which block the call.
+ * @param missedReason The encoded information about reasons for missed call.
*/
private void logCall(
CallerInfo callerInfo,
@@ -409,7 +419,8 @@
@Nullable LogCallCompletedListener logCallCompletedListener,
int callBlockReason,
CharSequence callScreeningAppName,
- String callScreeningComponentName) {
+ String callScreeningComponentName,
+ long missedReason) {
// On some devices, to avoid accidental redialing of emergency numbers, we *never* log
// emergency calls to the Call Log. (This behavior is set on a per-product basis, based
@@ -443,7 +454,7 @@
AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
viaNumber, presentation, callType, features, accountHandle, start, duration,
dataUsage, initiatingUser, isRead, logCallCompletedListener, callBlockReason,
- callScreeningAppName, callScreeningComponentName);
+ callScreeningAppName, callScreeningComponentName, missedReason);
logCallAsync(args);
} else {
Log.d(TAG, "Not adding emergency call to call log.");
@@ -596,7 +607,7 @@
c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
c.durationInSec, c.dataUsage, userToBeInserted == null,
userToBeInserted, c.isRead, c.callBockReason, c.callScreeningAppName,
- c.callScreeningComponentName);
+ c.callScreeningComponentName, c.missedReason);
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index b53a557..6b99633 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
import static android.telecom.TelecomManager.ACTION_POST_CALL;
import static android.telecom.TelecomManager.DURATION_LONG;
import static android.telecom.TelecomManager.DURATION_MEDIUM;
@@ -27,6 +28,9 @@
import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS;
import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS;
import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
+import static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
import android.Manifest;
import android.annotation.NonNull;
@@ -739,6 +743,7 @@
// Only set the incoming call as ringing if it isn't already disconnected. It is possible
// that the connection service disconnected the call before it was even added to Telecom, in
// which case it makes no sense to set it back to a ringing state.
+ Log.i(this, "onCallFilteringComplete");
mGraphHandlerThreads.clear();
if (incomingCall.getState() != CallState.DISCONNECTED &&
@@ -760,16 +765,17 @@
} else {
Log.i(this, "onCallFilteringCompleted: Call rejected! " +
"Exceeds maximum number of ringing calls.");
- rejectCallAndLog(incomingCall, result);
+ incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+ autoMissCallAndLog(incomingCall, result);
}
} else if (hasMaximumManagedDialingCalls(incomingCall)) {
if (shouldSilenceInsteadOfReject(incomingCall)) {
incomingCall.silence();
} else {
-
Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
"dialing calls.");
- rejectCallAndLog(incomingCall, result);
+ incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_DIALING);
+ autoMissCallAndLog(incomingCall, result);
}
} else if (result.shouldScreenViaAudio) {
Log.i(this, "onCallFilteringCompleted: starting background audio processing");
@@ -1335,12 +1341,18 @@
if (isConference) {
notifyCreateConferenceFailed(phoneAccountHandle, call);
} else {
+ if (hasMaximumManagedRingingCalls(call)) {
+ call.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+ mCallLogManager.logCall(call, Calls.MISSED_TYPE,
+ true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
+ }
notifyCreateConnectionFailed(phoneAccountHandle, call);
}
} else if (isInEmergencyCall()) {
// The incoming call is implicitly being rejected so the user does not get any incoming
// call UI during an emergency call. In this case, log the call as missed instead of
// rejected since the user did not explicitly reject.
+ call.setMissedReason(AUTO_MISSED_EMERGENCY_CALL);
mCallLogManager.logCall(call, Calls.MISSED_TYPE,
true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
if (isConference) {
@@ -3448,7 +3460,8 @@
* Reject an incoming call and manually add it to the Call Log.
* @param incomingCall Incoming call that has been rejected
*/
- private void rejectCallAndLog(Call incomingCall, CallFilteringResult result) {
+ private void autoMissCallAndLog(Call incomingCall, CallFilteringResult result) {
+ incomingCall.getAnalytics().setMissedReason(incomingCall.getMissedReason());
if (incomingCall.getConnectionService() != null) {
// Only reject the call if it has not already been destroyed. If a call ends while
// incoming call filtering is taking place, it is possible that the call has already
@@ -3586,6 +3599,10 @@
(newState == CallState.DISCONNECTED)) {
maybeSendPostCallScreenIntent(call);
}
+ if (((newState == CallState.ABORTED) || (newState == CallState.DISCONNECTED))
+ && (call.getDisconnectCause().getCode() != DisconnectCause.MISSED)) {
+ call.setMissedReason(MISSED_REASON_NOT_MISSED);
+ }
maybeShowErrorDialogOnDisconnect(call);
Trace.beginSection("onCallStateChanged");
@@ -4742,6 +4759,7 @@
* @param call The {@link Call} which could not be added.
*/
private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
+ call.getAnalytics().setMissedReason(call.getMissedReason());
if (phoneAccountHandle == null) {
return;
}
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index ec5f7ba..a64f39d 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.tests;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -127,7 +129,8 @@
Analytics.dump(ip);
String dumpResult = sr.toString();
String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
- "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
+ "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService",
+ "missedReason"};
for (String field : expectedFields) {
assertTrue(dumpResult.contains(field));
}
@@ -200,6 +203,8 @@
assertTrue(callAnalytics2.startTime > 0);
assertEquals(0, callAnalytics1.endTime);
assertEquals(0, callAnalytics2.endTime);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics1.missedReason);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics2.missedReason);
assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
new file mode 100644
index 0000000..d2c832a
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 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 static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.telecom.DisconnectCause;
+import android.telecom.TelecomManager;
+
+import com.android.server.telecom.Analytics;
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallIntentProcessor;
+import com.android.server.telecom.CallState;
+import com.android.server.telecom.CallsManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.Map;
+
+public class MissedInformationTest extends TelecomSystemTest {
+ private static final int TEST_TIMEOUT_MILLIS = 1000;
+ private static final String TEST_NUMBER = "650-555-1212";
+ private static final String TEST_NUMBER_1 = "7";
+ private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
+ @Mock ContentResolver mContentResolver;
+ @Mock IContentProvider mContentProvider;
+ @Mock Call mEmergencyCall;
+ @Mock Analytics.CallInfo mCallInfo;
+ private CallsManager mCallsManager;
+ private CallIntentProcessor.AdapterImpl mAdapter;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mCallsManager = mTelecomSystem.getCallsManager();
+ mAdapter = new CallIntentProcessor.AdapterImpl(mCallsManager.getDefaultDialerCache());
+ when(mContentResolver.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mContentResolver.acquireProvider(any(String.class))).thenReturn(mContentProvider);
+ when(mContentProvider.call(any(String.class), any(String.class),
+ any(String.class), any(Bundle.class))).thenReturn(new Bundle());
+ doReturn(mContentResolver).when(mSpyContext).getContentResolver();
+ }
+
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testNotMissedCall() throws Exception {
+ IdPair testCall = startAndMakeActiveIncomingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ mConnectionServiceFixtureA.
+ sendSetDisconnected(testCall.mConnectionId, DisconnectCause.LOCAL);
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics.missedReason);
+ assertEquals(MISSED_REASON_NOT_MISSED, (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testEmergencyCallPlacing() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ setUpEmergencyCall();
+ mCallsManager.addCall(mEmergencyCall);
+ assertTrue(mCallsManager.isInEmergencyCall());
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (Analytics.CallInfoImpl ci : analyticsMap.values()) {
+ assertEquals(AUTO_MISSED_EMERGENCY_CALL, ci.missedReason);
+ }
+ assertEquals(AUTO_MISSED_EMERGENCY_CALL,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testMaximumDialingCalls() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ IdPair testDialingCall = startAndMakeDialingOutgoingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (String callId : analyticsMap.keySet()) {
+ if (callId.equals(testDialingCall.mCallId)) {
+ continue;
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_DIALING, analyticsMap.get(callId).missedReason);
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_DIALING,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testMaximumRingingCalls() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ IdPair testRingingCall = startAndMakeRingingIncomingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (String callId : analyticsMap.keySet()) {
+ if (callId.equals(testRingingCall.mCallId)) {
+ continue;
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_RINGING, analyticsMap.get(callId).missedReason);
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_RINGING,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ private ContentValues verifyInsertionWithCapture() {
+ ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
+ verify(mContentResolver, timeout(TEST_TIMEOUT_MILLIS))
+ .insert(any(Uri.class), captor.capture());
+ return captor.getValue();
+ }
+
+ private void setUpEmergencyCall() {
+ when(mEmergencyCall.isEmergencyCall()).thenReturn(true);
+ when(mEmergencyCall.getIntentExtras()).thenReturn(new Bundle());
+ when(mEmergencyCall.getAnalytics()).thenReturn(mCallInfo);
+ when(mEmergencyCall.getState()).thenReturn(CallState.ACTIVE);
+ when(mEmergencyCall.getContext()).thenReturn(mSpyContext);
+ when(mEmergencyCall.getHandle()).thenReturn(Uri.parse("tel:" + TEST_NUMBER));
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 226e7ef..aeb68c5 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -1122,6 +1122,54 @@
return ids;
}
+ protected IdPair startAndMakeDialingOutgoingCall(
+ String number,
+ PhoneAccountHandle phoneAccountHandle,
+ ConnectionServiceFixture connectionServiceFixture) throws Exception {
+ IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
+ Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
+
+ connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ }
+
+ return ids;
+ }
+
+ protected IdPair startAndMakeRingingIncomingCall(
+ String number,
+ PhoneAccountHandle phoneAccountHandle,
+ ConnectionServiceFixture connectionServiceFixture) throws Exception {
+ IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
+
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+ mInCallServiceFixtureX.mInCallAdapter
+ .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY);
+
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
+ if (!VideoProfile.isVideo(VideoProfile.STATE_AUDIO_ONLY)) {
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+ .answer(eq(ids.mConnectionId), any());
+ } else {
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+ .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_AUDIO_ONLY),
+ any());
+ }
+ }
+ return ids;
+ }
+
protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
int elapsed = 0;
while (elapsed < TEST_TIMEOUT) {