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

Commit f4b940d4 authored by Hyundo Moon's avatar Hyundo Moon Committed by Gerrit Code Review
Browse files

Merge "Add PbapClientServiceTest"

parents 3977fa6a 98771679
Loading
Loading
Loading
Loading
+20 −8
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ 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.Utils;
import com.android.bluetooth.btservice.AdapterService;
@@ -41,6 +42,7 @@ import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hfpclient.HfpClientConnectionService;
import com.android.bluetooth.sdp.SdpManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.SynchronousResultReceiver;

import java.util.ArrayList;
@@ -69,10 +71,12 @@ public class PbapClientService extends ProfileService {

    // MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices.
    private static final int MAXIMUM_DEVICES = 10;
    private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap =
    @VisibleForTesting
    Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap =
            new ConcurrentHashMap<>();
    private static PbapClientService sPbapClientService;
    private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver();
    @VisibleForTesting
    PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver();
    private int mSdpHandle = -1;

    private DatabaseManager mDatabaseManager;
@@ -162,6 +166,7 @@ public class PbapClientService extends ProfileService {
        for (PbapClientStateMachine pbapClientStateMachine : mPbapClientStateMachineMap.values()) {
            pbapClientStateMachine.doQuit();
        }
        mPbapClientStateMachineMap.clear();
        cleanupAuthenicationService();
        setComponentAvailable(AUTHENTICATOR_SERVICE, false);
        return true;
@@ -243,7 +248,8 @@ public class PbapClientService extends ProfileService {
                + CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME + "=?";
        String[] selectionArgs = new String[]{accountName, componentName.flattenToString()};
        try {
            getContentResolver().delete(CallLog.Calls.CONTENT_URI, selectionFilter, selectionArgs);
            BluetoothMethodProxy.getInstance().contentResolverDelete(getContentResolver(),
                    CallLog.Calls.CONTENT_URI, selectionFilter, selectionArgs);
        } catch (IllegalArgumentException e) {
            Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
        }
@@ -278,7 +284,8 @@ public class PbapClientService extends ProfileService {
    }


    private class PbapBroadcastReceiver extends BroadcastReceiver {
    @VisibleForTesting
    class PbapBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
@@ -314,7 +321,8 @@ public class PbapClientService extends ProfileService {
    /**
     * Handler for incoming service calls
     */
    private static class BluetoothPbapClientBinder extends IBluetoothPbapClient.Stub
    @VisibleForTesting
    static class BluetoothPbapClientBinder extends IBluetoothPbapClient.Stub
            implements IProfileServiceBinder {
        private PbapClientService mService;

@@ -329,6 +337,9 @@ public class PbapClientService extends ProfileService {

        @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
        private PbapClientService getService(AttributionSource source) {
            if (Utils.isInstrumentationTestMode()) {
                return mService;
            }
            if (!Utils.checkServiceAvailable(mService, TAG)
                    || !Utils.checkCallerIsSystemOrActiveOrManagedUser(mService, TAG)
                    || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) {
@@ -461,7 +472,8 @@ public class PbapClientService extends ProfileService {
        return sPbapClientService;
    }

    private static synchronized void setPbapClientService(PbapClientService instance) {
    @VisibleForTesting
    static synchronized void setPbapClientService(PbapClientService instance) {
        if (VDBG) {
            Log.v(TAG, "setPbapClientService(): set to: " + instance);
        }
@@ -511,7 +523,6 @@ public class PbapClientService extends ProfileService {
        if (pbapClientStateMachine != null) {
            pbapClientStateMachine.disconnect(device);
            return true;

        } else {
            Log.w(TAG, "disconnect() called on unconnected device.");
            return false;
@@ -523,7 +534,8 @@ public class PbapClientService extends ProfileService {
        return getDevicesMatchingConnectionStates(desiredStates);
    }

    private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    @VisibleForTesting
    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(0);
        for (Map.Entry<BluetoothDevice, PbapClientStateMachine> stateMachineEntry :
                mPbapClientStateMachineMap
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ import com.android.internal.util.StateMachine;
import java.util.ArrayList;
import java.util.List;

final class PbapClientStateMachine extends StateMachine {
class PbapClientStateMachine extends StateMachine {
    private static final boolean DBG = false; //Utils.DBG;
    private static final String TAG = "PbapClientStateMachine";

+271 −1
Original line number Diff line number Diff line
@@ -15,21 +15,36 @@
 */
package com.android.bluetooth.pbapclient;

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.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.provider.CallLog;

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

import com.android.bluetooth.R;
import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.x.com.android.modules.utils.SynchronousResultReceiver;

import org.junit.After;
import org.junit.Assert;
@@ -38,15 +53,19 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@MediumTest
@RunWith(AndroidJUnit4.class)
public class PbapClientServiceTest {
    private static final String REMOTE_DEVICE_ADDRESS = "00:00:00:00:00:00";

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

    @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();

@@ -69,6 +88,7 @@ public class PbapClientServiceTest {
        // Try getting the Bluetooth adapter
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        Assert.assertNotNull(mAdapter);
        mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
    }

    @After
@@ -80,10 +100,260 @@ public class PbapClientServiceTest {
        mService = PbapClientService.getPbapClientService();
        Assert.assertNull(mService);
        TestUtils.clearAdapterService(mAdapterService);
        BluetoothMethodProxy.setInstanceForTesting(null);
    }

    @Test
    public void testInitialize() {
        Assert.assertNotNull(PbapClientService.getPbapClientService());
    }

    @Test
    public void testSetPbapClientService_withNull() {
        PbapClientService.setPbapClientService(null);

        assertThat(PbapClientService.getPbapClientService()).isNull();
    }

    @Test
    public void dump_callsStateMachineDump() {
        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
        StringBuilder builder = new StringBuilder();

        mService.dump(builder);

        verify(sm).dump(builder);
    }

    @Test
    public void testSetConnectionPolicy_withNullDevice_throwsIAE() {
        assertThrows(IllegalArgumentException.class, () -> mService.setConnectionPolicy(
                null, BluetoothProfile.CONNECTION_POLICY_ALLOWED));
    }

    @Test
    public void testSetConnectionPolicy() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
        when(mDatabaseManager.setProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.PBAP_CLIENT, connectionPolicy)).thenReturn(true);

        assertThat(mService.setConnectionPolicy(mRemoteDevice, connectionPolicy)).isTrue();
    }

    @Test
    public void testGetConnectionPolicy_withNullDevice_throwsIAE() {
        assertThrows(IllegalArgumentException.class, () -> mService.getConnectionPolicy(null));
    }

    @Test
    public void testGetConnectionPolicy() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.PBAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.getConnectionPolicy(mRemoteDevice)).isEqualTo(connectionPolicy);
    }

    @Test
    public void testConnect_withNullDevice_throwsIAE() {
        assertThrows(IllegalArgumentException.class, () -> mService.connect(null));
    }

    @Test
    public void testConnect_whenPolicyIsForbidden_returnsFalse() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.PBAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.connect(mRemoteDevice)).isFalse();
    }

    @Test
    public void testConnect_whenPolicyIsAllowed_returnsTrue() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.PBAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.connect(mRemoteDevice)).isTrue();
    }

    @Test
    public void testDisconnect_withNullDevice_throwsIAE() {
        assertThrows(IllegalArgumentException.class, () -> mService.disconnect(null));
    }

    @Test
    public void testDisconnect_whenNotConnected_returnsFalse() {
        assertThat(mService.disconnect(mRemoteDevice)).isFalse();
    }

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

        assertThat(mService.disconnect(mRemoteDevice)).isTrue();

        verify(sm).disconnect(mRemoteDevice);
    }

    @Test
    public void testGetConnectionState_whenNotConnected() {
        assertThat(mService.getConnectionState(mRemoteDevice))
                .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);
    }

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

        assertThat(mService.getConnectedDevices()).contains(mRemoteDevice);
    }

    @Test
    public void binder_connect_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.connect(mRemoteDevice, null, SynchronousResultReceiver.get());

        verify(mockService).connect(mRemoteDevice);
    }

    @Test
    public void binder_disconnect_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.disconnect(mRemoteDevice, null, SynchronousResultReceiver.get());

        verify(mockService).disconnect(mRemoteDevice);
    }

    @Test
    public void binder_getConnectedDevices_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.getConnectedDevices(null, SynchronousResultReceiver.get());

        verify(mockService).getConnectedDevices();
    }

    @Test
    public void binder_getDevicesMatchingConnectionStates_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        int[] states = new int[] {BluetoothProfile.STATE_CONNECTED};
        binder.getDevicesMatchingConnectionStates(states, null, SynchronousResultReceiver.get());

        verify(mockService).getDevicesMatchingConnectionStates(states);
    }

    @Test
    public void binder_getConnectionState_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.getConnectionState(mRemoteDevice, null, SynchronousResultReceiver.get());

        verify(mockService).getConnectionState(mRemoteDevice);
    }

    @Test
    public void binder_setConnectionPolicy_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
        binder.setConnectionPolicy(mRemoteDevice, connectionPolicy,
                null, SynchronousResultReceiver.get());

        verify(mockService).setConnectionPolicy(mRemoteDevice, connectionPolicy);
    }

    @Test
    public void binder_getConnectionPolicy_callsServiceMethod() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.getConnectionPolicy(mRemoteDevice, null, SynchronousResultReceiver.get());

        verify(mockService).getConnectionPolicy(mRemoteDevice);
    }

    @Test
    public void binder_cleanUp_doesNotCrash() {
        PbapClientService mockService = mock(PbapClientService.class);
        PbapClientService.BluetoothPbapClientBinder binder =
                new PbapClientService.BluetoothPbapClientBinder(mockService);

        binder.cleanup();
    }

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

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

        verify(sm).disconnect(mRemoteDevice);
    }

    @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();
    }

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

        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
        mService.mPbapBroadcastReceiver.onReceive(mService, intent);

        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());
    }
}