Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70a44d35 authored by Pranav Madapurmath's avatar Pranav Madapurmath Committed by Android Build Coastguard Worker
Browse files

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
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:01ee614f3b811015f125f6d083e8b779cdd241ff)
Merged-In: I924f0fb47952d9e68bc278e8f11fd5fe2541f289
Change-Id: I924f0fb47952d9e68bc278e8f11fd5fe2541f289
parent b2085ee0
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
@@ -1572,7 +1572,14 @@ public class CallsManager extends Call.ListenerBase
        // Check if the target phone account is possibly in ECBM.
        // Check if the target phone account is possibly in ECBM.
        call.setIsInECBM(getEmergencyCallHelper()
        call.setIsInECBM(getEmergencyCallHelper()
                .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount()));
                .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()) {
                && !call.isEmergencyCall() && !call.isInECBM()) {
            Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.",
            Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.",
                    phoneAccountHandle.getUserHandle());
                    phoneAccountHandle.getUserHandle());
+5 −1
Original line number Original line Diff line number Diff line
@@ -2875,7 +2875,11 @@ public class InCallController extends CallsManagerListenerBase implements
            // Emergency call should never be blocked, so if the user associated with call is in
            // 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.
            // quite mode, use the primary user for the emergency call.
            if ((call.isEmergencyCall() || call.isInECBM())
            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 mCallsManager.getCurrentUserHandle();
            }
            }
            return userFromCall;
            return userFromCall;
+63 −1
Original line number Original line Diff line number Diff line
@@ -174,6 +174,8 @@ public class CallsManagerTest extends TelecomTestCase {
            ComponentName.unflattenFromString("com.baz/.Self"), "Self");
            ComponentName.unflattenFromString("com.baz/.Self"), "Self");
    private static final PhoneAccountHandle SELF_MANAGED_2_HANDLE = new PhoneAccountHandle(
    private static final PhoneAccountHandle SELF_MANAGED_2_HANDLE = new PhoneAccountHandle(
            ComponentName.unflattenFromString("com.baz/.Self2"), "Self2");
            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(
    private static final PhoneAccountHandle SELF_MANAGED_W_CUSTOM_HANDLE = new PhoneAccountHandle(
            new ComponentName(TEST_PACKAGE_NAME, "class"), "1", TEST_USER_HANDLE);
            new ComponentName(TEST_PACKAGE_NAME, "class"), "1", TEST_USER_HANDLE);
    private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
    private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
@@ -205,11 +207,19 @@ public class CallsManagerTest extends TelecomTestCase {
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setIsEnabled(true)
            .setIsEnabled(true)
            .build();
            .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(
    private static final PhoneAccount SM_W_DIFFERENT_PACKAGE_AND_USER = new PhoneAccount.Builder(
            SELF_MANAGED_W_CUSTOM_HANDLE, "Self")
            SELF_MANAGED_W_CUSTOM_HANDLE, "Self")
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            .setIsEnabled(true)
            .setIsEnabled(true)
            .build();
            .build();

    private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
    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_ADDRESS2 = Uri.parse("tel:555-1213");
    private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214");
    private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214");
@@ -346,6 +356,8 @@ public class CallsManagerTest extends TelecomTestCase {
                eq(SIM_1_HANDLE), any())).thenReturn(SIM_1_ACCOUNT);
                eq(SIM_1_HANDLE), any())).thenReturn(SIM_1_ACCOUNT);
        when(mPhoneAccountRegistrar.getPhoneAccount(
        when(mPhoneAccountRegistrar.getPhoneAccount(
                eq(SIM_2_HANDLE), any())).thenReturn(SIM_2_ACCOUNT);
                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(), anyInt(), anyInt())).thenReturn(mToast);
        when(mToastFactory.makeText(any(), any(), anyInt())).thenReturn(mToast);
        when(mToastFactory.makeText(any(), any(), anyInt())).thenReturn(mToast);
    }
    }
@@ -2490,7 +2502,30 @@ public class CallsManagerTest extends TelecomTestCase {


    @SmallTest
    @SmallTest
    @Test
    @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);
        ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
        doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
        doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
        mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
        mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
@@ -2525,6 +2560,30 @@ public class CallsManagerTest extends TelecomTestCase {
        verify(service, timeout(TEST_TIMEOUT).times(0)).createConnectionFailed(any());
        verify(service, timeout(TEST_TIMEOUT).times(0)).createConnectionFailed(any());
    }
    }


    @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
    @SmallTest
    @Test
    @Test
    public void testAcceptIncomingEmergencyCallOnPAHInactive() throws Exception {
    public void testAcceptIncomingEmergencyCallOnPAHInactive() throws Exception {
@@ -3100,6 +3159,9 @@ public class CallsManagerTest extends TelecomTestCase {
        // WHEN
        // WHEN
        when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any()))
        when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any()))
                .thenReturn(SM_W_DIFFERENT_PACKAGE_AND_USER);
                .thenReturn(SM_W_DIFFERENT_PACKAGE_AND_USER);
        UserManager um = mContext.getSystemService(UserManager.class);
        when(um.isUserAdmin(eq(mCallsManager.getCurrentUserHandle().getIdentifier())))
                .thenReturn(true);


        // THEN
        // THEN
        mCallsManager.processIncomingCallIntent(SELF_MANAGED_W_CUSTOM_HANDLE, new Bundle(), false);
        mCallsManager.processIncomingCallIntent(SELF_MANAGED_W_CUSTOM_HANDLE, new Bundle(), false);
+32 −0
Original line number Original line Diff line number Diff line
@@ -635,6 +635,37 @@ public class InCallControllerTests extends TelecomTestCase {
        assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
        assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
    }
    }


    @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
    @MediumTest
    @Test
    @Test
    public void
    public void
@@ -647,6 +678,7 @@ public class InCallControllerTests extends TelecomTestCase {
        when(mMockContext.getSystemService(eq(UserManager.class)))
        when(mMockContext.getSystemService(eq(UserManager.class)))
            .thenReturn(mMockUserManager);
            .thenReturn(mMockUserManager);
        when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
        when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(true);
        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
        setupMockPackageManagerLocationPermission(SYS_PKG, false /* granted */);
        setupMockPackageManagerLocationPermission(SYS_PKG, false /* granted */);