Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settingslib.bluetooth;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 
     21 import static org.mockito.ArgumentMatchers.any;
     22 import static org.mockito.ArgumentMatchers.anyInt;
     23 import static org.mockito.Mockito.never;
     24 import static org.mockito.Mockito.spy;
     25 import static org.mockito.Mockito.verify;
     26 import static org.mockito.Mockito.when;
     27 
     28 import android.bluetooth.BluetoothA2dp;
     29 import android.bluetooth.BluetoothAdapter;
     30 import android.bluetooth.BluetoothDevice;
     31 import android.bluetooth.BluetoothHeadset;
     32 import android.bluetooth.BluetoothHearingAid;
     33 import android.bluetooth.BluetoothPan;
     34 import android.bluetooth.BluetoothProfile;
     35 import android.bluetooth.BluetoothUuid;
     36 import android.content.Context;
     37 import android.content.Intent;
     38 import android.os.ParcelUuid;
     39 
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 
     43 import org.junit.Before;
     44 import org.junit.Test;
     45 import org.junit.runner.RunWith;
     46 import org.mockito.Mock;
     47 import org.mockito.MockitoAnnotations;
     48 import org.robolectric.RobolectricTestRunner;
     49 import org.robolectric.RuntimeEnvironment;
     50 import org.robolectric.annotation.Config;
     51 
     52 @RunWith(RobolectricTestRunner.class)
     53 @Config(resourceDir = "../../res")
     54 public class LocalBluetoothProfileManagerTest {
     55     @Mock
     56     private CachedBluetoothDeviceManager mDeviceManager;
     57     @Mock
     58     private BluetoothEventManager mEventManager;
     59     @Mock
     60     private LocalBluetoothAdapter mAdapter;
     61     @Mock
     62     private BluetoothDevice mDevice;
     63     @Mock
     64     private CachedBluetoothDevice mCachedBluetoothDevice;
     65 
     66     private Context mContext;
     67     private LocalBluetoothProfileManager mProfileManager;
     68     private Intent mIntent;
     69 
     70     @Before
     71     public void setUp() {
     72         MockitoAnnotations.initMocks(this);
     73         mContext = spy(RuntimeEnvironment.application);
     74         mEventManager = spy(new BluetoothEventManager(mAdapter,
     75                 mDeviceManager, mContext));
     76         when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
     77         when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);
     78     }
     79 
     80     /**
     81      * Verify HID and HID Device profiles are not null without running updateUuids()
     82      */
     83     @Test
     84     public void constructor_initiateHidAndHidDeviceProfile() {
     85         mProfileManager =
     86                 new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
     87 
     88         assertThat(mProfileManager.getHidProfile()).isNotNull();
     89         assertThat(mProfileManager.getHidDeviceProfile()).isNotNull();
     90     }
     91 
     92     /**
     93      * Verify updateLocalProfiles() for a local A2DP source adds A2dpProfile
     94      */
     95     @Test
     96     public void updateLocalProfiles_addA2dpToLocalProfiles() {
     97         mProfileManager =
     98                 new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
     99         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
    100         assertThat(mProfileManager.getA2dpProfile()).isNull();
    101         assertThat(mProfileManager.getHeadsetProfile()).isNull();
    102 
    103         ParcelUuid[] uuids = mAdapter.getUuids();
    104         mProfileManager.updateLocalProfiles(uuids);
    105 
    106         assertThat(mProfileManager.getA2dpProfile()).isNotNull();
    107         assertThat(mProfileManager.getHeadsetProfile()).isNull();
    108     }
    109 
    110     /**
    111      * Verify updateProfiles() for a remote HID device updates profiles and removedProfiles
    112      */
    113     @Test
    114     public void updateProfiles_addHidProfileForRemoteDevice() {
    115         mProfileManager =
    116                 new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
    117         ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.Hid};
    118         ParcelUuid[] localUuids = new ParcelUuid[]{};
    119         List<LocalBluetoothProfile> profiles = new ArrayList<>();
    120         List<LocalBluetoothProfile> removedProfiles = new ArrayList<>();
    121 
    122         mProfileManager.updateProfiles(uuids, localUuids, profiles, removedProfiles, false,
    123                 mDevice);
    124 
    125         assertThat(mProfileManager.getHidProfile()).isNotNull();
    126         assertThat(profiles.contains(mProfileManager.getHidProfile())).isTrue();
    127         assertThat(removedProfiles.contains(mProfileManager.getHidProfile())).isFalse();
    128     }
    129 
    130     /**
    131      * Verify BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
    132      * profile connection state changed callback
    133      */
    134     @Test
    135     public void stateChangedHandler_receiveA2dpConnectionStateChanged_shouldDispatchCallback() {
    136         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
    137         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    138                 mEventManager);
    139         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    140         // LocalBluetoothProfileManager created.
    141         mEventManager.setReceiverHandler(null);
    142         mIntent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
    143         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    144         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    145         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    146 
    147         mContext.sendBroadcast(mIntent);
    148 
    149         verify(mEventManager).dispatchProfileConnectionStateChanged(
    150                 mCachedBluetoothDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
    151     }
    152 
    153     /**
    154      * Verify BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
    155      * profile connection state changed callback
    156      */
    157     @Test
    158     public void stateChangedHandler_receiveHeadsetConnectionStateChanged_shouldDispatchCallback() {
    159         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.Handsfree_AG});
    160         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    161                 mEventManager);
    162         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    163         // LocalBluetoothProfileManager created.
    164         mEventManager.setReceiverHandler(null);
    165         mIntent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
    166         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    167         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    168         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    169 
    170         mContext.sendBroadcast(mIntent);
    171 
    172         verify(mEventManager).dispatchProfileConnectionStateChanged(mCachedBluetoothDevice,
    173                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEADSET);
    174     }
    175 
    176     /**
    177      * Verify BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
    178      * profile connection state changed callback
    179      */
    180     @Test
    181     public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldDispatchCallback() {
    182         ArrayList<Integer> supportProfiles = new ArrayList<>();
    183         supportProfiles.add(BluetoothProfile.HEARING_AID);
    184         when(mAdapter.getSupportedProfiles()).thenReturn(supportProfiles);
    185         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.HearingAid});
    186         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    187                 mEventManager);
    188         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    189         // LocalBluetoothProfileManager created.
    190         mEventManager.setReceiverHandler(null);
    191         mIntent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
    192         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    193         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    194         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    195 
    196         mContext.sendBroadcast(mIntent);
    197 
    198         verify(mEventManager).dispatchProfileConnectionStateChanged(mCachedBluetoothDevice,
    199                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
    200     }
    201 
    202     /**
    203      * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
    204      * profile connection state changed callback
    205      */
    206     @Test
    207     public void stateChangedHandler_receivePanConnectionStateChanged_shouldNotDispatchCallback() {
    208         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
    209         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    210                 mEventManager);
    211         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    212         // LocalBluetoothProfileManager created.
    213         mEventManager.setReceiverHandler(null);
    214         mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
    215         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    216         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    217         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    218 
    219         mContext.sendBroadcast(mIntent);
    220 
    221         verify(mEventManager).dispatchProfileConnectionStateChanged(
    222                 any(CachedBluetoothDevice.class), anyInt(), anyInt());
    223     }
    224 
    225     /**
    226      * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent without uuids will not dispatch to
    227      * handler and refresh CachedBluetoothDevice
    228      */
    229     @Test
    230     public void stateChangedHandler_receivePanConnectionStateChangedWithoutUuid_shouldNotRefresh() {
    231         when(mAdapter.getUuids()).thenReturn(null);
    232         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    233                 mEventManager);
    234         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    235         // LocalBluetoothProfileManager created.
    236         mEventManager.setReceiverHandler(null);
    237         mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
    238         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    239         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    240         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    241 
    242         mContext.sendBroadcast(mIntent);
    243 
    244         verify(mCachedBluetoothDevice).refresh();
    245     }
    246 
    247     /**
    248      * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuids will dispatch to
    249      * handler and refresh CachedBluetoothDevice
    250      */
    251     @Test
    252     public void stateChangedHandler_receivePanConnectionStateChangedWithUuids_shouldRefresh() {
    253         when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
    254         mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
    255                 mEventManager);
    256         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
    257         // LocalBluetoothProfileManager created.
    258         mEventManager.setReceiverHandler(null);
    259         mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
    260         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
    261         mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
    262         mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
    263 
    264         mContext.sendBroadcast(mIntent);
    265 
    266         verify(mCachedBluetoothDevice).refresh();
    267     }
    268 }
    269