From 69e0a82189cb1262c8f804b72f767419ad5fd8f7 Mon Sep 17 00:00:00 2001
From: Aritra Sen <aritrasen@google.com>
Date: Wed, 7 Dec 2022 11:06:36 +0000
Subject: [PATCH] Add ability to find discoverable devices.

Added tests for the same.

Bug: 261616658
Test: mma -j $(nproc)
Test: ./build.py
Test: system/gd/cert/run --clean --topshim
Tag: #floss
Change-Id: I6252c6759937d263a2ae9a161df78083115860cf
---
 system/blueberry/facade/topshim/facade.proto  |  1 +
 .../tests/topshim/adapter/adapter_test.py     | 12 ++++++++++++
 .../tests/topshim/lib/adapter_client.py       | 10 ++++++++--
 .../tests/topshim/lib/topshim_device.py       | 19 +++++++++++++++++++
 .../topshim/facade/src/adapter_service.rs     | 15 +++++++++++++++
 5 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/system/blueberry/facade/topshim/facade.proto b/system/blueberry/facade/topshim/facade.proto
index 24cdad0bde9..c6583c1dc08 100644
--- a/system/blueberry/facade/topshim/facade.proto
+++ b/system/blueberry/facade/topshim/facade.proto
@@ -127,6 +127,7 @@ enum EventType {
   HFP_CONNECTION_STATE = 4;
   ADAPTER_PROPERTY = 5;
   DISCOVERY_STATE = 6;
+  DEVICE_FOUND = 7;
 }
 
 message FetchEventsRequest {}
diff --git a/system/blueberry/tests/topshim/adapter/adapter_test.py b/system/blueberry/tests/topshim/adapter/adapter_test.py
index c3980d78313..c2f1f1ee244 100644
--- a/system/blueberry/tests/topshim/adapter/adapter_test.py
+++ b/system/blueberry/tests/topshim/adapter/adapter_test.py
@@ -57,6 +57,18 @@ class AdapterTest(TopshimBaseTest):
         state = self.dut().toggle_discovery(False)
         assertThat(state).isEqualTo("Stopped")
 
+    def test_find_device_device_available(self):
+        self.dut().enable_inquiry_scan()
+        self.cert().enable_inquiry_scan()
+        self.dut().toggle_discovery(True)
+        device_addr = self.dut().find_device()
+        assertThat(device_addr).isNotNone()
+        # Reset DUT device discovering and scanning to None
+        self.dut().disable_page_scan()
+        self.dut().toggle_discovery(False)
+        # Reset CERT device to not discoverable
+        self.cert().disable_page_scan()
+
 
 if __name__ == "__main__":
     test_runner.main()
diff --git a/system/blueberry/tests/topshim/lib/adapter_client.py b/system/blueberry/tests/topshim/lib/adapter_client.py
index 83603c80781..e85d379569d 100644
--- a/system/blueberry/tests/topshim/lib/adapter_client.py
+++ b/system/blueberry/tests/topshim/lib/adapter_client.py
@@ -42,8 +42,9 @@ class AdapterClient(AsyncClosable):
 
     async def close(self):
         for task in self.__task_list:
+            if task.done() or task.cancelled():
+                continue
             task.cancel()
-            task = None
         self.__task_list.clear()
         await self.__channel.close()
 
@@ -63,10 +64,12 @@ class AdapterClient(AsyncClosable):
     async def _listen_for_event(self, event):
         """Start fetching events"""
         future = asyncio.get_running_loop().create_future()
-        self.__task_list.append(asyncio.get_running_loop().create_task(self.__get_next_event(event, future)))
+        task = asyncio.get_running_loop().create_task(self.__get_next_event(event, future))
+        self.__task_list.append(task)
         try:
             await asyncio.wait_for(future, AdapterClient.DEFAULT_TIMEOUT)
         except:
+            task.cancel()
             print("Failed to get event", event)
         return future
 
@@ -138,6 +141,9 @@ class AdapterClient(AsyncClosable):
         future = await self._listen_for_event(facade_pb2.EventType.DISCOVERY_STATE)
         return future
 
+    async def find_device(self):
+        return await self._listen_for_event(facade_pb2.EventType.DEVICE_FOUND)
+
 
 class A2dpAutomationHelper():
     """Invoke gRPC on topshim for A2DP testing"""
diff --git a/system/blueberry/tests/topshim/lib/topshim_device.py b/system/blueberry/tests/topshim/lib/topshim_device.py
index b3693d0cdfd..2b6483a1b66 100644
--- a/system/blueberry/tests/topshim/lib/topshim_device.py
+++ b/system/blueberry/tests/topshim/lib/topshim_device.py
@@ -209,3 +209,22 @@ class TopshimDevice(AsyncClosable):
             return params["state"].data[0]
 
         return self.__post(waiter(f))
+
+    def find_device(self):
+        """
+        Attempts to find discoverable devices when discovery is toggled on.
+
+        @return a list of properties of found device.
+        """
+        f = self.__post(self.__adapter.find_device())
+
+        async def waiter(f):
+            try:
+                params = await f
+                return params["BdAddr"].data[0]
+            except:
+                # The future `f` has a timeout after 2s post which it is cancelled.
+                print("No device was found. Timed out.")
+            return None
+
+        return self.__post(waiter(f))
diff --git a/system/gd/rust/topshim/facade/src/adapter_service.rs b/system/gd/rust/topshim/facade/src/adapter_service.rs
index 6bacea29e0d..899bd940729 100644
--- a/system/gd/rust/topshim/facade/src/adapter_service.rs
+++ b/system/gd/rust/topshim/facade/src/adapter_service.rs
@@ -46,6 +46,9 @@ fn get_bt_dispatcher(
                 BaseCallbacks::DiscoveryState(state) => {
                     println!("Discovery state changed, state = {:?}, ", state);
                 }
+                BaseCallbacks::DeviceFound(_, properties) => {
+                    println!("Device found with properties : {:?}", properties)
+                }
                 _ => (),
             }
         }),
@@ -173,6 +176,18 @@ impl AdapterService for AdapterServiceImpl {
                         );
                         sink.send((rsp, WriteFlags::default())).await.unwrap();
                     }
+                    BaseCallbacks::DeviceFound(_, properties) => {
+                        let mut rsp = FetchEventsResponse::new();
+                        rsp.event_type = EventType::DEVICE_FOUND;
+                        for property in properties.clone() {
+                            let (key, event_data) = bluetooth_property_to_event_data(property);
+                            if key == "skip" {
+                                continue;
+                            }
+                            rsp.params.insert(key, event_data);
+                        }
+                        sink.send((rsp, WriteFlags::default())).await.unwrap();
+                    }
                     _ => (),
                 }
             }
-- 
GitLab