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

Commit c78d4f17 authored by Tyler Gunn's avatar Tyler Gunn Committed by Android (Google) Code Review
Browse files

Merge "Make sure late connected non ui ICS are unbound." into udc-dev

parents 464a9a6d 97574b38
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -801,6 +801,9 @@ public class InCallController extends CallsManagerListenerBase implements
            }
            Call callToConnectWith = mCallIdMapper.getCalls().iterator().next();
            for (InCallServiceBindingConnection newConnection : newConnections) {
                // Ensure we track the new sub-connection so that when we later disconnect we will
                // be able to disconnect it.
                mSubConnections.add(newConnection);
                newConnection.connect(callToConnectWith);
            }
        }
@@ -2189,7 +2192,8 @@ public class InCallController extends CallsManagerListenerBase implements
     * Adds the call to the list of calls tracked by the {@link InCallController}.
     * @param call The call to add.
     */
    private void addCall(Call call) {
    @VisibleForTesting
    public void addCall(Call call) {
        if (mCallIdMapper.getCalls().size() == 0) {
            mAppOpsManager.startWatchingActive(new String[] { OPSTR_RECORD_AUDIO },
                    java.lang.Runnable::run, this);
+130 −14
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -53,10 +52,12 @@ import android.app.NotificationManager;
import android.app.UiModeManager;
import android.content.AttributionSource;
import android.content.AttributionSourceState;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
@@ -66,7 +67,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.compat.testing.PlatformCompatChangeRule;
import android.os.Binder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -123,14 +124,13 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import libcore.junit.util.compat.CoreCompatChangeRule;

@RunWith(JUnit4.class)
public class InCallControllerTests extends TelecomTestCase {
    @Mock CallsManager mMockCallsManager;
@@ -156,25 +156,25 @@ public class InCallControllerTests extends TelecomTestCase {
    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    private static final int CURRENT_USER_ID = 900973;
    private static final int CURRENT_USER_ID = 9;
    private static final String DEF_PKG = "defpkg";
    private static final String DEF_CLASS = "defcls";
    private static final int DEF_UID = 1;
    private static final int DEF_UID = 900972;
    private static final String SYS_PKG = "syspkg";
    private static final String SYS_CLASS = "syscls";
    private static final int SYS_UID = 2;
    private static final int SYS_UID = 900971;
    private static final String COMPANION_PKG = "cpnpkg";
    private static final String COMPANION_CLASS = "cpncls";
    private static final int COMPANION_UID = 3;
    private static final int COMPANION_UID = 900970;
    private static final String CAR_PKG = "carpkg";
    private static final String CAR2_PKG = "carpkg2";
    private static final String CAR_CLASS = "carcls";
    private static final String CAR2_CLASS = "carcls";
    private static final int CAR_UID = 4;
    private static final int CAR2_UID = 5;
    private static final int CAR_UID = 900969;
    private static final int CAR2_UID = 900968;
    private static final String NONUI_PKG = "nonui_pkg";
    private static final String NONUI_CLASS = "nonui_cls";
    private static final int NONUI_UID = 6;
    private static final int NONUI_UID = 900973;
    private static final String APPOP_NONUI_PKG = "appop_nonui_pkg";
    private static final String APPOP_NONUI_CLASS = "appop_nonui_cls";
    private static final int APPOP_NONUI_UID = 7;
@@ -190,6 +190,7 @@ public class InCallControllerTests extends TelecomTestCase {
    private EmergencyCallHelper mEmergencyCallHelper;
    private SystemStateHelper.SystemStateListener mSystemStateListener;
    private CarModeTracker mCarModeTracker = spy(new CarModeTracker());
    private BroadcastReceiver mRegisteredReceiver;

    private final int serviceBindingFlags = Context.BIND_AUTO_CREATE
        | Context.BIND_FOREGROUND_SERVICE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
@@ -202,6 +203,7 @@ public class InCallControllerTests extends TelecomTestCase {
        MockitoAnnotations.initMocks(this);
        when(mMockCall.getAnalytics()).thenReturn(new Analytics.CallInfo());
        when(mMockCall.getUserHandleFromTargetPhoneAccount()).thenReturn(mUserHandle);
        when(mMockCall.getId()).thenReturn("TC@1");
        doReturn(mMockResources).when(mMockContext).getResources();
        doReturn(mMockAppOpsManager).when(mMockContext).getSystemService(AppOpsManager.class);
        doReturn(SYS_PKG).when(mMockResources).getString(
@@ -225,6 +227,12 @@ public class InCallControllerTests extends TelecomTestCase {
        mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
                mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
                mEmergencyCallHelper, mCarModeTracker, mClockProxy);
        // Capture the broadcast receiver registered.
        doAnswer(invocation -> {
            mRegisteredReceiver = invocation.getArgument(0);
            return null;
        }).when(mMockContext).registerReceiver(any(BroadcastReceiver.class),
                any(IntentFilter.class));

        ArgumentCaptor<SystemStateHelper.SystemStateListener> systemStateListenerArgumentCaptor
                = ArgumentCaptor.forClass(SystemStateHelper.SystemStateListener.class);
@@ -878,6 +886,114 @@ public class InCallControllerTests extends TelecomTestCase {
        verifyBinding(bindIntentCaptor2, 1, CAR_PKG, CAR_CLASS);
    }

    /**
     * This test verifies the behavior of Telecom when the system dialer crashes on binding and must
     * be restarted.  Specifically, it ensures when the system dialer crashes we revoke the runtime
     * location permission, and when it restarts we re-grant the permission.
     * @throws Exception
     */
    @MediumTest
    @Test
    public void testBindToLateConnectionNonUiIcs() throws Exception {
        Bundle callExtras = new Bundle();
        callExtras.putBoolean("whatever", true);

        // Make a basic call and bind to the default dialer.
        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
        when(mMockCallsManager.isInEmergencyCall()).thenReturn(true);
        when(mMockCall.isEmergencyCall()).thenReturn(true);
        when(mMockContext.getSystemService(eq(UserManager.class)))
                .thenReturn(mMockUserManager);
        when(mMockUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
        when(mMockCall.isIncoming()).thenReturn(false);
        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
        when(mMockCall.getIntentExtras()).thenReturn(callExtras);
        when(mMockCall.isExternalCall()).thenReturn(false);
        when(mDefaultDialerCache.getDefaultDialerApplication(CURRENT_USER_ID))
                .thenReturn(DEF_PKG);
        ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
                ArgumentCaptor.forClass(ServiceConnection.class);
        when(mMockContext.bindServiceAsUser(any(Intent.class), serviceConnectionCaptor.capture(),
                eq(serviceBindingFlags),
                eq(mUserHandle))).thenReturn(true);
        when(mTimeoutsAdapter.getEmergencyCallbackWindowMillis(any(ContentResolver.class)))
                .thenReturn(300_000L);

        // Setup package manager; there is a dialer and disable non-ui ICS
        when(mMockPackageManager.queryIntentServicesAsUser(
                any(Intent.class), anyInt(), anyInt())).thenReturn(
                Arrays.asList(
                        getDefResolveInfo(false /* externalCalls */, false /* selfMgd */),
                        getNonUiResolveinfo(false /* selfManaged */,
                                false /* isEnabled */)
                )
        );
        when(mMockPackageManager
                .getComponentEnabledSetting(new ComponentName(DEF_PKG, DEF_CLASS)))
                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
        when(mMockPackageManager
                .getComponentEnabledSetting(new ComponentName(NONUI_PKG, NONUI_CLASS)))
                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);

        mInCallController.addCall(mMockCall);
        mInCallController.bindToServices(mMockCall);

        // There will be 4 calls for the various types of ICS.
        verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                any(Intent.class),
                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
                eq(CURRENT_USER_ID));

        // Verify bind to the dialer
        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
        verify(mMockContext, times(1)).bindServiceAsUser(
                bindIntentCaptor.capture(),
                any(ServiceConnection.class),
                eq(serviceBindingFlags),
                eq(mUserHandle));

        Intent bindIntent = bindIntentCaptor.getValue();
        assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
        assertEquals(SYS_PKG, bindIntent.getComponent().getPackageName());
        assertEquals(SYS_CLASS, bindIntent.getComponent().getClassName());

        // Setup mocks to enable nonui ICS
        when(mMockPackageManager.queryIntentServicesAsUser(
                any(Intent.class), anyInt(), anyInt())).thenReturn(
                        Arrays.asList(
                                getDefResolveInfo(false /* externalCalls */, false /* selfMgd */),
                                getNonUiResolveinfo(false /* selfManaged */,
                                        true /* isEnabled */)
                        )
        );
        when(mMockPackageManager
                .getComponentEnabledSetting(new ComponentName(NONUI_PKG, NONUI_CLASS)))
                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);

        // Emulate a late enable of the non-ui ICS
        Intent packageUpdated = new Intent(Intent.ACTION_PACKAGE_CHANGED);
        packageUpdated.setData(Uri.fromParts("package", NONUI_PKG, null));
        packageUpdated.putExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
                new String[] {NONUI_CLASS});
        packageUpdated.putExtra(Intent.EXTRA_UID, NONUI_UID);
        mRegisteredReceiver.onReceive(mMockContext, packageUpdated);

        // Now, we expect to auto-rebind to the system dialer (verify 2 times since this is the
        // second binding).
        verify(mMockContext, times(2)).bindServiceAsUser(
                bindIntentCaptor.capture(),
                any(ServiceConnection.class),
                eq(serviceBindingFlags),
                eq(mUserHandle));

        // Unbind!
        mInCallController.unbindFromServices(UserHandle.of(CURRENT_USER_ID));

        // Make sure we unbound 2 times
        verify(mMockContext, times(2)).unbindService(any(ServiceConnection.class));
    }

    /**
     * Ensures that the {@link InCallController} will bind to an {@link InCallService} which
     * supports external calls.
@@ -1558,14 +1674,14 @@ public class InCallControllerTests extends TelecomTestCase {
        }};
    }

    private ResolveInfo getNonUiResolveinfo(boolean supportsSelfManaged) {
    private ResolveInfo getNonUiResolveinfo(boolean supportsSelfManaged, boolean isEnabled) {
        return new ResolveInfo() {{
            serviceInfo = new ServiceInfo();
            serviceInfo.packageName = NONUI_PKG;
            serviceInfo.name = NONUI_CLASS;
            serviceInfo.applicationInfo = new ApplicationInfo();
            serviceInfo.applicationInfo.uid = NONUI_UID;
            serviceInfo.enabled = true;
            serviceInfo.enabled = isEnabled;
            serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
            serviceInfo.metaData = new Bundle();
            if (supportsSelfManaged) {
@@ -1656,7 +1772,7 @@ public class InCallControllerTests extends TelecomTestCase {
                } else {
                    // InCallController uses a blank package name when querying for non-ui incalls
                    if (useNonUiInCalls) {
                        resolveInfo.add(getNonUiResolveinfo(includeSelfManagedCallsInNonUi));
                        resolveInfo.add(getNonUiResolveinfo(includeSelfManagedCallsInNonUi, true));
                    }
                    // InCallController uses a blank package name when querying for App Op non-ui incalls
                    if (useAppOpNonUiInCalls) {