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

Commit 98a0a8d5 authored by Hall Liu's avatar Hall Liu Committed by android-build-merger
Browse files

Fix broken test and in-call controller bug

am: 28b82f0f

Change-Id: Id3eb39c2883b2d10ce5ed67a2d3fc5eb42baef97
parents 7ae63cc5 28b82f0f
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -266,7 +266,7 @@ public class CallsManager extends Call.ListenerBase
        RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
        SystemVibrator systemVibrator = new SystemVibrator(context);
        mInCallController = new InCallController(
                context, mLock, this, systemStateProvider, defaultDialerAdapter);
                context, mLock, this, systemStateProvider, defaultDialerAdapter, mTimeoutsAdapter);
        mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
                ringtoneFactory, systemVibrator, mInCallController);

@@ -629,7 +629,8 @@ public class CallsManager extends Call.ListenerBase
        return false;
    }

    CallAudioState getAudioState() {
    @VisibleForTesting
    public CallAudioState getAudioState() {
        return mCallAudioManager.getCallAudioState();
    }

@@ -1489,7 +1490,8 @@ public class CallsManager extends Call.ListenerBase
    /**
     * Returns true if telecom supports adding another top-level call.
     */
    boolean canAddCall() {
    @VisibleForTesting
    public boolean canAddCall() {
        boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
        if (!isDeviceProvisioned) {
+35 −31
Original line number Diff line number Diff line
@@ -217,7 +217,7 @@ public final class InCallController extends CallsManagerListenerBase {
                    InCallController.this.onConnected(mInCallServiceInfo, service);
            if (!shouldRemainConnected) {
                // Sometimes we can opt to disconnect for certain reasons, like if the
                // InCallService rejected our intialization step, or the calls went away
                // InCallService rejected our initialization step, or the calls went away
                // in the time it took us to bind to the InCallService. In such cases, we go
                // ahead and disconnect ourselves.
                disconnect();
@@ -599,17 +599,19 @@ public final class InCallController extends CallsManagerListenerBase {
    private final CallsManager mCallsManager;
    private final SystemStateProvider mSystemStateProvider;
    private final DefaultDialerManagerAdapter mDefaultDialerAdapter;
    private final Timeouts.Adapter mTimeoutsAdapter;
    private CarSwappingInCallServiceConnection mInCallServiceConnection;
    private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;

    public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
            SystemStateProvider systemStateProvider,
            DefaultDialerManagerAdapter defaultDialerAdapter) {
            DefaultDialerManagerAdapter defaultDialerAdapter, Timeouts.Adapter timeoutsAdapter) {
        mContext = context;
        mLock = lock;
        mCallsManager = callsManager;
        mSystemStateProvider = systemStateProvider;
        mDefaultDialerAdapter = defaultDialerAdapter;
        mTimeoutsAdapter = timeoutsAdapter;

        Resources resources = mContext.getResources();
        mSystemInCallComponentName = new ComponentName(
@@ -671,7 +673,7 @@ public final class InCallController extends CallsManagerListenerBase {
                        }
                    }
                }
            }.prepare(), Timeouts.getCallRemoveUnbindInCallServicesDelay(
            }.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
                            mContext.getContentResolver()));
        }
        call.removeListener(mCallListener);
@@ -842,12 +844,16 @@ public final class InCallController extends CallsManagerListenerBase {
     */
    private void unbindFromServices() {
        if (isBoundToServices()) {
            if (mInCallServiceConnection != null) {
                mInCallServiceConnection.disconnect();
                mInCallServiceConnection = null;
            }
            if (mNonUIInCallServiceConnections != null) {
                mNonUIInCallServiceConnections.disconnect();
                mNonUIInCallServiceConnections = null;
            }
        }
    }

    /**
     * Binds to all the UI-providing InCallService as well as system-implemented non-UI
@@ -1079,9 +1085,9 @@ public final class InCallController extends CallsManagerListenerBase {

        // Upon successful connection, send the state of the world to the service.
        List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls());
        if (!calls.isEmpty()) {
            Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
                    info.getComponentName());
        Log.i(this, "Adding %s calls to InCallService after onConnected: %s, including external " +
                "calls", calls.size(), info.getComponentName());
        int numCallsSent = 0;
        for (Call call : calls) {
            try {
                if (call.isExternalCall() && !info.isExternalCallsSupported()) {
@@ -1090,7 +1096,7 @@ public final class InCallController extends CallsManagerListenerBase {

                // Track the call if we don't already know about it.
                addCall(call);

                numCallsSent += 1;
                inCallService.addCall(ParcelableCallUtils.toParcelableCall(
                        call,
                        true /* includeVideoProvider */,
@@ -1104,9 +1110,7 @@ public final class InCallController extends CallsManagerListenerBase {
            inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
        } catch (RemoteException ignored) {
        }
        } else {
            return false;
        }
        Log.i(this, "%s calls sent to InCallService.", numCallsSent);
        Trace.endSection();
        return true;
    }
+1 −1
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ public class ParcelableCallUtils {
        }

        // If this is a single-SIM device, the "default SIM" will always be the only SIM.
        boolean isDefaultSmsAccount =
        boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
                phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
        if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
            capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
+4 −16
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ public final class Timeouts {
        public long getCallScreeningTimeoutMillis(ContentResolver cr) {
            return Timeouts.getCallScreeningTimeoutMillis(cr);
        }

        public long getCallRemoveUnbindInCallServicesDelay(ContentResolver cr) {
            return Timeouts.getCallRemoveUnbindInCallServicesDelay(cr);
        }
    }

    /** A prefix to use for all keys so to not clobber the global namespace. */
@@ -52,15 +56,6 @@ public final class Timeouts {
        return Settings.Secure.getLong(contentResolver, PREFIX + key, defaultValue);
    }

    /**
     * Returns the longest period, in milliseconds, to wait for the query for direct-to-voicemail
     * to complete. If the query goes beyond this timeout, the incoming call screen is shown to the
     * user.
     */
    public static long getDirectToVoicemailMillis(ContentResolver contentResolver) {
        return get(contentResolver, "direct_to_voicemail_ms", 500L);
    }

    /**
     * Returns the amount of time to wait before disconnecting a call that was canceled via
     * NEW_OUTGOING_CALL broadcast. This timeout allows apps which repost the call using a gateway
@@ -141,11 +136,4 @@ public final class Timeouts {
    public static long getCallScreeningTimeoutMillis(ContentResolver contentResolver) {
        return get(contentResolver, "call_screening_timeout", 5000L /* 5 seconds */);
    }

    /**
     * Returns the amount of time to wait for the block checker to allow or disallow a call.
     */
    public static long getBlockCheckTimeoutMillis(ContentResolver contentResolver) {
        return get(contentResolver, "block_check_timeout_millis", 500L);
    }
}
+65 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.telecom.tests;

