blob: 23aac3991ca736fc1086e6d12f702f482d012fed [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.bluetooth.btservice;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.hfp.HeadsetService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
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 SilenceDeviceManagerTest {
private BluetoothAdapter mAdapter;
private Context mContext;
private BluetoothDevice mTestDevice;
private SilenceDeviceManager mSilenceDeviceManager;
private HandlerThread mHandlerThread;
private Looper mLooper;
private static final String TEST_BT_ADDR = "11:22:33:44:55:66";
private int mVerifyCount = 0;
@Mock private AdapterService mAdapterService;
@Mock private ServiceFactory mServiceFactory;
@Mock private A2dpService mA2dpService;
@Mock private HeadsetService mHeadsetService;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
// Set up mocks and test assets
MockitoAnnotations.initMocks(this);
TestUtils.setAdapterService(mAdapterService);
when(mServiceFactory.getA2dpService()).thenReturn(mA2dpService);
when(mServiceFactory.getHeadsetService()).thenReturn(mHeadsetService);
// Get devices for testing
mTestDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(TEST_BT_ADDR);
mHandlerThread = new HandlerThread("SilenceManagerTestHandlerThread");
mHandlerThread.start();
mLooper = mHandlerThread.getLooper();
mSilenceDeviceManager = new SilenceDeviceManager(mAdapterService, mServiceFactory,
mLooper);
mSilenceDeviceManager.start();
}
@After
public void tearDown() throws Exception {
mSilenceDeviceManager.cleanup();
mHandlerThread.quit();
TestUtils.clearAdapterService(mAdapterService);
}
@Test
public void testSetGetDeviceSilence() {
testSetGetDeviceSilenceConnectedCase(false, true);
testSetGetDeviceSilenceConnectedCase(false, false);
testSetGetDeviceSilenceConnectedCase(true, true);
testSetGetDeviceSilenceConnectedCase(true, false);
testSetGetDeviceSilenceDisconnectedCase(false);
testSetGetDeviceSilenceDisconnectedCase(true);
}
void testSetGetDeviceSilenceConnectedCase(boolean wasSilenced, boolean enableSilence) {
ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
doReturn(true).when(mA2dpService).setSilenceMode(mTestDevice, enableSilence);
doReturn(true).when(mHeadsetService).setSilenceMode(mTestDevice, enableSilence);
// Send A2DP/HFP connected intent
a2dpConnected(mTestDevice);
headsetConnected(mTestDevice);
// Set pre-state for mSilenceDeviceManager
if (wasSilenced) {
Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, true));
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
verify(mAdapterService, times(++mVerifyCount)).sendBroadcastAsUser(
intentArgument.capture(), eq(UserHandle.ALL),
eq(BLUETOOTH_CONNECT), any(Bundle.class));
}
// Set silence state and check whether state changed successfully
Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence));
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
Assert.assertEquals(enableSilence, mSilenceDeviceManager.getSilenceMode(mTestDevice));
// Check for silence state changed intent
if (wasSilenced != enableSilence) {
verify(mAdapterService, times(++mVerifyCount)).sendBroadcastAsUser(
intentArgument.capture(), eq(UserHandle.ALL),
eq(BLUETOOTH_CONNECT), any(Bundle.class));
verifySilenceStateIntent(intentArgument.getValue());
}
// Remove test devices
a2dpDisconnected(mTestDevice);
headsetDisconnected(mTestDevice);
Assert.assertFalse(mSilenceDeviceManager.getSilenceMode(mTestDevice));
if (enableSilence) {
// If the silence mode is enabled, it should be automatically disabled
// after device is disconnected.
verify(mAdapterService, times(++mVerifyCount)).sendBroadcastAsUser(
intentArgument.capture(), eq(UserHandle.ALL),
eq(BLUETOOTH_CONNECT), any(Bundle.class));
}
}
void testSetGetDeviceSilenceDisconnectedCase(boolean enableSilence) {
ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
// Set silence mode and it should stay disabled
Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence));
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
Assert.assertFalse(mSilenceDeviceManager.getSilenceMode(mTestDevice));
// Should be no intent been broadcasted
verify(mAdapterService, times(mVerifyCount)).sendBroadcastAsUser(
intentArgument.capture(), eq(UserHandle.ALL),
eq(BLUETOOTH_CONNECT), any(Bundle.class));
}
void verifySilenceStateIntent(Intent intent) {
Assert.assertEquals(BluetoothDevice.ACTION_SILENCE_MODE_CHANGED, intent.getAction());
Assert.assertEquals(mTestDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
}
/**
* Helper to indicate A2dp connected for a device.
*/
private void a2dpConnected(BluetoothDevice device) {
mSilenceDeviceManager.a2dpConnectionStateChanged(
device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED);
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
}
/**
* Helper to indicate A2dp disconnected for a device.
*/
private void a2dpDisconnected(BluetoothDevice device) {
mSilenceDeviceManager.a2dpConnectionStateChanged(
device, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
}
/**
* Helper to indicate Headset connected for a device.
*/
private void headsetConnected(BluetoothDevice device) {
mSilenceDeviceManager.hfpConnectionStateChanged(
device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED);
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
}
/**
* Helper to indicate Headset disconnected for a device.
*/
private void headsetDisconnected(BluetoothDevice device) {
mSilenceDeviceManager.hfpConnectionStateChanged(
device, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
}
}