blob: 50680ef90dd7ea36fc2d3d8488f0f3f48f02d030 [file] [log] [blame]
/*
* Copyright 2022 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.hfp;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.database.Cursor;
import android.provider.CallLog;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.PhoneNumberUtils;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.internal.telephony.GsmAlphabet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@RunWith(AndroidJUnit4.class)
public class AtPhonebookTest {
private static final String INVALID_COMMAND = "invalid_command";
private Context mTargetContext;
private BluetoothAdapter mAdapter;
private BluetoothDevice mTestDevice;
@Mock private AdapterService mAdapterService;
@Mock private HeadsetNativeInterface mNativeInterface;
private AtPhonebook mAtPhonebook;
@Spy
private BluetoothMethodProxy mHfpMethodProxy = BluetoothMethodProxy.getInstance();
@Before
public void setUp() throws Exception {
mTargetContext = InstrumentationRegistry.getTargetContext();
MockitoAnnotations.initMocks(this);
TestUtils.setAdapterService(mAdapterService);
BluetoothMethodProxy.setInstanceForTesting(mHfpMethodProxy);
mAdapter = BluetoothAdapter.getDefaultAdapter();
mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
// Spy on native interface
mAtPhonebook = new AtPhonebook(mTargetContext, mNativeInterface);
}
@After
public void tearDown() throws Exception {
TestUtils.clearAdapterService(mAdapterService);
BluetoothMethodProxy.setInstanceForTesting(null);
}
@Test
public void checkAccessPermission_returnsCorrectPermission() {
assertThat(mAtPhonebook.checkAccessPermission(mTestDevice)).isEqualTo(
BluetoothDevice.ACCESS_UNKNOWN);
}
@Test
public void getAndSetCheckingAccessPermission_setCorrectly() {
mAtPhonebook.setCheckingAccessPermission(true);
assertThat(mAtPhonebook.getCheckingAccessPermission()).isTrue();
}
@Test
public void handleCscsCommand() {
mAtPhonebook.handleCscsCommand(INVALID_COMMAND, AtPhonebook.TYPE_READ, mTestDevice);
verify(mNativeInterface).atResponseString(mTestDevice,
"+CSCS: \"" + "UTF-8" + "\"");
mAtPhonebook.handleCscsCommand(INVALID_COMMAND, AtPhonebook.TYPE_TEST, mTestDevice);
verify(mNativeInterface).atResponseString(mTestDevice,
"+CSCS: (\"UTF-8\",\"IRA\",\"GSM\")");
mAtPhonebook.handleCscsCommand(INVALID_COMMAND, AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface, atLeastOnce()).atResponseCode(mTestDevice,
HeadsetHalConstants.AT_RESPONSE_ERROR, -1);
mAtPhonebook.handleCscsCommand("command=GSM", AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface, atLeastOnce()).atResponseCode(mTestDevice,
HeadsetHalConstants.AT_RESPONSE_OK, -1);
mAtPhonebook.handleCscsCommand("command=ERR", AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.OPERATION_NOT_SUPPORTED);
mAtPhonebook.handleCscsCommand(INVALID_COMMAND, AtPhonebook.TYPE_UNKNOWN, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.TEXT_HAS_INVALID_CHARS);
}
@Test
public void handleCpbsCommand() {
mAtPhonebook.handleCpbsCommand(INVALID_COMMAND, AtPhonebook.TYPE_READ, mTestDevice);
int size = mAtPhonebook.getPhonebookResult("ME", true).cursor.getCount();
int maxSize = mAtPhonebook.getMaxPhoneBookSize(size);
verify(mNativeInterface).atResponseString(mTestDevice,
"+CPBS: \"" + "ME" + "\"," + size + "," + maxSize);
mAtPhonebook.handleCpbsCommand(INVALID_COMMAND, AtPhonebook.TYPE_TEST, mTestDevice);
verify(mNativeInterface).atResponseString(mTestDevice,
"+CPBS: (\"ME\",\"SM\",\"DC\",\"RC\",\"MC\")");
mAtPhonebook.handleCpbsCommand(INVALID_COMMAND, AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.OPERATION_NOT_SUPPORTED);
mAtPhonebook.handleCpbsCommand("command=ERR", AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.OPERATION_NOT_ALLOWED);
mAtPhonebook.handleCpbsCommand("command=SM", AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface, atLeastOnce()).atResponseCode(mTestDevice,
HeadsetHalConstants.AT_RESPONSE_OK, -1);
mAtPhonebook.handleCpbsCommand(INVALID_COMMAND, AtPhonebook.TYPE_UNKNOWN, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.TEXT_HAS_INVALID_CHARS);
}
@Test
public void handleCpbrCommand() {
mAtPhonebook.handleCpbrCommand(INVALID_COMMAND, AtPhonebook.TYPE_TEST, mTestDevice);
int size = mAtPhonebook.getPhonebookResult("ME", true).cursor.getCount();
if (size == 0) {
size = 1;
}
verify(mNativeInterface).atResponseString(mTestDevice, "+CPBR: (1-" + size + "),30,30");
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_OK,
-1);
mAtPhonebook.handleCpbrCommand(INVALID_COMMAND, AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
-1);
mAtPhonebook.handleCpbrCommand("command=ERR", AtPhonebook.TYPE_SET, mTestDevice);
verify(mNativeInterface).atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR,
BluetoothCmeError.TEXT_HAS_INVALID_CHARS);
mAtPhonebook.handleCpbrCommand("command=123,123", AtPhonebook.TYPE_SET, mTestDevice);
assertThat(mAtPhonebook.getCheckingAccessPermission()).isTrue();
mAtPhonebook.handleCpbrCommand(INVALID_COMMAND, AtPhonebook.TYPE_UNKNOWN, mTestDevice);
verify(mNativeInterface, atLeastOnce()).atResponseCode(mTestDevice,
HeadsetHalConstants.AT_RESPONSE_ERROR, BluetoothCmeError.TEXT_HAS_INVALID_CHARS);
}
@Test
public void processCpbrCommand() {
mAtPhonebook.handleCpbsCommand("command=SM", AtPhonebook.TYPE_SET, mTestDevice);
assertThat(mAtPhonebook.processCpbrCommand(mTestDevice)).isEqualTo(
HeadsetHalConstants.AT_RESPONSE_OK);
mAtPhonebook.handleCpbsCommand("command=ME", AtPhonebook.TYPE_SET, mTestDevice);
assertThat(mAtPhonebook.processCpbrCommand(mTestDevice)).isEqualTo(
HeadsetHalConstants.AT_RESPONSE_OK);
mAtPhonebook.mCurrentPhonebook = "ER";
assertThat(mAtPhonebook.processCpbrCommand(mTestDevice)).isEqualTo(
HeadsetHalConstants.AT_RESPONSE_ERROR);
}
@Test
public void processCpbrCommand_withMobilePhonebook() {
Cursor mockCursorOne = mock(Cursor.class);
when(mockCursorOne.getCount()).thenReturn(1);
when(mockCursorOne.getColumnIndex(Phone.TYPE)).thenReturn(1); //TypeColumn
when(mockCursorOne.getColumnIndex(Phone.NUMBER)).thenReturn(2); //numberColumn
when(mockCursorOne.getColumnIndex(Phone.DISPLAY_NAME)).thenReturn(3); // nameColumn
when(mockCursorOne.getInt(1)).thenReturn(Phone.TYPE_WORK);
when(mockCursorOne.getString(2)).thenReturn(null);
when(mockCursorOne.getString(3)).thenReturn(null);
when(mockCursorOne.moveToNext()).thenReturn(false);
doReturn(mockCursorOne).when(mHfpMethodProxy).contentResolverQuery(any(), any(), any(),
any(), any());
mAtPhonebook.mCurrentPhonebook = "ME";
mAtPhonebook.mCpbrIndex1 = 1;
mAtPhonebook.mCpbrIndex2 = 2;
mAtPhonebook.processCpbrCommand(mTestDevice);
String expected = "+CPBR: " + 1 + ",\"" + "" + "\"," + PhoneNumberUtils.toaFromString("")
+ ",\"" + "" + "/" + AtPhonebook.getPhoneType(Phone.TYPE_WORK) + "\"" + "\r\n\r\n";
verify(mNativeInterface).atResponseString(mTestDevice, expected);
}
@Test
public void processCpbrCommand_withMissedCalls() {
Cursor mockCursorOne = mock(Cursor.class);
when(mockCursorOne.getCount()).thenReturn(1);
when(mockCursorOne.getColumnIndexOrThrow(CallLog.Calls.NUMBER)).thenReturn(1);
when(mockCursorOne.getColumnIndexOrThrow(CallLog.Calls.NUMBER_PRESENTATION)).thenReturn(2);
String number = "1".repeat(31);
when(mockCursorOne.getString(1)).thenReturn(number);
when(mockCursorOne.getInt(2)).thenReturn(CallLog.Calls.PRESENTATION_RESTRICTED);
doReturn(mockCursorOne).when(mHfpMethodProxy).contentResolverQuery(any(), any(), any(),
any(), any());
Cursor mockCursorTwo = mock(Cursor.class);
when(mockCursorTwo.moveToFirst()).thenReturn(true);
String name = "k".repeat(30);
when(mockCursorTwo.getString(0)).thenReturn(name);
when(mockCursorTwo.getInt(1)).thenReturn(1);
doReturn(mockCursorTwo).when(mHfpMethodProxy).contentResolverQuery(any(), any(), any(),
any(), any(), any());
mAtPhonebook.mCurrentPhonebook = "MC";
mAtPhonebook.mCpbrIndex1 = 1;
mAtPhonebook.mCpbrIndex2 = 2;
mAtPhonebook.processCpbrCommand(mTestDevice);
String expected = "+CPBR: " + 1 + ",\"" + "" + "\"," + PhoneNumberUtils.toaFromString(
number) + ",\"" + mTargetContext.getString(R.string.unknownNumber) + "\""
+ "\r\n\r\n";
verify(mNativeInterface).atResponseString(mTestDevice, expected);
}
@Test
public void processCpbrCommand_withReceivcedCallsAndCharsetGsm() {
Cursor mockCursorOne = mock(Cursor.class);
when(mockCursorOne.getCount()).thenReturn(1);
when(mockCursorOne.getColumnIndexOrThrow(CallLog.Calls.NUMBER)).thenReturn(1);
when(mockCursorOne.getColumnIndexOrThrow(CallLog.Calls.NUMBER_PRESENTATION)).thenReturn(-1);
String number = "1".repeat(31);
when(mockCursorOne.getString(1)).thenReturn(number);
when(mockCursorOne.getInt(2)).thenReturn(CallLog.Calls.PRESENTATION_RESTRICTED);
doReturn(mockCursorOne).when(mHfpMethodProxy).contentResolverQuery(any(), any(), any(),
any(), any());
Cursor mockCursorTwo = mock(Cursor.class);
when(mockCursorTwo.moveToFirst()).thenReturn(true);
String name = "k".repeat(30);
when(mockCursorTwo.getString(0)).thenReturn(name);
when(mockCursorTwo.getInt(1)).thenReturn(1);
doReturn(mockCursorTwo).when(mHfpMethodProxy).contentResolverQuery(any(), any(), any(),
any(), any(), any());
mAtPhonebook.mCurrentPhonebook = "RC";
mAtPhonebook.mCpbrIndex1 = 1;
mAtPhonebook.mCpbrIndex2 = 2;
mAtPhonebook.mCharacterSet = "GSM";
mAtPhonebook.processCpbrCommand(mTestDevice);
String expectedName = new String(GsmAlphabet.stringToGsm8BitPacked(name.substring(0, 28)));
String expected = "+CPBR: " + 1 + ",\"" + number.substring(0, 30) + "\","
+ PhoneNumberUtils.toaFromString(number) + ",\"" + expectedName + "\"" + "\r\n\r\n";
verify(mNativeInterface).atResponseString(mTestDevice, expected);
}
@Test
public void setCpbrIndex() {
int index = 1;
mAtPhonebook.setCpbrIndex(index);
assertThat(mAtPhonebook.mCpbrIndex1).isEqualTo(index);
assertThat(mAtPhonebook.mCpbrIndex2).isEqualTo(index);
}
@Test
public void resetAtState() {
mAtPhonebook.resetAtState();
assertThat(mAtPhonebook.getCheckingAccessPermission()).isFalse();
}
@Test
public void getPhoneType() {
assertThat(AtPhonebook.getPhoneType(Phone.TYPE_HOME)).isEqualTo("H");
assertThat(AtPhonebook.getPhoneType(Phone.TYPE_MOBILE)).isEqualTo("M");
assertThat(AtPhonebook.getPhoneType(Phone.TYPE_WORK)).isEqualTo("W");
assertThat(AtPhonebook.getPhoneType(Phone.TYPE_FAX_WORK)).isEqualTo("F");
assertThat(AtPhonebook.getPhoneType(Phone.TYPE_CUSTOM)).isEqualTo("O");
}
}