Resolve MT Work Profile ECall
Currently, we don't properly support handling work calls across profile
boundaries. This only applies to emergency calling use cases as
non-emergency work calls are always rejected across profiles. The
existing check to verify if the work profile is paused only applies to
the context of an admin user using the work sim. However, it is possible
that the user is signed in as a guest/secondary user, the profile isn't
paused, and they receive an incoming emergency call on the work sim.
In order to account for this, we also need to ensure that if the current
user isn't the admin user, we should always perform the binding on that
user. In CallsManager, we need to ensure that the non-emergency work
calls are properly being rejected in the guest/secondary user. For the
ECBM use case, we need to ensure that all non-emergency calls are
permitted within the 5 minute time period.
Fixes: 287687156
Test: Added unit tests
Test: Manual verification on emergency calling use cases
Change-Id: I924f0fb47952d9e68bc278e8f11fd5fe2541f289
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 4d2f273..77570c3 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -1572,7 +1572,14 @@
// Check if the target phone account is possibly in ECBM.
call.setIsInECBM(getEmergencyCallHelper()
.isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount()));
- if (mUserManager.isQuietModeEnabled(call.getAssociatedUser())
+ // If the phone account user profile is paused or the call isn't visible to the secondary/
+ // guest user, reject the non-emergency incoming call. When the current user is the admin,
+ // we need to allow the calls to go through if the work profile isn't paused. We should
+ // always allow emergency calls and also allow non-emergency calls when ECBM is active for
+ // the phone account.
+ if ((mUserManager.isQuietModeEnabled(call.getAssociatedUser())
+ || (!mUserManager.isUserAdmin(mCurrentUserHandle.getIdentifier())
+ && !isCallVisibleForUser(call, mCurrentUserHandle)))
&& !call.isEmergencyCall() && !call.isInECBM()) {
Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.",
phoneAccountHandle.getUserHandle());
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 8e10614..d5689ae 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -2875,7 +2875,11 @@
// Emergency call should never be blocked, so if the user associated with call is in
// quite mode, use the primary user for the emergency call.
if ((call.isEmergencyCall() || call.isInECBM())
- && userManager.isQuietModeEnabled(userFromCall)) {
+ && (userManager.isQuietModeEnabled(userFromCall)
+ // We should also account for secondary/guest users where the profile may not
+ // necessarily be paused.
+ || !userManager.isUserAdmin(mCallsManager.getCurrentUserHandle()
+ .getIdentifier()))) {
return mCallsManager.getCurrentUserHandle();
}
return userFromCall;
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index c42a2ca..9f46336 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -174,6 +174,8 @@
ComponentName.unflattenFromString("com.baz/.Self"), "Self");
private static final PhoneAccountHandle SELF_MANAGED_2_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.baz/.Self2"), "Self2");
+ private static final PhoneAccountHandle WORK_HANDLE = new PhoneAccountHandle(
+ ComponentName.unflattenFromString("com.foo/.Blah"), "work", new UserHandle(10));
private static final PhoneAccountHandle SELF_MANAGED_W_CUSTOM_HANDLE = new PhoneAccountHandle(
new ComponentName(TEST_PACKAGE_NAME, "class"), "1", TEST_USER_HANDLE);
private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
@@ -205,11 +207,19 @@
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
.setIsEnabled(true)
.build();
+ private static final PhoneAccount WORK_ACCOUNT = new PhoneAccount.Builder(
+ WORK_HANDLE, "work")
+ .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+ | PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
+ .setIsEnabled(true)
+ .build();
private static final PhoneAccount SM_W_DIFFERENT_PACKAGE_AND_USER = new PhoneAccount.Builder(
SELF_MANAGED_W_CUSTOM_HANDLE, "Self")
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
.setIsEnabled(true)
.build();
+
private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
private static final Uri TEST_ADDRESS2 = Uri.parse("tel:555-1213");
private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214");
@@ -346,6 +356,8 @@
eq(SIM_1_HANDLE), any())).thenReturn(SIM_1_ACCOUNT);
when(mPhoneAccountRegistrar.getPhoneAccount(
eq(SIM_2_HANDLE), any())).thenReturn(SIM_2_ACCOUNT);
+ when(mPhoneAccountRegistrar.getPhoneAccount(
+ eq(WORK_HANDLE), any())).thenReturn(WORK_ACCOUNT);
when(mToastFactory.makeText(any(), anyInt(), anyInt())).thenReturn(mToast);
when(mToastFactory.makeText(any(), any(), anyInt())).thenReturn(mToast);
}
@@ -2490,7 +2502,30 @@
@SmallTest
@Test
- public void testRejectIncomingCallOnPAHInactive() throws Exception {
+ public void testRejectIncomingCallOnPAHInactive_SecondaryUser() throws Exception {
+ ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
+ doReturn(WORK_HANDLE.getComponentName()).when(service).getComponentName();
+ mCallsManager.addConnectionServiceRepositoryCache(WORK_HANDLE.getComponentName(),
+ WORK_HANDLE.getUserHandle(), service);
+
+ UserManager um = mContext.getSystemService(UserManager.class);
+ UserHandle newUser = new UserHandle(11);
+ when(mCallsManager.getCurrentUserHandle()).thenReturn(newUser);
+ when(um.isUserAdmin(eq(newUser.getIdentifier()))).thenReturn(false);
+ when(um.isQuietModeEnabled(eq(WORK_HANDLE.getUserHandle()))).thenReturn(false);
+ when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(WORK_HANDLE)))
+ .thenReturn(WORK_ACCOUNT);
+ Call newCall = mCallsManager.processIncomingCallIntent(
+ WORK_HANDLE, new Bundle(), false);
+
+ verify(service, timeout(TEST_TIMEOUT)).createConnectionFailed(any());
+ assertFalse(newCall.isInECBM());
+ assertEquals(USER_MISSED_NOT_RUNNING, newCall.getMissedReason());
+ }
+
+ @SmallTest
+ @Test
+ public void testRejectIncomingCallOnPAHInactive_ProfilePaused() throws Exception {
ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
@@ -2527,6 +2562,30 @@
@SmallTest
@Test
+ public void testAcceptIncomingCallOnPAHInactiveAndECBMActive_SecondaryUser() throws Exception {
+ ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
+ doReturn(WORK_HANDLE.getComponentName()).when(service).getComponentName();
+ mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
+ WORK_HANDLE.getUserHandle(), service);
+
+ when(mEmergencyCallHelper.isLastOutgoingEmergencyCallPAH(eq(WORK_HANDLE)))
+ .thenReturn(true);
+ UserManager um = mContext.getSystemService(UserManager.class);
+ UserHandle newUser = new UserHandle(11);
+ when(mCallsManager.getCurrentUserHandle()).thenReturn(newUser);
+ when(um.isUserAdmin(eq(newUser.getIdentifier()))).thenReturn(false);
+ when(um.isQuietModeEnabled(eq(WORK_HANDLE.getUserHandle()))).thenReturn(false);
+ when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(eq(WORK_HANDLE)))
+ .thenReturn(WORK_ACCOUNT);
+ Call newCall = mCallsManager.processIncomingCallIntent(
+ WORK_HANDLE, new Bundle(), false);
+
+ assertTrue(newCall.isInECBM());
+ verify(service, timeout(TEST_TIMEOUT).times(0)).createConnectionFailed(any());
+ }
+
+ @SmallTest
+ @Test
public void testAcceptIncomingEmergencyCallOnPAHInactive() throws Exception {
ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
@@ -3100,6 +3159,9 @@
// WHEN
when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any()))
.thenReturn(SM_W_DIFFERENT_PACKAGE_AND_USER);
+ UserManager um = mContext.getSystemService(UserManager.class);
+ when(um.isUserAdmin(eq(mCallsManager.getCurrentUserHandle().getIdentifier())))
+ .thenReturn(true);
// THEN
mCallsManager.processIncomingCallIntent(SELF_MANAGED_W_CUSTOM_HANDLE, new Bundle(), false);
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 2f3e4bf..683a5e2 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -638,6 +638,37 @@
@MediumTest
@Test
public void
+ testBindToService_UserAssociatedWithCallSecondary_NonEmergCallECBM_BindsToSecondaryUser()
+ throws Exception {
+ UserHandle newUser = new UserHandle(13);
+ when(mMockCallsManager.getCurrentUserHandle()).thenReturn(newUser);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockCall.isEmergencyCall()).thenReturn(false);
+ when(mMockCall.isInECBM()).thenReturn(true);
+ when(mMockCall.isIncoming()).thenReturn(true);
+ when(mMockCall.getAssociatedUser()).thenReturn(DUMMY_USER_HANDLE);
+ when(mMockContext.getSystemService(eq(UserManager.class)))
+ .thenReturn(mMockUserManager);
+ when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+ when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
+ setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+ setupMockPackageManagerLocationPermission(SYS_PKG, false /* granted */);
+
+ mInCallController.bindToServices(mMockCall);
+
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockContext, times(1)).bindServiceAsUser(
+ bindIntentCaptor.capture(),
+ any(ServiceConnection.class),
+ eq(serviceBindingFlags),
+ eq(newUser));
+ Intent bindIntent = bindIntentCaptor.getValue();
+ assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
+ }
+
+ @MediumTest
+ @Test
+ public void
testBindToService_UserAssociatedWithCallNotInQuietMode_EmergCallInCallUi_BindsToAssociatedUser()
throws Exception {
when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
@@ -647,6 +678,7 @@
when(mMockContext.getSystemService(eq(UserManager.class)))
.thenReturn(mMockUserManager);
when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+ when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(true);
setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
setupMockPackageManagerLocationPermission(SYS_PKG, false /* granted */);