Merge "Introduce Session logging to CallAudioManager"
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 6d6ee29..382f2aa 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -1030,6 +1030,19 @@
}
}
+ /**
+ * Silences the ringer.
+ */
+ void silence() {
+ if (mConnectionService == null) {
+ Log.w(this, "silence() request on a call without a connection service.");
+ } else {
+ Log.i(this, "Send silence to connection service for call %s", this);
+ Log.event(this, Log.Events.STOP_DTMF);
+ mConnectionService.silence(this);
+ }
+ }
+
void disconnect() {
disconnect(false);
}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 8a0adfb..5567fd8 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -20,8 +20,10 @@
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.UserHandle;
import android.provider.CallLog.Calls;
import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
@@ -55,7 +57,8 @@
*/
public AddCallArgs(Context context, CallerInfo callerInfo, String number, String postDialDigits,
int presentation, int callType, int features, PhoneAccountHandle accountHandle,
- long creationDate, long durationInMillis, Long dataUsage) {
+ long creationDate, long durationInMillis, Long dataUsage,
+ UserHandle initiatingUser) {
this.context = context;
this.callerInfo = callerInfo;
this.number = number;
@@ -67,6 +70,7 @@
this.timestamp = creationDate;
this.durationInSec = (int)(durationInMillis / 1000);
this.dataUsage = dataUsage;
+ this.initiatingUser = initiatingUser;
}
// Since the members are accessed directly, we don't use the
// mXxxx notation.
@@ -81,11 +85,13 @@
public final long timestamp;
public final int durationInSec;
public final Long dataUsage;
+ public final UserHandle initiatingUser;
}
private static final String TAG = CallLogManager.class.getSimpleName();
private final Context mContext;
+ private final PhoneAccountRegistrar mPhoneAccountRegistrar;
private static final String ACTION_CALLS_TABLE_ADD_ENTRY =
"com.android.server.telecom.intent.action.CALLS_ADD_ENTRY";
private static final String PERMISSION_PROCESS_CALLLOG_INFO =
@@ -93,8 +99,9 @@
private static final String CALL_TYPE = "callType";
private static final String CALL_DURATION = "duration";
- public CallLogManager(Context context) {
+ public CallLogManager(Context context, PhoneAccountRegistrar phoneAccountRegistrar) {
mContext = context;
+ mPhoneAccountRegistrar = phoneAccountRegistrar;
}
@Override
@@ -153,7 +160,7 @@
int callFeatures = getCallFeatures(call.getVideoStateHistory());
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(),
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
- creationTime, age, null, call.isEmergencyCall());
+ creationTime, age, null, call.isEmergencyCall(), call.getInitiatingUser());
}
/**
@@ -182,7 +189,8 @@
long start,
long duration,
Long dataUsage,
- boolean isEmergency) {
+ boolean isEmergency,
+ UserHandle initiatingUser) {
// 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
@@ -200,7 +208,8 @@
+ Log.pii(number) + "," + presentation + ", " + callType
+ ", " + start + ", " + duration);
AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
- presentation, callType, features, accountHandle, start, duration, dataUsage);
+ presentation, callType, features, accountHandle, start, duration, dataUsage,
+ initiatingUser);
logCallAsync(args);
} else {
Log.d(TAG, "Not adding emergency call to call log.");
@@ -264,12 +273,9 @@
Uri[] result = new Uri[count];
for (int i = 0; i < count; i++) {
AddCallArgs c = callList[i];
-
try {
// May block.
- result[i] = Calls.addCall(c.callerInfo, c.context, c.number, c.postDialDigits,
- c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
- c.durationInSec, c.dataUsage, true /* addForAllUsers */);
+ result[i] = addCall(c);
} catch (Exception e) {
// This is very rare but may happen in legitimate cases.
// E.g. If the phone is encrypted and thus write request fails, it may cause
@@ -285,6 +291,34 @@
return result;
}
+ private Uri addCall(AddCallArgs c) {
+ PhoneAccount phoneAccount = mPhoneAccountRegistrar
+ .getPhoneAccountUnchecked(c.accountHandle);
+ if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+ if (c.initiatingUser != null &&
+ UserUtil.isManagedProfile(mContext, c.initiatingUser)) {
+ return addCall(c, c.initiatingUser);
+ } else {
+ return addCall(c, null);
+ }
+ } else {
+ return addCall(c, c.accountHandle.getUserHandle());
+ }
+ }
+
+ /**
+ * Insert the call to a specific user or all users except managed profile.
+ * @param c context
+ * @param userToBeInserted user handle of user that the call going be inserted to. null
+ * if insert to all users except managed profile.
+ */
+ private Uri addCall(AddCallArgs c, UserHandle userToBeInserted) {
+ return Calls.addCall(c.callerInfo, c.context, c.number, c.postDialDigits,
+ c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
+ c.durationInSec, c.dataUsage, userToBeInserted == null,
+ userToBeInserted);
+ }
+
/**
* Performs a simple sanity check to make sure the call was written in the database.
* Typically there is only one result per call so it is easy to identify which one failed.
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 56f0963..6919afa 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -217,7 +217,7 @@
mTtyManager = new TtyManager(context, mWiredHeadsetManager);
mProximitySensorManager = proximitySensorManagerFactory.create(context, this);
mPhoneStateBroadcaster = new PhoneStateBroadcaster(this);
- mCallLogManager = new CallLogManager(context);
+ mCallLogManager = new CallLogManager(context, phoneAccountRegistrar);
mInCallController = new InCallController(context, mLock, this);
mDtmfLocalTonePlayer = new DtmfLocalTonePlayer(context);
mConnectionServiceRepository =
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index f7046bc..792eb8b 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -661,6 +661,18 @@
removeCall(call, new DisconnectCause(DisconnectCause.LOCAL));
}
+ /** @see IConnectionService#silence(String) */
+ void silence(Call call) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("silence")) {
+ try {
+ logOutgoing("silence %s", callId);
+ mServiceInterface.silence(callId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/** @see IConnectionService#hold(String) */
void hold(Call call) {
final String callId = mCallIdMapper.getCallId(call);
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 15a2a30..9780633 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -235,7 +235,7 @@
mState.defaultOutgoing = null;
} else {
// TODO: Do we really want to return for *any* user?
- PhoneAccount account = getPhoneAccount(accountHandle);
+ PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
if (account == null) {
Log.w(this, "Trying to set nonexistent default outgoing %s",
accountHandle);
@@ -374,7 +374,7 @@
* otherwise.
*/
public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
- PhoneAccount account = getPhoneAccount(accountHandle);
+ PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
if (account == null) {
Log.w(this, "Could not find account to enable: " + accountHandle);
return false;
@@ -525,7 +525,7 @@
// source app provides or else an third party app could enable itself.
boolean isEnabled = false;
- PhoneAccount oldAccount = getPhoneAccount(account.getAccountHandle());
+ PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle());
if (oldAccount != null) {
mState.accounts.remove(oldAccount);
isEnabled = oldAccount.isEnabled();
@@ -545,7 +545,7 @@
}
public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
- PhoneAccount account = getPhoneAccount(accountHandle);
+ PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
if (account != null) {
if (mState.accounts.remove(account)) {
write();
@@ -688,7 +688,7 @@
* @param handle
* @return The corresponding phone account if one exists.
*/
- PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
+ public PhoneAccount getPhoneAccountUnchecked(PhoneAccountHandle handle) {
for (PhoneAccount m : mState.accounts) {
if (Objects.equals(handle, m.getAccountHandle())) {
return m;
@@ -703,7 +703,7 @@
* device.
*/
public PhoneAccount getPhoneAccountCheckCallingUser(PhoneAccountHandle handle) {
- PhoneAccount account = getPhoneAccount(handle);
+ PhoneAccount account = getPhoneAccountUnchecked(handle);
if (account != null && isVisibleForUser(account)) {
return account;
}
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 0ec2298..da22e98 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -151,6 +151,10 @@
* Silences the ringer for any actively ringing calls.
*/
void silence() {
+ for (Call call : mRingingCalls) {
+ call.silence();
+ }
+
// Remove all calls from the "ringing" set and then update the ringer.
mRingingCalls.clear();
updateRinging(null);
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index cd30e52..43084bb 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -201,7 +201,7 @@
return null;
}
// TODO: Do we really want to return for *any* user?
- return mPhoneAccountRegistrar.getPhoneAccount(accountHandle);
+ return mPhoneAccountRegistrar.getPhoneAccountUnchecked(accountHandle);
} catch (Exception e) {
Log.e(this, e, "getPhoneAccount %s", accountHandle);
throw e;
@@ -987,7 +987,7 @@
if (accountHandle == null) {
return false;
}
- return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccount(accountHandle));
+ return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccountUnchecked(accountHandle));
}
private boolean isVisibleToCaller(PhoneAccount account) {
diff --git a/src/com/android/server/telecom/UserUtil.java b/src/com/android/server/telecom/UserUtil.java
new file mode 100644
index 0000000..a35a61e
--- /dev/null
+++ b/src/com/android/server/telecom/UserUtil.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+public final class UserUtil {
+
+ private UserUtil() {
+ }
+
+ private static UserInfo getUserInfoFromUserHandle(Context context, UserHandle userHandle) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ return userManager.getUserInfo(userHandle.getIdentifier());
+ }
+
+ public static boolean isManagedProfile(Context context, UserHandle userHandle) {
+ UserInfo userInfo = getUserInfoFromUserHandle(context, userHandle);
+ return userInfo != null && userInfo.isManagedProfile();
+ }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index a1e58ee..48e8fb3 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.IContentProvider;
@@ -26,13 +27,16 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.CallLog;
+import android.provider.CallLog.Calls;
import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.VideoProfile;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallLogManager;
import com.android.server.telecom.CallState;
+import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.TelephonyUtil;
import static org.mockito.Matchers.any;
@@ -43,14 +47,17 @@
import static org.mockito.Mockito.when;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
-import java.util.Collections;
+import java.util.Arrays;
public class CallLogManagerTest extends TelecomTestCase {
private CallLogManager mCallLogManager;
private IContentProvider mContentProvider;
private PhoneAccountHandle mDefaultAccountHandle;
+ private PhoneAccountHandle mOtherUserAccountHandle;
+ private PhoneAccountHandle mManagedProfileAccountHandle;
private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234");
@@ -64,25 +71,52 @@
private static final String TEST_PHONE_ACCOUNT_ID= "testPhoneAccountId";
private static final int TEST_TIMEOUT_MILLIS = 100;
+ private static final int CURRENT_USER_ID = 0;
+ private static final int OTHER_USER_ID = 10;
+ private static final int MANAGED_USER_ID = 11;
+
+ @Mock
+ PhoneAccountRegistrar mMockPhoneAccountRegistrar;
+
@Override
public void setUp() throws Exception {
super.setUp();
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
- mCallLogManager = new CallLogManager(mContext);
+ mCallLogManager = new CallLogManager(mContext, mMockPhoneAccountRegistrar);
mContentProvider = mContext.getContentResolver().acquireProvider("test");
mDefaultAccountHandle = new PhoneAccountHandle(
new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"),
- TEST_PHONE_ACCOUNT_ID
+ TEST_PHONE_ACCOUNT_ID,
+ UserHandle.of(CURRENT_USER_ID)
+ );
+
+ mOtherUserAccountHandle = new PhoneAccountHandle(
+ new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"),
+ TEST_PHONE_ACCOUNT_ID,
+ UserHandle.of(OTHER_USER_ID)
+ );
+
+ mManagedProfileAccountHandle = new PhoneAccountHandle(
+ new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"),
+ TEST_PHONE_ACCOUNT_ID,
+ UserHandle.of(MANAGED_USER_ID)
);
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- UserInfo userInfo = new UserInfo(UserHandle.USER_CURRENT, "test", 0);
+ UserInfo userInfo = new UserInfo(CURRENT_USER_ID, "test", 0);
+ UserInfo otherUserInfo = new UserInfo(OTHER_USER_ID, "test2", 0);
+ UserInfo managedProfileUserInfo = new UserInfo(OTHER_USER_ID, "test3",
+ UserInfo.FLAG_MANAGED_PROFILE);
+
when(userManager.isUserRunning(any(UserHandle.class))).thenReturn(true);
when(userManager.hasUserRestriction(any(String.class), any(UserHandle.class)))
.thenReturn(false);
when(userManager.getUsers(any(Boolean.class)))
- .thenReturn(Collections.singletonList(userInfo));
+ .thenReturn(Arrays.asList(userInfo, otherUserInfo, managedProfileUserInfo));
+ when(userManager.getUserInfo(eq(CURRENT_USER_ID))).thenReturn(userInfo);
+ when(userManager.getUserInfo(eq(OTHER_USER_ID))).thenReturn(otherUserInfo);
+ when(userManager.getUserInfo(eq(MANAGED_USER_ID))).thenReturn(managedProfileUserInfo);
}
public void testDontLogCancelledCall() {
@@ -95,7 +129,8 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits,
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.DIALING, CallState.DISCONNECTED);
verifyNoInsertion();
@@ -104,6 +139,8 @@
}
public void testDontLogChoosingAccountCall() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -113,7 +150,8 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.SELECT_PHONE_ACCOUNT,
CallState.DISCONNECTED);
@@ -121,6 +159,8 @@
}
public void testDontLogCallsFromEmergencyAccount() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(EMERGENCY_ACCT_HANDLE, 0));
mComponentContextFixture.putBooleanResource(R.bool.allow_emergency_numbers_in_call_log,
false);
Call fakeCall = makeFakeCall(
@@ -132,13 +172,16 @@
TEL_PHONEHANDLE, // callHandle
EMERGENCY_ACCT_HANDLE, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits,
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
verifyNoInsertion();
}
public void testLogCallDirectionOutgoing() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeOutgoingCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -148,16 +191,19 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
}
public void testLogCallDirectionIncoming() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeIncomingCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -167,16 +213,19 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ null
);
mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE,
CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
}
public void testLogCallDirectionMissed() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeMissedCall = makeFakeCall(
DisconnectCause.MISSED, // disconnectCauseCode
false, // isConference
@@ -186,17 +235,20 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ null
);
mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE,
CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
Integer.valueOf(CallLog.Calls.MISSED_TYPE));
}
public void testCreationTimeAndAge() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
long currentTime = System.currentTimeMillis();
long duration = 1000L;
Call fakeCall = makeFakeCall(
@@ -208,10 +260,11 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsLong(CallLog.Calls.DATE),
Long.valueOf(currentTime));
assertEquals(insertedValues.getAsLong(CallLog.Calls.DURATION),
@@ -219,6 +272,8 @@
}
public void testLogPhoneAccountId() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -228,15 +283,18 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsString(CallLog.Calls.PHONE_ACCOUNT_ID),
TEST_PHONE_ACCOUNT_ID);
}
public void testLogCorrectPhoneNumber() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -246,16 +304,19 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
NO_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertEquals(insertedValues.getAsString(CallLog.Calls.NUMBER),
TEL_PHONEHANDLE.getSchemeSpecificPart());
assertEquals(insertedValues.getAsString(CallLog.Calls.POST_DIAL_DIGITS), POST_DIAL_STRING);
}
public void testLogCallVideoFeatures() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
Call fakeVideoCall = makeFakeCall(
DisconnectCause.OTHER, // disconnectCauseCode
false, // isConference
@@ -265,14 +326,158 @@
TEL_PHONEHANDLE, // callHandle
mDefaultAccountHandle, // phoneAccountHandle
BIDIRECTIONAL_VIDEO_STATE, // callVideoState
- POST_DIAL_STRING // postDialDigits
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
);
mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED);
- ContentValues insertedValues = verifyInsertionWithCapture();
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
assertTrue((insertedValues.getAsInteger(CallLog.Calls.FEATURES)
& CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO);
}
+ public void testLogCallDirectionOutgoingWithMultiUserCapability() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle,
+ PhoneAccount.CAPABILITY_MULTI_USER));
+ Call fakeOutgoingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(CURRENT_USER_ID)
+ );
+ mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+
+ // Outgoing call placed through a phone account with multi user capability is inserted to
+ // all users except managed profile.
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ insertedValues = verifyInsertionWithCapture(OTHER_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ verifyNoInsertionInUser(MANAGED_USER_ID);
+ }
+
+ public void testLogCallDirectionIncomingWithMultiUserCapability() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle,
+ PhoneAccount.CAPABILITY_MULTI_USER));
+ Call fakeIncomingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ null
+ );
+ mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+
+ // Incoming call using a phone account with multi user capability is inserted to all users
+ // except managed profile.
+ ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
+ insertedValues = verifyInsertionWithCapture(OTHER_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
+ verifyNoInsertionInUser(MANAGED_USER_ID);
+ }
+
+
+ public void testLogCallDirectionOutgoingWithMultiUserCapabilityFromManagedProfile() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle,
+ PhoneAccount.CAPABILITY_MULTI_USER));
+ Call fakeOutgoingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mManagedProfileAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(MANAGED_USER_ID)
+ );
+ mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+
+ // Outgoing call placed through work dialer should be inserted to managed profile only.
+ verifyNoInsertionInUser(CURRENT_USER_ID);
+ verifyNoInsertionInUser(OTHER_USER_ID);
+ ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ }
+
+ public void testLogCallDirectionOutgoingFromManagedProfile() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0));
+ Call fakeOutgoingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ false, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mManagedProfileAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ UserHandle.of(MANAGED_USER_ID)
+ );
+ mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+
+ // Outgoing call using phone account in managed profile should be inserted to managed
+ // profile only.
+ verifyNoInsertionInUser(CURRENT_USER_ID);
+ verifyNoInsertionInUser(OTHER_USER_ID);
+ ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ }
+
+ public void testLogCallDirectionIngoingFromManagedProfile() {
+ when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+ .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0));
+ Call fakeOutgoingCall = makeFakeCall(
+ DisconnectCause.OTHER, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mManagedProfileAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ null
+ );
+ mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+
+ // Incoming call using phone account in managed profile should be inserted to managed
+ // profile only.
+ verifyNoInsertionInUser(CURRENT_USER_ID);
+ verifyNoInsertionInUser(OTHER_USER_ID);
+ ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID);
+ assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(Calls.INCOMING_TYPE));
+ }
+
+
private void verifyNoInsertion() {
try {
verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).never()).insert(any(String.class),
@@ -282,11 +487,23 @@
}
}
- private ContentValues verifyInsertionWithCapture() {
+
+ private void verifyNoInsertionInUser(int userId) {
+ try {
+ Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
+ verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).never()).insert(any(String.class),
+ eq(uri), any(ContentValues.class));
+ } catch (android.os.RemoteException e) {
+ fail("Remote exception occurred during test execution");
+ }
+ }
+
+ private ContentValues verifyInsertionWithCapture(int userId) {
ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
try {
+ Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS)).insert(any(String.class),
- eq(CallLog.Calls.CONTENT_URI), captor.capture());
+ eq(uri), captor.capture());
} catch (android.os.RemoteException e) {
fail("Remote exception occurred during test execution");
}
@@ -298,7 +515,7 @@
private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming,
long creationTimeMillis, long ageMillis, Uri callHandle,
PhoneAccountHandle phoneAccountHandle, int callVideoState,
- String postDialDigits) {
+ String postDialDigits, UserHandle initiatingUser) {
Call fakeCall = mock(Call.class);
when(fakeCall.getDisconnectCause()).thenReturn(
new DisconnectCause(disconnectCauseCode));
@@ -310,7 +527,13 @@
when(fakeCall.getTargetPhoneAccount()).thenReturn(phoneAccountHandle);
when(fakeCall.getVideoStateHistory()).thenReturn(callVideoState);
when(fakeCall.getPostDialDigits()).thenReturn(postDialDigits);
-
+ when(fakeCall.getInitiatingUser()).thenReturn(initiatingUser);
return fakeCall;
}
+
+ private PhoneAccount makeFakePhoneAccount(PhoneAccountHandle phoneAccountHandle,
+ int capabilities) {
+ return PhoneAccount.builder(phoneAccountHandle, "testing")
+ .setCapabilities(capabilities).build();
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 903028c..bdcfb5b 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -40,6 +40,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.StatusHints;
+import java.lang.Override;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -113,6 +114,9 @@
public void disconnect(String callId) throws RemoteException { }
@Override
+ public void silence(String callId) throws RemoteException { }
+
+ @Override
public void hold(String callId) throws RemoteException { }
@Override