2323from avatar import BumblePandoraDevice
2424from avatar import PandoraDevice
2525from avatar import PandoraDevices
26+ from avatar import aio
27+ from avatar import pandora_snippet
2628from mobly import base_test
2729from mobly import test_runner
2830from mobly .asserts import assert_equal # type: ignore
3537from pandora .host_pb2 import Connection
3638from pandora .host_pb2 import DataTypes
3739from pandora .host_pb2 import OwnAddressType
40+ from pandora .security_pb2 import LE_LEVEL3
3841from typing import Any , Dict , Literal , Optional , Union
3942
4043
@@ -67,6 +70,7 @@ def setup_class(self) -> None:
6770 for device in self .devices :
6871 if isinstance (device , BumblePandoraDevice ):
6972 device .config .setdefault ('classic_enabled' , True )
73+ device .config .setdefault ('address_resolution_offload' , True )
7074
7175 def teardown_class (self ) -> None :
7276 if self .devices :
@@ -105,6 +109,45 @@ def test_scan(
105109 scan_response_data = DataTypes () if scannable == 'scannable' else None
106110 target = self .dut .address if directed == 'directed' else None
107111
112+ async def setup_pairing (
113+ initiator : PandoraDevice ,
114+ acceptor : PandoraDevice ,
115+ initiator_addr_type : OwnAddressType ,
116+ acceptor_addr_type : OwnAddressType ,
117+ ) -> None :
118+ # Acceptor - Advertise
119+ advertisement = acceptor .aio .host .Advertise (
120+ legacy = True ,
121+ connectable = True ,
122+ own_address_type = acceptor_addr_type ,
123+ data = DataTypes (manufacturer_specific_data = b'pause cafe' ),
124+ )
125+
126+ # Initiator - Scan and fetch the address
127+ scan = initiator .aio .host .Scan (own_address_type = initiator_addr_type )
128+ acceptor_scan = await anext (
129+ (x async for x in scan if b'pause cafe' in x .data .manufacturer_specific_data )
130+ ) # pytype: disable=name-error
131+ scan .cancel ()
132+
133+ ini_cer , cer_ini = await pandora_snippet .connect_le (
134+ initiator , advertisement , acceptor_scan , initiator_addr_type
135+ )
136+
137+ await asyncio .gather (
138+ initiator .aio .security .Secure (connection = ini_cer , le = LE_LEVEL3 ),
139+ acceptor .aio .security .WaitSecurity (connection = cer_ini , le = LE_LEVEL3 ),
140+ )
141+
142+ await asyncio .gather (
143+ initiator .aio .host .Disconnect (connection = ini_cer ),
144+ acceptor .aio .host .WaitDisconnection (connection = cer_ini ),
145+ )
146+
147+ if directed == 'directed' and self .dut .name == 'android' :
148+ # Android cannot advertise with Public address, so devices must be paired and enable resolution to perform directed advertisement
149+ aio .run_until_complete (setup_pairing (self .dut , self .ref , RANDOM , RANDOM ))
150+
108151 advertise = self .ref .host .Advertise (
109152 legacy = True ,
110153 connectable = is_connectable ,
@@ -114,7 +157,12 @@ def test_scan(
114157 own_address_type = PUBLIC ,
115158 )
116159
117- scan = self .dut .host .Scan (legacy = False , passive = False , timeout = self .scan_timeout )
160+ scan = self .dut .host .Scan (
161+ legacy = False ,
162+ passive = False ,
163+ own_address_type = RANDOM if self .dut .name == 'android' else PUBLIC ,
164+ timeout = self .scan_timeout ,
165+ )
118166 report = next ((x for x in scan if x .public == self .ref .address ))
119167 try :
120168 report = next ((x for x in scan if x .public == self .ref .address ))
0 commit comments