import android.Manifest;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
@@ -29,6 +30,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
import android.telecom.InCallService;
import android.telecom.ParcelableCall;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.test.mock.MockContext;
@@ -46,6 +48,7 @@ import com.android.server.telecom.R;
import com.android.server.telecom.SystemStateProvider;
import com.android.server.telecom.TelecomServiceImpl.DefaultDialerManagerAdapter;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;

import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -53,6 +56,7 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.Collections;
import java.util.LinkedList;

import static org.mockito.Matchers.any;
@@ -79,6 +83,7 @@ public class InCallControllerTests extends TelecomTestCase {
    @Mock Resources mMockResources;
    @Mock MockContext mMockContext;
    @Mock DefaultDialerManagerAdapter mMockDefaultDialerAdapter;
    @Mock Timeouts.Adapter mTimeoutsAdapter;

    private static final int CURRENT_USER_ID = 900973;
    private static final String DEF_PKG = "defpkg";
@@ -100,7 +105,7 @@ public class InCallControllerTests extends TelecomTestCase {
        doReturn(SYS_PKG).when(mMockResources).getString(R.string.ui_default_package);
        doReturn(SYS_CLASS).when(mMockResources).getString(R.string.incall_default_class);
        mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
                mMockSystemStateProvider, mMockDefaultDialerAdapter);
                mMockSystemStateProvider, mMockDefaultDialerAdapter, mTimeoutsAdapter);
    }

    @Override
@@ -278,10 +283,14 @@ public class InCallControllerTests extends TelecomTestCase {
        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
        when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
        when(mMockCallsManager.getAudioState()).thenReturn(null);
        when(mMockCallsManager.canAddCall()).thenReturn(false);
        when(mMockCall.isIncoming()).thenReturn(false);
        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
        when(mMockCall.getIntentExtras()).thenReturn(callExtras);
        when(mMockCall.isExternalCall()).thenReturn(false);
        when(mMockCall.getConferenceableCalls()).thenReturn(Collections.emptyList());
        when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
                .thenReturn(DEF_PKG);
        when(mMockContext.bindServiceAsUser(
@@ -386,6 +395,61 @@ public class InCallControllerTests extends TelecomTestCase {
        assertEquals(DEF_CLASS, bindIntent.getComponent().getClassName());
    }

    /**
     * Make sure that if a call goes away before the in-call service finishes binding and another
     * call gets connected soon after, the new call will still be sent to the in-call service.
     */
    @MediumTest
    public void testUnbindDueToCallDisconnect() throws Exception {
        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
        when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
        when(mMockCall.isIncoming()).thenReturn(true);
        when(mMockCall.isExternalCall()).thenReturn(false);
        when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
                .thenReturn(DEF_PKG);
        when(mMockContext.bindServiceAsUser(
                any(Intent.class), any(ServiceConnection.class), anyInt(), any(UserHandle.class)))
                .thenReturn(true);
        when(mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(any(ContentResolver.class)))
                .thenReturn(500L);

        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
        mInCallController.bindToServices(mMockCall);

        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
        ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
                ArgumentCaptor.forClass(ServiceConnection.class);
        verify(mMockContext, times(1)).bindServiceAsUser(
                bindIntentCaptor.capture(),
                serviceConnectionCaptor.capture(),
                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                eq(UserHandle.CURRENT));

        // Pretend that the call has gone away.
        when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList());
        mInCallController.onCallRemoved(mMockCall);

        // Start the connection, make sure we don't unbind, and make sure that we don't send
        // anything to the in-call service yet.
        ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
        ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
        IBinder mockBinder = mock(IBinder.class);
        IInCallService mockInCallService = mock(IInCallService.class);
        when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);

        serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
        verify(mockInCallService).setInCallAdapter(any(IInCallAdapter.class));
        verify(mMockContext, never()).unbindService(serviceConnection);
        verify(mockInCallService, never()).addCall(any(ParcelableCall.class));

        // Now, we add in the call again and make sure that it's sent to the InCallService.
        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
        mInCallController.onCallAdded(mMockCall);
        verify(mockInCallService).addCall(any(ParcelableCall.class));
    }

    private void setupMocks(boolean isExternalCall) {
        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);