Update calllog insertion logic
Here are behaviors defined by Lilian, we may revisit the behavior later.
1. Calls using multi user PhoneAccount are inserted to all users
except managed profile.
2. Outgoing call placed through work dialer is inserted into managed profile
only.
3. Calls using non-multi user PhoneAccount should be only inserted to
that particular user.
Change-Id: I84f54afb3af38b931b71063608f38d265aa0417c
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/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/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 91056d2..5ae548a 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;
@@ -985,7 +985,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();
+ }
}