blob: 972ad474cf4d0347352f704b6f1f2a28c101d498 [file] [log] [blame]
/*
* Copyright (C) 2017 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.mapclient;
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.SdpMasRecord;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.R;
import com.android.bluetooth.btservice.ProfileService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
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 MapClientStateMachineTest {
private static final String TAG = "MapStateMachineTest";
private static final int ASYNC_CALL_TIMEOUT_MILLIS = 100;
private BluetoothAdapter mAdapter;
private MceStateMachine mMceStateMachine = null;
private BluetoothDevice mTestDevice;
private Context mTargetContext;
private Handler mHandler;
private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class);
@Mock
private MapClientService mMockMapClientService;
@Mock
private MasClient mMockMasClient;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTargetContext = InstrumentationRegistry.getTargetContext();
Assume.assumeTrue("Ignore test when MapClientService is not enabled",
mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce));
doReturn(mTargetContext.getResources()).when(mMockMapClientService).getResources();
// This line must be called to make sure relevant objects are initialized properly
mAdapter = BluetoothAdapter.getDefaultAdapter();
// Get a device for testing
mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
when(mMockMasClient.makeRequest(any(Request.class))).thenReturn(true);
mMceStateMachine = new MceStateMachine(mMockMapClientService, mTestDevice, mMockMasClient);
Assert.assertNotNull(mMceStateMachine);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mHandler = new Handler();
}
@After
public void tearDown() {
if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)) {
return;
}
if (mMceStateMachine != null) {
mMceStateMachine.doQuit();
}
}
/**
* Test that default state is STATE_CONNECTING
*/
@Test
public void testDefaultConnectingState() {
Log.i(TAG, "in testDefaultConnectingState");
Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mMceStateMachine.getState());
}
/**
* Test transition from
* STATE_CONNECTING --> (receive MSG_MAS_DISCONNECTED) --> STATE_DISCONNECTED
*/
@Test
public void testStateTransitionFromConnectingToDisconnected() {
Log.i(TAG, "in testStateTransitionFromConnectingToDisconnected");
setupSdpRecordReceipt();
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED);
mMceStateMachine.sendMessage(msg);
// Wait until the message is processed and a broadcast request is sent to
// to MapClientService to change
// state from STATE_CONNECTING to STATE_DISCONNECTED
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState());
}
/**
* Test transition from STATE_CONNECTING --> (receive MSG_MAS_CONNECTED) --> STATE_CONNECTED
*/
@Test
public void testStateTransitionFromConnectingToConnected() {
Log.i(TAG, "in testStateTransitionFromConnectingToConnected");
setupSdpRecordReceipt();
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
mMceStateMachine.sendMessage(msg);
// Wait until the message is processed and a broadcast request is sent to
// to MapClientService to change
// state from STATE_CONNECTING to STATE_CONNECTED
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
}
/**
* Test transition from STATE_CONNECTING --> (receive MSG_MAS_CONNECTED) --> STATE_CONNECTED
* --> (receive MSG_MAS_DISCONNECTED) --> STATE_DISCONNECTED
*/
@Test
public void testStateTransitionFromConnectedWithMasDisconnected() {
Log.i(TAG, "in testStateTransitionFromConnectedWithMasDisconnected");
setupSdpRecordReceipt();
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
mMceStateMachine.sendMessage(msg);
// Wait until the message is processed and a broadcast request is sent to
// to MapClientService to change
// state from STATE_CONNECTING to STATE_CONNECTED
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED);
mMceStateMachine.sendMessage(msg);
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(4)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState());
}
/**
* Test receiving an empty event report
*/
@Test
public void testReceiveEmptyEvent() {
setupSdpRecordReceipt();
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
mMceStateMachine.sendMessage(msg);
// Wait until the message is processed and a broadcast request is sent to
// to MapClientService to change
// state from STATE_CONNECTING to STATE_CONNECTED
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
// Send an empty notification event, verify the mMceStateMachine is still connected
Message notification = Message.obtain(mHandler, MceStateMachine.MSG_NOTIFICATION);
mMceStateMachine.getCurrentState().processMessage(msg);
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
}
/**
* Test set message status
*/
@Test
public void testSetMessageStatus() {
setupSdpRecordReceipt();
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
mMceStateMachine.sendMessage(msg);
// Wait until the message is processed and a broadcast request is sent to
// to MapClientService to change
// state from STATE_CONNECTING to STATE_CONNECTED
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
Assert.assertTrue(mMceStateMachine.setMessageStatus("123456789AB", BluetoothMapClient.READ));
}
private void setupSdpRecordReceipt() {
// Perform first part of MAP connection logic.
verify(mMockMapClientService,
timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).sendBroadcast(
mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mMceStateMachine.getState());
// Setup receipt of SDP record
SdpMasRecord record = new SdpMasRecord(1, 1, 1, 1, 1, 1, "MasRecord");
Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_SDP_DONE, record);
mMceStateMachine.sendMessage(msg);
}
}