blob: 900b618e3ab9f04ff633f8a9d9208e80e5af36d8 [file] [log] [blame]
/*
* Copyright (C) 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.server.nearby.fastpair;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accounts.Account;
import android.content.Context;
import android.nearby.FastPairDevice;
import com.android.server.nearby.common.bloomfilter.BloomFilter;
import com.android.server.nearby.common.locator.LocatorContextWrapper;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
import com.android.server.nearby.fastpair.notification.FastPairNotificationManager;
import com.android.server.nearby.provider.FastPairDataProvider;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.ByteString;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.time.Clock;
import java.util.List;
import service.proto.Cache;
import service.proto.Data;
import service.proto.Rpcs;
public class FastPairAdvHandlerTest {
@Mock
private Context mContext;
@Mock
private FastPairDataProvider mFastPairDataProvider;
@Mock
private FastPairHalfSheetManager mFastPairHalfSheetManager;
@Mock
private FastPairNotificationManager mFastPairNotificationManager;
@Mock
private FastPairCacheManager mFastPairCacheManager;
@Mock
private FastPairController mFastPairController;
@Mock
private Data.FastPairDeviceWithAccountKey mFastPairDeviceWithAccountKey;
@Mock
private BloomFilter mBloomFilter;
@Mock
Cache.StoredFastPairItem mStoredFastPairItem;
@Mock private Clock mClock;
private final Account mAccount = new Account("test1@gmail.com", "com.google");
private static final byte[] ACCOUNT_KEY =
new byte[] {4, 65, 90, -26, -5, -38, -128, 40, -103, 101, 95, 55, 8, -42, -120, 78};
private static final byte[] ACCOUNT_KEY_2 = new byte[] {0, 1, 2};
private static final String BLUETOOTH_ADDRESS = "AA:BB:CC:DD";
private static final String MODEL_ID = "MODEL_ID";
private static final int CLOSE_RSSI = -80;
private static final int FAR_AWAY_RSSI = -120;
private static final int TX_POWER = -70;
private static final byte[] INITIAL_BYTE_ARRAY = new byte[]{0x01, 0x02, 0x03};
private static final byte[] SUBSEQUENT_DATA_BYTES = new byte[]{
0, -112, -63, 32, 37, -20, 36, 0, -60, 0, -96, 17, -10, 51, -28, -28, 100};
private static final byte[] SUBSEQUENT_DATA_BYTES_INVALID = new byte[]{
0, -112, -63, 32, 37, -20, 48, 0, -60, 0, 90, 17, -10, 51, -28, -28, 100};
private static final byte[] SALT = new byte[]{0x01};
private static final Cache.StoredDiscoveryItem STORED_DISCOVERY_ITEM =
Cache.StoredDiscoveryItem.newBuilder()
.setDeviceName("Device Name")
.setTxPower(TX_POWER)
.setMacAddress(BLUETOOTH_ADDRESS)
.build();
LocatorContextWrapper mLocatorContextWrapper;
FastPairAdvHandler mFastPairAdvHandler;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mLocatorContextWrapper = new LocatorContextWrapper(mContext);
mLocatorContextWrapper.getLocator().overrideBindingForTest(
FastPairHalfSheetManager.class, mFastPairHalfSheetManager
);
mLocatorContextWrapper.getLocator().overrideBindingForTest(
FastPairNotificationManager.class, mFastPairNotificationManager
);
mLocatorContextWrapper.getLocator().overrideBindingForTest(
FastPairCacheManager.class, mFastPairCacheManager
);
mLocatorContextWrapper.getLocator().overrideBindingForTest(
FastPairController.class, mFastPairController);
mLocatorContextWrapper.getLocator().overrideBindingForTest(Clock.class, mClock);
when(mFastPairDataProvider.loadFastPairAntispoofKeyDeviceMetadata(any()))
.thenReturn(Rpcs.GetObservedDeviceResponse.getDefaultInstance());
when(mFastPairDataProvider.loadFastPairEligibleAccounts()).thenReturn(List.of(mAccount));
when(mFastPairDataProvider.loadFastPairDeviceWithAccountKey(mAccount))
.thenReturn(List.of(mFastPairDeviceWithAccountKey));
when(mFastPairDataProvider.loadFastPairDeviceWithAccountKey(eq(mAccount), any()))
.thenReturn(List.of(mFastPairDeviceWithAccountKey));
when(mFastPairDeviceWithAccountKey.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY));
when(mFastPairDeviceWithAccountKey.getDiscoveryItem())
.thenReturn(STORED_DISCOVERY_ITEM);
when(mStoredFastPairItem.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY_2), ByteString.copyFrom(ACCOUNT_KEY_2));
when(mFastPairCacheManager.getAllSavedStoredFastPairItem())
.thenReturn(List.of(mStoredFastPairItem));
mFastPairAdvHandler = new FastPairAdvHandler(mLocatorContextWrapper, mFastPairDataProvider);
}
@Test
public void testInitialBroadcast() {
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(INITIAL_BYTE_ARRAY)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(CLOSE_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
verify(mFastPairHalfSheetManager).showHalfSheet(any());
}
@Test
public void testInitialBroadcast_farAway_notShowHalfSheet() {
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(INITIAL_BYTE_ARRAY)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(FAR_AWAY_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
@Test
public void testSubsequentBroadcast_showNotification() {
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(SUBSEQUENT_DATA_BYTES)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(CLOSE_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
DiscoveryItem discoveryItem =
new DiscoveryItem(mLocatorContextWrapper, STORED_DISCOVERY_ITEM);
verify(mFastPairNotificationManager).showDiscoveryNotification(eq(discoveryItem),
eq(ACCOUNT_KEY));
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
@Test
public void testSubsequentBroadcast_tooFar_notShowNotification() {
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(SUBSEQUENT_DATA_BYTES)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(FAR_AWAY_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
verify(mFastPairController, never()).pair(any(), any(), any());
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
@Test
public void testSubsequentBroadcast_notRecognize_notShowNotification() {
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(SUBSEQUENT_DATA_BYTES_INVALID)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(FAR_AWAY_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
verify(mFastPairController, never()).pair(any(), any(), any());
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
@Test
public void testSubsequentBroadcast_cached_notShowNotification() {
when(mStoredFastPairItem.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY), ByteString.copyFrom(ACCOUNT_KEY));
FastPairDevice fastPairDevice = new FastPairDevice.Builder()
.setData(SUBSEQUENT_DATA_BYTES_INVALID)
.setBluetoothAddress(BLUETOOTH_ADDRESS)
.setModelId(MODEL_ID)
.setRssi(FAR_AWAY_RSSI)
.setTxPower(TX_POWER)
.build();
mFastPairAdvHandler.handleBroadcast(fastPairDevice);
verify(mFastPairController, never()).pair(any(), any(), any());
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
@Test
public void testFindRecognizedDevice_bloomFilterNotContains_notFound() {
when(mFastPairDeviceWithAccountKey.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY), ByteString.copyFrom(ACCOUNT_KEY));
when(mBloomFilter.possiblyContains(any(byte[].class))).thenReturn(false);
assertThat(FastPairAdvHandler.findRecognizedDevice(
ImmutableList.of(mFastPairDeviceWithAccountKey), mBloomFilter, SALT)).isNull();
}
@Test
public void testFindRecognizedDevice_bloomFilterContains_found() {
when(mFastPairDeviceWithAccountKey.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY), ByteString.copyFrom(ACCOUNT_KEY));
when(mBloomFilter.possiblyContains(any(byte[].class))).thenReturn(true);
assertThat(FastPairAdvHandler.findRecognizedDevice(
ImmutableList.of(mFastPairDeviceWithAccountKey), mBloomFilter, SALT)).isNotNull();
}
@Test
public void testFindRecognizedDeviceFromCachedItem_bloomFilterNotContains_notFound() {
when(mStoredFastPairItem.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY), ByteString.copyFrom(ACCOUNT_KEY));
when(mBloomFilter.possiblyContains(any(byte[].class))).thenReturn(false);
assertThat(FastPairAdvHandler.findRecognizedDeviceFromCachedItem(
ImmutableList.of(mStoredFastPairItem), mBloomFilter, SALT)).isNull();
}
@Test
public void testFindRecognizedDeviceFromCachedItem_bloomFilterContains_found() {
when(mStoredFastPairItem.getAccountKey())
.thenReturn(ByteString.copyFrom(ACCOUNT_KEY), ByteString.copyFrom(ACCOUNT_KEY));
when(mBloomFilter.possiblyContains(any(byte[].class))).thenReturn(true);
assertThat(FastPairAdvHandler.findRecognizedDeviceFromCachedItem(
ImmutableList.of(mStoredFastPairItem), mBloomFilter, SALT)).isNotNull();
}
@Test
public void testGenerateBatteryData_correct() {
byte[] data = new byte[]
{0, -112, 96, 5, -125, 45, 35, 98, 98, 81, 13, 17, 3, 51, -28, -28, -28};
assertThat(FastPairAdvHandler.generateBatteryData(data))
.isEqualTo(new byte[]{51, -28, -28, -28});
}
}