tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BluetoothManagerTest.java (11427B)


      1 /*
      2 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 package org.appspot.apprtc;
     12 
     13 import static org.junit.Assert.assertEquals;
     14 import static org.junit.Assert.assertNotNull;
     15 import static org.junit.Assert.assertNull;
     16 import static org.mockito.Mockito.mock;
     17 import static org.mockito.Mockito.never;
     18 import static org.mockito.Mockito.times;
     19 import static org.mockito.Mockito.verify;
     20 import static org.mockito.Mockito.when;
     21 
     22 import android.bluetooth.BluetoothAdapter;
     23 import android.bluetooth.BluetoothDevice;
     24 import android.bluetooth.BluetoothHeadset;
     25 import android.bluetooth.BluetoothProfile;
     26 import android.content.BroadcastReceiver;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.IntentFilter;
     30 import android.media.AudioManager;
     31 import android.util.Log;
     32 import androidx.test.core.app.ApplicationProvider;
     33 import java.util.ArrayList;
     34 import java.util.List;
     35 import org.appspot.apprtc.AppRTCBluetoothManager.State;
     36 import org.junit.Before;
     37 import org.junit.Test;
     38 import org.junit.runner.RunWith;
     39 import org.robolectric.annotation.Config;
     40 import org.robolectric.shadows.ShadowLog;
     41 import org.robolectric.RobolectricTestRunner;
     42 
     43 /**
     44 * Verifies basic behavior of the AppRTCBluetoothManager class.
     45 * Note that the test object uses an AppRTCAudioManager (injected in ctor),
     46 * but a mocked version is used instead. Hence, the parts "driven" by the AppRTC
     47 * audio manager are not included in this test.
     48 */
     49 @RunWith(RobolectricTestRunner.class)
     50 @Config(manifest = Config.NONE)
     51 public class BluetoothManagerTest {
     52  private static final String TAG = "BluetoothManagerTest";
     53  private static final String BLUETOOTH_TEST_DEVICE_NAME = "BluetoothTestDevice";
     54 
     55  private BroadcastReceiver bluetoothHeadsetStateReceiver;
     56  private BluetoothProfile.ServiceListener bluetoothServiceListener;
     57  private BluetoothHeadset mockedBluetoothHeadset;
     58  private BluetoothDevice mockedBluetoothDevice;
     59  private List<BluetoothDevice> mockedBluetoothDeviceList;
     60  private AppRTCBluetoothManager bluetoothManager;
     61  private AppRTCAudioManager mockedAppRtcAudioManager;
     62  private AudioManager mockedAudioManager;
     63  private Context context;
     64 
     65  @Before
     66  public void setUp() {
     67    ShadowLog.stream = System.out;
     68    context = ApplicationProvider.getApplicationContext();
     69    mockedAppRtcAudioManager = mock(AppRTCAudioManager.class);
     70    mockedAudioManager = mock(AudioManager.class);
     71    mockedBluetoothHeadset = mock(BluetoothHeadset.class);
     72    mockedBluetoothDevice = mock(BluetoothDevice.class);
     73    mockedBluetoothDeviceList = new ArrayList<BluetoothDevice>();
     74 
     75    // Simulate that bluetooth SCO audio is available by default.
     76    when(mockedAudioManager.isBluetoothScoAvailableOffCall()).thenReturn(true);
     77 
     78    // Create the test object and override protected methods for this test.
     79    bluetoothManager = new AppRTCBluetoothManager(context, mockedAppRtcAudioManager) {
     80      @Override
     81      protected AudioManager getAudioManager(Context context) {
     82        Log.d(TAG, "getAudioManager");
     83        return mockedAudioManager;
     84      }
     85 
     86      @Override
     87      protected void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
     88        Log.d(TAG, "registerReceiver");
     89        if (filter.hasAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)
     90            && filter.hasAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
     91          // Gives access to the real broadcast receiver so the test can use it.
     92          bluetoothHeadsetStateReceiver = receiver;
     93        }
     94      }
     95 
     96      @Override
     97      protected void unregisterReceiver(BroadcastReceiver receiver) {
     98        Log.d(TAG, "unregisterReceiver");
     99        if (receiver == bluetoothHeadsetStateReceiver) {
    100          bluetoothHeadsetStateReceiver = null;
    101        }
    102      }
    103 
    104      @Override
    105      protected boolean getBluetoothProfileProxy(
    106          Context context, BluetoothProfile.ServiceListener listener, int profile) {
    107        Log.d(TAG, "getBluetoothProfileProxy");
    108        if (profile == BluetoothProfile.HEADSET) {
    109          // Allows the test to access the real Bluetooth service listener object.
    110          bluetoothServiceListener = listener;
    111        }
    112        return true;
    113      }
    114 
    115      @Override
    116      protected boolean hasPermission(Context context, String permission) {
    117        Log.d(TAG, "hasPermission(" + permission + ")");
    118        // Ensure that the client asks for Bluetooth permission.
    119        return android.Manifest.permission.BLUETOOTH.equals(permission);
    120      }
    121 
    122      @Override
    123      protected void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
    124        // Do nothing in tests. No need to mock BluetoothAdapter.
    125      }
    126    };
    127  }
    128 
    129  // Verify that Bluetooth service listener for headset profile is properly initialized.
    130  @Test
    131  public void testBluetoothServiceListenerInitialized() {
    132    bluetoothManager.start();
    133    assertNotNull(bluetoothServiceListener);
    134    verify(mockedAppRtcAudioManager, never()).updateAudioDeviceState();
    135  }
    136 
    137  // Verify that broadcast receivers for Bluetooth SCO audio state and Bluetooth headset state
    138  // are properly registered and unregistered.
    139  @Test
    140  public void testBluetoothBroadcastReceiversAreRegistered() {
    141    bluetoothManager.start();
    142    assertNotNull(bluetoothHeadsetStateReceiver);
    143    bluetoothManager.stop();
    144    assertNull(bluetoothHeadsetStateReceiver);
    145  }
    146 
    147  // Verify that the Bluetooth manager starts and stops with correct states.
    148  @Test
    149  public void testBluetoothDefaultStartStopStates() {
    150    bluetoothManager.start();
    151    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    152    bluetoothManager.stop();
    153    assertEquals(State.UNINITIALIZED, bluetoothManager.getState());
    154  }
    155 
    156  // Verify correct state after receiving BluetoothServiceListener.onServiceConnected()
    157  // when no BT device is enabled.
    158  @Test
    159  public void testBluetoothServiceListenerConnectedWithNoHeadset() {
    160    bluetoothManager.start();
    161    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    162    simulateBluetoothServiceConnectedWithNoConnectedHeadset();
    163    verify(mockedAppRtcAudioManager, times(1)).updateAudioDeviceState();
    164    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    165  }
    166 
    167  // Verify correct state after receiving BluetoothServiceListener.onServiceConnected()
    168  // when one emulated (test) BT device is enabled. Android does not support more than
    169  // one connected BT headset.
    170  @Test
    171  public void testBluetoothServiceListenerConnectedWithHeadset() {
    172    bluetoothManager.start();
    173    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    174    simulateBluetoothServiceConnectedWithConnectedHeadset();
    175    verify(mockedAppRtcAudioManager, times(1)).updateAudioDeviceState();
    176    assertEquals(State.HEADSET_AVAILABLE, bluetoothManager.getState());
    177  }
    178 
    179  // Verify correct state after receiving BluetoothProfile.ServiceListener.onServiceDisconnected().
    180  @Test
    181  public void testBluetoothServiceListenerDisconnected() {
    182    bluetoothManager.start();
    183    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    184    simulateBluetoothServiceDisconnected();
    185    verify(mockedAppRtcAudioManager, times(1)).updateAudioDeviceState();
    186    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    187  }
    188 
    189  // Verify correct state after BluetoothServiceListener.onServiceConnected() and
    190  // the intent indicating that the headset is actually connected. Both these callbacks
    191  // results in calls to updateAudioDeviceState() on the AppRTC audio manager.
    192  // No BT SCO is enabled here to keep the test limited.
    193  @Test
    194  public void testBluetoothHeadsetConnected() {
    195    bluetoothManager.start();
    196    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    197    simulateBluetoothServiceConnectedWithConnectedHeadset();
    198    simulateBluetoothHeadsetConnected();
    199    verify(mockedAppRtcAudioManager, times(2)).updateAudioDeviceState();
    200    assertEquals(State.HEADSET_AVAILABLE, bluetoothManager.getState());
    201  }
    202 
    203  // Verify correct state sequence for a case when a BT headset is available,
    204  // followed by BT SCO audio being enabled and then stopped.
    205  @Test
    206  public void testBluetoothScoAudioStartAndStop() {
    207    bluetoothManager.start();
    208    assertEquals(State.HEADSET_UNAVAILABLE, bluetoothManager.getState());
    209    simulateBluetoothServiceConnectedWithConnectedHeadset();
    210    assertEquals(State.HEADSET_AVAILABLE, bluetoothManager.getState());
    211    bluetoothManager.startScoAudio();
    212    assertEquals(State.SCO_CONNECTING, bluetoothManager.getState());
    213    simulateBluetoothScoConnectionConnected();
    214    assertEquals(State.SCO_CONNECTED, bluetoothManager.getState());
    215    bluetoothManager.stopScoAudio();
    216    simulateBluetoothScoConnectionDisconnected();
    217    assertEquals(State.SCO_DISCONNECTING,bluetoothManager.getState());
    218    bluetoothManager.stop();
    219    assertEquals(State.UNINITIALIZED, bluetoothManager.getState());
    220    verify(mockedAppRtcAudioManager, times(3)).updateAudioDeviceState();
    221  }
    222 
    223  /**
    224   * Private helper methods.
    225   */
    226  private void simulateBluetoothServiceConnectedWithNoConnectedHeadset() {
    227    mockedBluetoothDeviceList.clear();
    228    when(mockedBluetoothHeadset.getConnectedDevices()).thenReturn(mockedBluetoothDeviceList);
    229    bluetoothServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mockedBluetoothHeadset);
    230    // In real life, the AppRTC audio manager makes this call.
    231    bluetoothManager.updateDevice();
    232  }
    233 
    234  private void simulateBluetoothServiceConnectedWithConnectedHeadset() {
    235    mockedBluetoothDeviceList.clear();
    236    mockedBluetoothDeviceList.add(mockedBluetoothDevice);
    237    when(mockedBluetoothHeadset.getConnectedDevices()).thenReturn(mockedBluetoothDeviceList);
    238    when(mockedBluetoothDevice.getName()).thenReturn(BLUETOOTH_TEST_DEVICE_NAME);
    239    bluetoothServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mockedBluetoothHeadset);
    240    // In real life, the AppRTC audio manager makes this call.
    241    bluetoothManager.updateDevice();
    242  }
    243 
    244  private void simulateBluetoothServiceDisconnected() {
    245    bluetoothServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
    246  }
    247 
    248  private void simulateBluetoothHeadsetConnected() {
    249    Intent intent = new Intent();
    250    intent.setAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
    251    intent.putExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_CONNECTED);
    252    bluetoothHeadsetStateReceiver.onReceive(context, intent);
    253  }
    254 
    255  private void simulateBluetoothScoConnectionConnected() {
    256    Intent intent = new Intent();
    257    intent.setAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
    258    intent.putExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_CONNECTED);
    259    bluetoothHeadsetStateReceiver.onReceive(context, intent);
    260  }
    261 
    262  private void simulateBluetoothScoConnectionDisconnected() {
    263    Intent intent = new Intent();
    264    intent.setAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
    265    intent.putExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
    266    bluetoothHeadsetStateReceiver.onReceive(context, intent);
    267  }
    268 }