• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth
18 
19 import android.bluetooth.DckTestRule.LeScanResult
20 import android.bluetooth.le.ScanFilter
21 import android.bluetooth.le.ScanSettings
22 import android.bluetooth.test_utils.EnableBluetoothRule
23 import android.content.Context
24 import android.os.ParcelUuid
25 import androidx.test.core.app.ApplicationProvider
26 import com.android.compatibility.common.util.AdoptShellPermissionsRule
27 import com.google.common.truth.Truth.assertThat
28 import com.google.testing.junit.testparameterinjector.TestParameter
29 import com.google.testing.junit.testparameterinjector.TestParameterInjector
30 import java.util.UUID
31 import kotlinx.coroutines.flow.first
32 import kotlinx.coroutines.runBlocking
33 import kotlinx.coroutines.withTimeout
34 import org.junit.Assume.assumeTrue
35 import org.junit.Ignore
36 import org.junit.Rule
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 
40 /** DCK LE Scan Tests */
41 @RunWith(TestParameterInjector::class)
42 class DckScanTest(
43     private @TestParameter val isBluetoothToggled: Boolean,
44     private @TestParameter val isRemoteAdvertisingWithUuid: Boolean,
45     private @TestParameter val isGattConnected: Boolean
46 ) {
47     // TODO(315852141): Include variations for LE only vs. Dual mode Bumble when supported
48     // TODO(315852141): Include variations for two advertisements at the same time
49     // TODO(303502437): Include variations for other callback types when supported in rootcanal
50 
51     private val context: Context = ApplicationProvider.getApplicationContext()
52 
53     // Gives shell permissions during the test.
54     @Rule(order = 0) @JvmField val shellPermissionRule = AdoptShellPermissionsRule()
55 
56     // Setup a Bumble Pandora device for the duration of the test.
57     // Acting as a Pandora client, it can be interacted with through the Pandora APIs.
58     @Rule(order = 1) @JvmField val bumble = PandoraDevice()
59 
60     // Test rule for common DCK test setup and teardown procedures, along with utility APIs.
61     @get:Rule(order = 2)
62     public val dck =
63         DckTestRule(
64             context,
65             bumble,
66             isBluetoothToggled = isBluetoothToggled,
67             isRemoteAdvertisingWithUuid = isRemoteAdvertisingWithUuid,
68             isGattConnected = isGattConnected
69         )
70 
71     @Rule(order = 3) @JvmField val enableBluetoothRule = EnableBluetoothRule(false, true)
72 
73     @Test
scanForIrkAndIdentityAddress_remoteFoundnull74     fun scanForIrkAndIdentityAddress_remoteFound() {
75         // TODO(316001793): Retrieve identity address from Bumble
76         val scanFilter =
77             ScanFilter.Builder()
78                 .setDeviceAddress(
79                     TEST_ADDRESS_RANDOM_STATIC,
80                     BluetoothDevice.ADDRESS_TYPE_RANDOM,
81                     Utils.BUMBLE_IRK
82                 )
83                 .build()
84         val scanSettings =
85             ScanSettings.Builder()
86                 .setScanMode(ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY)
87                 .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
88                 .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
89                 .build()
90 
91         val result: LeScanResult = runBlocking {
92             withTimeout(TIMEOUT_MS) { dck.scanWithPendingIntent(scanFilter, scanSettings).first() }
93         }
94 
95         assertThat(result).isInstanceOf(LeScanResult.Success::class.java)
96         assertThat((result as LeScanResult.Success).callbackType)
97             .isEqualTo(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
98         assertThat((result as LeScanResult.Success).scanResult.device.address)
99             .isEqualTo(TEST_ADDRESS_RANDOM_STATIC)
100     }
101 
102     @Test
103     @Ignore("b/404159990")
scanForUuid_remoteFoundnull104     fun scanForUuid_remoteFound() {
105         // Assume isRemoteAdvertisingWithUuid is true to skip tests in which
106         // device is not advertising with UUID
107         assumeTrue(isRemoteAdvertisingWithUuid)
108         val scanFilter = ScanFilter.Builder().setServiceUuid(ParcelUuid(CCC_DK_UUID)).build()
109         val scanSettings =
110             ScanSettings.Builder()
111                 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
112                 .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
113                 .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
114                 .build()
115 
116         val result: LeScanResult = runBlocking {
117             withTimeout(TIMEOUT_MS) { dck.scanWithCallback(scanFilter, scanSettings).first() }
118         }
119 
120         assertThat(result).isInstanceOf(LeScanResult.Success::class.java)
121         assertThat((result as LeScanResult.Success).callbackType)
122             .isEqualTo(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
123         assertThat((result as LeScanResult.Success).scanResult.device.address)
124             .isEqualTo(Utils.BUMBLE_RANDOM_ADDRESS)
125     }
126 
127     companion object {
128         private const val TIMEOUT_MS = 3000L
129         private const val TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"
130         private val CCC_DK_UUID = UUID.fromString("0000FFF5-0000-1000-8000-00805f9b34fb")
131     }
132 }
133