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

Commit f449d647 authored by Hyundo Moon's avatar Hyundo Moon Committed by Android (Google) Code Review
Browse files

Merge "Add PbapClientServiceTest" into tm-qpr-dev

parents 446553ae 8311d24a
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());
    }
}