Merge "Add Unit Test for FastPairDualConnection."
diff --git a/nearby/README.md b/nearby/README.md
index da70819..ff3b701 100644
--- a/nearby/README.md
+++ b/nearby/README.md
@@ -34,9 +34,9 @@
 
 ```sh
 $ source build/envsetup.sh && lunch <TARGET>
-$ m com.android.tethering deapexer
+$ m com.google.android.tethering.next deapexer
 $ $ANDROID_BUILD_TOP/out/host/linux-x86/bin/deapexer decompress --input \
-    {ANDROID_PRODUCT_OUT}/system/apex/com.android.tethering.capex --output \
-    /tmp/tethering.apex
+    ${ANDROID_PRODUCT_OUT}/system/apex/com.google.android.tethering.next.capex \
+    --output /tmp/tethering.apex
 $ adb install -r /tmp/tethering.apex
 ```
diff --git a/nearby/service/Android.bp b/nearby/service/Android.bp
index 1e1af20..8f6a227 100644
--- a/nearby/service/Android.bp
+++ b/nearby/service/Android.bp
@@ -20,6 +20,7 @@
     name: "nearby-service-srcs",
     srcs: [
         "java/**/*.java",
+        ":statslog-nearby-java-gen",
     ],
 }
 
@@ -53,6 +54,7 @@
         "framework-bluetooth.stubs.module_lib", // TODO(b/215722418): Change to framework-bluetooth once fixed
         "error_prone_annotations",
         "framework-connectivity-tiramisu.impl",
+        "framework-statsd.stubs.module_lib",
     ],
     static_libs: [
         "androidx.annotation_annotation",
@@ -84,3 +86,12 @@
         "com.android.tethering",
     ],
 }
+
+genrule {
+    name: "statslog-nearby-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module nearby " +
+         " --javaPackage com.android.server.nearby.proto --javaClass NearbyStatsLog" +
+         " --minApiLevel 33",
+    out: ["com/android/server/nearby/proto/NearbyStatsLog.java"],
+}
diff --git a/nearby/service/java/com/android/server/nearby/metrics/NearbyMetrics.java b/nearby/service/java/com/android/server/nearby/metrics/NearbyMetrics.java
new file mode 100644
index 0000000..75815f1
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/metrics/NearbyMetrics.java
@@ -0,0 +1,85 @@
+/*
+ * 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.metrics;
+
+import android.nearby.NearbyDeviceParcelable;
+import android.nearby.ScanRequest;
+import android.os.WorkSource;
+
+import com.android.server.nearby.proto.NearbyStatsLog;
+
+/**
+ * A class to collect and report Nearby metrics.
+ */
+public class NearbyMetrics {
+    /**
+     * Logs a scan started event.
+     */
+    public static void logScanStarted(int scanSessionId, ScanRequest scanRequest) {
+        NearbyStatsLog.write(
+                NearbyStatsLog.NEARBY_DEVICE_SCAN_STATE_CHANGED,
+                getUid(scanRequest),
+                scanSessionId,
+                NearbyStatsLog
+                        .NEARBY_DEVICE_SCAN_STATE_CHANGED__SCAN_STATE__NEARBY_SCAN_STATE_STARTED,
+                scanRequest.getScanType(),
+                0,
+                0,
+                "",
+                "");
+    }
+
+    /**
+     * Logs a scan stopped event.
+     */
+    public static void logScanStopped(int scanSessionId, ScanRequest scanRequest) {
+        NearbyStatsLog.write(
+                NearbyStatsLog.NEARBY_DEVICE_SCAN_STATE_CHANGED,
+                getUid(scanRequest),
+                scanSessionId,
+                NearbyStatsLog
+                        .NEARBY_DEVICE_SCAN_STATE_CHANGED__SCAN_STATE__NEARBY_SCAN_STATE_STOPPED,
+                scanRequest.getScanType(),
+                0,
+                0,
+                "",
+                "");
+    }
+
+    /**
+     * Logs a scan device discovered event.
+     */
+    public static void logScanDeviceDiscovered(int scanSessionId, ScanRequest scanRequest,
+            NearbyDeviceParcelable nearbyDevice) {
+        NearbyStatsLog.write(
+                NearbyStatsLog.NEARBY_DEVICE_SCAN_STATE_CHANGED,
+                getUid(scanRequest),
+                scanSessionId,
+                NearbyStatsLog
+                        .NEARBY_DEVICE_SCAN_STATE_CHANGED__SCAN_STATE__NEARBY_SCAN_STATE_DISCOVERED,
+                scanRequest.getScanType(),
+                nearbyDevice.getMedium(),
+                nearbyDevice.getRssi(),
+                nearbyDevice.getFastPairModelId(),
+                "");
+    }
+
+    private static int getUid(ScanRequest scanRequest) {
+        WorkSource workSource = scanRequest.getWorkSource();
+        return workSource.isEmpty() ? -1 : workSource.getUid(0);
+    }
+}
diff --git a/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
index 72c4b75..27f3acb 100644
--- a/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
+++ b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.nearby.injector.Injector;
+import com.android.server.nearby.metrics.NearbyMetrics;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -59,6 +60,8 @@
                     record.getScanListener().onDiscovered(
                             PrivacyFilter.filter(record.getScanRequest().getScanType(),
                                     nearbyDevice));
+                    NearbyMetrics.logScanDeviceDiscovered(
+                            record.hashCode(), record.getScanRequest(), nearbyDevice);
                 } catch (RemoteException e) {
                     Log.w(TAG, "DiscoveryProviderManager failed to report onDiscovered.", e);
                 }
@@ -89,8 +92,9 @@
 
             startProviders(scanRequest);
 
-            mScanTypeScanListenerRecordMap.put(listenerBinder,
-                    new ScanListenerRecord(scanRequest, listener));
+            ScanListenerRecord scanListenerRecord = new ScanListenerRecord(scanRequest, listener);
+            mScanTypeScanListenerRecordMap.put(listenerBinder, scanListenerRecord);
+            NearbyMetrics.logScanStarted(scanListenerRecord.hashCode(), scanRequest);
             if (mScanMode < scanRequest.getScanMode()) {
                 mScanMode = scanRequest.getScanMode();
                 invalidateProviderScanMode();
@@ -113,6 +117,8 @@
 
             ScanListenerRecord removedRecord = mScanTypeScanListenerRecordMap
                     .remove(listenerBinder);
+            NearbyMetrics.logScanStopped(
+                    removedRecord.hashCode(), removedRecord.getScanRequest());
             if (mScanTypeScanListenerRecordMap.isEmpty()) {
                 stopProviders();
                 return;
@@ -201,7 +207,7 @@
 
         @Override
         public int hashCode() {
-            return  Objects.hash(mScanListener, mScanRequest);
+            return Objects.hash(mScanListener, mScanRequest);
         }
     }
 }