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

Commit 7edc0deb authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Clean up PbapClientServiceTest" into main

parents 4fc751aa 6dc72243
Loading
Loading
Loading
Loading
+5 −12
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import android.provider.CallLog;
import android.sysprop.BluetoothProperties;
import android.util.Log;

import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.R;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
@@ -297,11 +296,10 @@ public class PbapClientService extends ProfileService {
        }
    }

    private void removeHfpCallLog(String accountName, Context context) {
    private void removeHfpCallLog(String accountName) {
        Log.d(TAG, "Removing call logs from " + accountName);
        // Delete call logs belonging to accountName==BD_ADDR that also match
        // component name "hfpclient".
        ComponentName componentName = new ComponentName(context, HfpClientConnectionService.class);
        // Delete call logs belonging to accountName==BD_ADDR that also match component "hfpclient"
        ComponentName componentName = new ComponentName(this, HfpClientConnectionService.class);
        String selectionFilter =
                CallLog.Calls.PHONE_ACCOUNT_ID
                        + "=? AND "
@@ -309,12 +307,7 @@ public class PbapClientService extends ProfileService {
                        + "=?";
        String[] selectionArgs = new String[] {accountName, componentName.flattenToString()};
        try {
            BluetoothMethodProxy.getInstance()
                    .contentResolverDelete(
                            getContentResolver(),
                            CallLog.Calls.CONTENT_URI,
                            selectionFilter,
                            selectionArgs);
            getContentResolver().delete(CallLog.Calls.CONTENT_URI, selectionFilter, selectionArgs);
        } catch (IllegalArgumentException e) {
            Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
        }
@@ -345,7 +338,7 @@ public class PbapClientService extends ProfileService {
            Log.d(TAG, "Received intent to disconnect HFP with " + device);
            // HFP client stores entries in calllog.db by BD_ADDR and component name
            // Using the current Service as the context.
            removeHfpCallLog(device.getAddress(), this);
            removeHfpCallLog(device.getAddress());
        }
    }

+149 −86
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -27,19 +29,26 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.Intent;
import android.net.Uri;
import android.os.Looper;
import android.provider.CallLog;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
@@ -62,47 +71,72 @@ public class PbapClientServiceTest {

    private PbapClientService mService = null;
    private BluetoothAdapter mAdapter = null;
    private Context mTargetContext;
    private BluetoothDevice mRemoteDevice;
    boolean mIsAdapterServiceSet;
    boolean mIsPbapClientServiceStarted;

    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock private AdapterService mAdapterService;

    @Mock private Context mMockContext;
    @Mock private AdapterService mMockAdapterService;
    @Mock private DatabaseManager mDatabaseManager;
    @Mock private PackageManager mMockPackageManager;
    private MockContentResolver mMockContentResolver;
    private MockCallLogProvider mMockCallLogProvider;
    @Mock private Resources mMockResources;
    @Mock private AccountManager mMockAccountManager;

    @Before
    public void setUp() throws Exception {
        mTargetContext = InstrumentationRegistry.getTargetContext();
        TestUtils.setAdapterService(mAdapterService);
        mIsAdapterServiceSet = true;
        doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
        mService = new PbapClientService(mTargetContext);
        mService.start();
        mService.setAvailable(true);
        mIsPbapClientServiceStarted = true;
        // Try getting the Bluetooth adapter
        TestUtils.setAdapterService(mMockAdapterService);
        doReturn(mDatabaseManager).when(mMockAdapterService).getDatabase();

        doReturn("").when(mMockContext).getPackageName();
        doReturn(mMockPackageManager).when(mMockContext).getPackageManager();

        doReturn(mMockResources).when(mMockContext).getResources();
        doReturn(Utils.ACCOUNT_TYPE).when(mMockResources).getString(anyInt());

        mMockContentResolver = new MockContentResolver();
        mMockCallLogProvider = new MockCallLogProvider();
        mMockContentResolver.addProvider(CallLog.AUTHORITY, mMockCallLogProvider);
        doReturn(mMockContentResolver).when(mMockContext).getContentResolver();

        doReturn(AccountManager.VISIBILITY_VISIBLE)
                .when(mMockAccountManager)
                        .getAccountVisibility(any(Account.class), anyString());
        doReturn(new Account[]{})
                .when(mMockAccountManager)
                        .getAccountsByType(eq(Utils.ACCOUNT_TYPE));
        TestUtils.mockGetSystemService(
                mMockContext,
                Context.ACCOUNT_SERVICE,
                AccountManager.class,
                mMockAccountManager);

        mAdapter = BluetoothAdapter.getDefaultAdapter();
        Assert.assertNotNull(mAdapter);
        mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);

        if (Looper.myLooper() == null) {
            Looper.prepare();
        }

        mService = new PbapClientService(mMockContext);
        mService.start();
        mService.setAvailable(true);
    }

    @After
    public void tearDown() throws Exception {
        if (!mIsAdapterServiceSet) {
            return;
        }
        if (mIsPbapClientServiceStarted) {
        if (mService != null) {
            mService.stop();
            mService = PbapClientService.getPbapClientService();
            Assert.assertNull(mService);
            mService = null;
        }
        TestUtils.clearAdapterService(mAdapterService);
        BluetoothMethodProxy.setInstanceForTesting(null);
        TestUtils.clearAdapterService(mMockAdapterService);
    }

    // *********************************************************************************************
    // * Initialize Service
    // *********************************************************************************************

    @Test
    public void testInitialize() {
        Assert.assertNotNull(PbapClientService.getPbapClientService());
@@ -115,17 +149,81 @@ public class PbapClientServiceTest {
        assertThat(PbapClientService.getPbapClientService()).isNull();
    }

    // *********************************************************************************************
    // * Incoming Events
    // *********************************************************************************************

    // ACL state changes from AdapterService

    @Test
    public void dump_callsStateMachineDump() {
    public void aclDisconnected_withLeTransport_doesNotCallDisconnect() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
        StringBuilder builder = new StringBuilder();
        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);

        mService.dump(builder);
        mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_LE);
        TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());

        verify(sm).dump(builder);
        verify(sm, never()).disconnect(mRemoteDevice);
    }

    @Test
    public void aclDisconnected_withBrEdrTransport_callsDisconnect() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);

        mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_BREDR);
        TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());

        verify(sm).disconnect(mRemoteDevice);
    }

    // User unlock state changes

    @Test
    public void broadcastReceiver_withActionUserUnlocked_callsTryDownloadIfConnected() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);

        Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        mService.mPbapBroadcastReceiver.onReceive(mService, intent);

        verify(sm).tryDownloadIfConnected();
    }

    // HFP HF State changes

    @Test
    public void headsetClientConnectionStateChanged_hfpCallLogIsRemoved() {
        mService.handleHeadsetClientConnectionStateChanged(
                mRemoteDevice,
                BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);

        assertThat(mMockCallLogProvider.getMostRecentlyDeletedDevice())
                .isEqualTo(mRemoteDevice.getAddress());
    }

    // Device state machines cleans up

    @Test
    public void cleanUpDevice() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);

        mService.cleanupDevice(mRemoteDevice);

        assertThat(mService.mPbapClientStateMachineMap).doesNotContainKey(mRemoteDevice);
    }

    // *********************************************************************************************
    // * API Methods
    // *********************************************************************************************

    @Test
    public void testSetConnectionPolicy_withNullDevice_throwsIAE() {
        assertThrows(
@@ -211,73 +309,38 @@ public class PbapClientServiceTest {
                .isEqualTo(BluetoothProfile.STATE_DISCONNECTED);
    }

    @Test
    public void cleanUpDevice() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);

        mService.cleanupDevice(mRemoteDevice);

        assertThat(mService.mPbapClientStateMachineMap).doesNotContainKey(mRemoteDevice);
    }
    // *********************************************************************************************
    // * Debug/Dump/toString()
    // *********************************************************************************************

    @Test
    public void broadcastReceiver_withActionAclDisconnectedLeTransport_doesNotCallDisconnect() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
    public void dump_callsStateMachineDump() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
        StringBuilder builder = new StringBuilder();

        mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_LE);
        TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
        mService.dump(builder);

        verify(sm, never()).disconnect(mRemoteDevice);
        verify(sm).dump(builder);
    }

    @Test
    public void broadcastReceiver_withActionAclDisconnectedBrEdrTransport_callsDisconnect() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
    // *********************************************************************************************
    // * Fake Call Log Provider
    // *********************************************************************************************

        mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_BREDR);
        TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
    private static class MockCallLogProvider extends MockContentProvider {
        private String mMostRecentlyDeletedDevice = null;

        verify(sm).disconnect(mRemoteDevice);
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            if (selectionArgs != null && selectionArgs.length > 0) {
                mMostRecentlyDeletedDevice = selectionArgs[0];
            }

    @Test
    public void broadcastReceiver_withActionUserUnlocked_callsTryDownloadIfConnected() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);

        Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        mService.mPbapBroadcastReceiver.onReceive(mService, intent);

        verify(sm).tryDownloadIfConnected();
            return 0;
        }

    @Test
    public void headsetClientConnectionStateChanged_hfpCallLogIsRemoved() {
        BluetoothMethodProxy methodProxy = spy(BluetoothMethodProxy.getInstance());
        BluetoothMethodProxy.setInstanceForTesting(methodProxy);

        mService.handleHeadsetClientConnectionStateChanged(
                mRemoteDevice,
                BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);

        ArgumentCaptor<Object> selectionArgsCaptor = ArgumentCaptor.forClass(Object.class);
        verify(methodProxy)
                .contentResolverDelete(
                        any(),
                        eq(CallLog.Calls.CONTENT_URI),
                        any(),
                        (String[]) selectionArgsCaptor.capture());

        assertThat(((String[]) selectionArgsCaptor.getValue())[0])
                .isEqualTo(mRemoteDevice.getAddress());
        public String getMostRecentlyDeletedDevice() {
            return mMostRecentlyDeletedDevice;
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ public class Utils {
    public static final String OUTGOING_CALL = "DIALED";
    private static final String CALL_HISTORY = "X-IRMC-CALL-DATETIME";

    public static final String ACCOUNT_TYPE =
            "com.android.bluetooth.pbapclient";

    /**
     * Group a list of VCard entries or Call History entries into a full phonebook
     *