Merge "Expose PresenceClient System API for scan filter."
diff --git a/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
index 852791f..c051eb0 100644
--- a/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
+++ b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
@@ -82,6 +82,14 @@
     }
 
     /**
+     * Get device name.
+     */
+    @Nullable
+    public String getName() {
+        return mMetadataParcel.name;
+    }
+
+    /**
      * Get true wireless image url for left bud.
      */
     @Nullable
@@ -311,6 +319,7 @@
             mBuilderParcel = new FastPairDeviceMetadataParcel();
             mBuilderParcel.imageUrl = null;
             mBuilderParcel.intentUri = null;
+            mBuilderParcel.name = null;
             mBuilderParcel.bleTxPower = 0;
             mBuilderParcel.triggerDistance = 0;
             mBuilderParcel.image = null;
@@ -369,6 +378,18 @@
         }
 
         /**
+         * Set device name.
+         *
+         * @param name Device name.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mBuilderParcel.name = name;
+            return this;
+        }
+
+        /**
          * Set ble transmission power.
          *
          * @param bleTxPower Ble transmission power.
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl
index 565439b..ef00321 100644
--- a/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl
+++ b/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl
@@ -39,6 +39,9 @@
     // The image icon that shows in the notification.
     byte[] image;
 
+    // The name of the device.
+    String name;
+
     int deviceType;
 
     // The image urls for device with device type "true wireless".
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
index db2d69f..3f7ad2a 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
@@ -30,14 +30,12 @@
 import com.android.server.nearby.common.locator.Locator;
 import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
 import com.android.server.nearby.provider.FastPairDataProvider;
+import com.android.server.nearby.util.DataUtils;
 import com.android.server.nearby.util.FastPairDecoder;
 import com.android.server.nearby.util.Hex;
 
-import com.google.protobuf.ByteString;
-
 import java.util.List;
 
-import service.proto.Cache;
 import service.proto.Data;
 import service.proto.Rpcs;
 
@@ -74,17 +72,14 @@
         if (FastPairDecoder.checkModelId(fastPairDevice.getData())) {
             byte[] model = FastPairDecoder.getModelId(fastPairDevice.getData());
             Log.d("FastPairService",
-                    "On discovery model id" + Hex.bytesToStringLowercase(model));
+                    "On discovery model id " + Hex.bytesToStringLowercase(model));
             // Use api to get anti spoofing key from model id.
             try {
                 Rpcs.GetObservedDeviceResponse response =
                         FastPairDataProvider.getInstance()
                                 .loadFastPairAntispoofkeyDeviceMetadata(model);
-                ByteString publicKey = response.getDevice().getAntiSpoofingKeyPair().getPublicKey();
                 Locator.get(mContext, FastPairHalfSheetManager.class).showHalfSheet(
-                        Cache.ScanFastPairStoreItem.newBuilder().setAddress(mBleAddress)
-                                .setAntiSpoofingPublicKey(publicKey)
-                                .build());
+                        DataUtils.toScanFastPairStoreItem(response, mBleAddress));
             } catch (IllegalStateException e) {
                 Log.e(TAG, "OEM does not construct fast pair data proxy correctly");
             }
diff --git a/nearby/service/java/com/android/server/nearby/provider/Utils.java b/nearby/service/java/com/android/server/nearby/provider/Utils.java
index a340b04..3aceb7d 100644
--- a/nearby/service/java/com/android/server/nearby/provider/Utils.java
+++ b/nearby/service/java/com/android/server/nearby/provider/Utils.java
@@ -291,29 +291,42 @@
         if (metadata == null) {
             return null;
         }
+
+        Rpcs.Device.Builder deviceBuilder = Rpcs.Device.newBuilder();
+        if (metadata.antiSpoofPublicKey != null) {
+            deviceBuilder.setAntiSpoofingKeyPair(Rpcs.AntiSpoofingKeyPair.newBuilder()
+                    .setPublicKey(ByteString.copyFrom(metadata.antiSpoofPublicKey))
+                    .build());
+        }
+        if (metadata.deviceMetadata != null) {
+            Rpcs.TrueWirelessHeadsetImages.Builder imagesBuilder =
+                    Rpcs.TrueWirelessHeadsetImages.newBuilder();
+            if (metadata.deviceMetadata.trueWirelessImageUrlLeftBud != null) {
+                imagesBuilder.setLeftBudUrl(metadata.deviceMetadata.trueWirelessImageUrlLeftBud);
+            }
+            if (metadata.deviceMetadata.trueWirelessImageUrlRightBud != null) {
+                imagesBuilder.setRightBudUrl(metadata.deviceMetadata.trueWirelessImageUrlRightBud);
+            }
+            if (metadata.deviceMetadata.trueWirelessImageUrlCase != null) {
+                imagesBuilder.setCaseUrl(metadata.deviceMetadata.trueWirelessImageUrlCase);
+            }
+            deviceBuilder.setTrueWirelessImages(imagesBuilder.build());
+            if (metadata.deviceMetadata.imageUrl != null) {
+                deviceBuilder.setImageUrl(metadata.deviceMetadata.imageUrl);
+            }
+            if (metadata.deviceMetadata.intentUri != null) {
+                deviceBuilder.setIntentUri(metadata.deviceMetadata.intentUri);
+            }
+            if (metadata.deviceMetadata.name != null) {
+                deviceBuilder.setName(metadata.deviceMetadata.name);
+            }
+            deviceBuilder.setBleTxPower(metadata.deviceMetadata.bleTxPower)
+                    .setTriggerDistance(metadata.deviceMetadata.triggerDistance)
+                    .setDeviceType(Rpcs.DeviceType.forNumber(metadata.deviceMetadata.deviceType));
+        }
+
         return Rpcs.GetObservedDeviceResponse.newBuilder()
-                .setDevice(Rpcs.Device.newBuilder()
-                        .setAntiSpoofingKeyPair(Rpcs.AntiSpoofingKeyPair.newBuilder()
-                                .setPublicKey(ByteString.copyFrom(metadata.antiSpoofPublicKey))
-                                .build())
-                        .setTrueWirelessImages(Rpcs.TrueWirelessHeadsetImages.newBuilder()
-                                .setLeftBudUrl(
-                                        metadata.deviceMetadata.trueWirelessImageUrlLeftBud)
-                                .setRightBudUrl(
-                                        metadata.deviceMetadata
-                                                .trueWirelessImageUrlRightBud)
-                                .setCaseUrl(
-                                        metadata.deviceMetadata
-                                                .trueWirelessImageUrlCase
-                                )
-                                .build())
-                        .setImageUrl(metadata.deviceMetadata.imageUrl)
-                        .setIntentUri(metadata.deviceMetadata.intentUri)
-                        .setBleTxPower(metadata.deviceMetadata.bleTxPower)
-                        .setTriggerDistance(metadata.deviceMetadata.triggerDistance)
-                        .setDeviceType(
-                                Rpcs.DeviceType.forNumber(metadata.deviceMetadata.deviceType))
-                        .build())
+                .setDevice(deviceBuilder.build())
                 .setImage(ByteString.copyFrom(metadata.deviceMetadata.image))
                 .setStrings(Rpcs.ObservedDeviceStrings.newBuilder()
                         .setAssistantSetupHalfSheet(metadata.deviceMetadata.assistantSetupHalfSheet)
diff --git a/nearby/service/java/com/android/server/nearby/util/DataUtils.java b/nearby/service/java/com/android/server/nearby/util/DataUtils.java
new file mode 100644
index 0000000..c67d2f3
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/util/DataUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.util;
+
+import service.proto.Cache.ScanFastPairStoreItem;
+import service.proto.Cache.StoredDiscoveryItem;
+import service.proto.FastPairString.FastPairStrings;
+import service.proto.Rpcs.Device;
+import service.proto.Rpcs.GetObservedDeviceResponse;
+import service.proto.Rpcs.ObservedDeviceStrings;
+
+/**
+ * Utils class converts different data types {@link ScanFastPairStoreItem},
+ * {@link StoredDiscoveryItem} and {@link GetObservedDeviceResponse},
+ *
+ */
+public final class DataUtils {
+
+    /**
+     * Converts a {@link GetObservedDeviceResponse} to a {@link ScanFastPairStoreItem}.
+     */
+    public static ScanFastPairStoreItem toScanFastPairStoreItem(
+            GetObservedDeviceResponse observedDeviceResponse, String bleAddress) {
+        Device device = observedDeviceResponse.getDevice();
+        ScanFastPairStoreItem item = ScanFastPairStoreItem.newBuilder()
+                .setAddress(bleAddress)
+                .setActionUrl(device.getIntentUri())
+                .setDeviceName(device.getName())
+                .setIconPng(observedDeviceResponse.getImage())
+                .setIconFifeUrl(device.getImageUrl())
+                .setAntiSpoofingPublicKey(device.getAntiSpoofingKeyPair().getPublicKey())
+                .setFastPairStrings(getFastPairStrings(observedDeviceResponse))
+                .build();
+        return item;
+    }
+
+    private static FastPairStrings getFastPairStrings(GetObservedDeviceResponse response) {
+        ObservedDeviceStrings strings = response.getStrings();
+        return FastPairStrings.newBuilder()
+                .setTapToPairWithAccount(strings.getInitialNotificationDescription())
+                .setTapToPairWithoutAccount(
+                        strings.getInitialNotificationDescriptionNoAccount())
+                .setInitialPairingDescription(strings.getInitialPairingDescription())
+                .setPairingFinishedCompanionAppInstalled(
+                        strings.getConnectSuccessCompanionAppInstalled())
+                .setPairingFinishedCompanionAppNotInstalled(
+                        strings.getConnectSuccessCompanionAppNotInstalled())
+                .setSubsequentPairingDescription(strings.getSubsequentPairingDescription())
+                .setRetroactivePairingDescription(strings.getRetroactivePairingDescription())
+                .setWaitAppLaunchDescription(strings.getWaitLaunchCompanionAppDescription())
+                .setPairingFailDescription(strings.getFailConnectGoToSettingsDescription())
+                .setAssistantHalfSheetDescription(strings.getAssistantSetupHalfSheet())
+                .setAssistantNotificationDescription(strings.getAssistantSetupNotification())
+                .setFastPairTvConnectDeviceNoAccountDescription(
+                        strings.getFastPairTvConnectDeviceNoAccountDescription())
+                .build();
+    }
+}
diff --git a/nearby/service/java/com/android/server/nearby/util/Hex.java b/nearby/service/java/com/android/server/nearby/util/Hex.java
index c827ec5..446204e 100644
--- a/nearby/service/java/com/android/server/nearby/util/Hex.java
+++ b/nearby/service/java/com/android/server/nearby/util/Hex.java
@@ -30,8 +30,8 @@
     public static String bytesToStringLowercase(byte[] bytes) {
         char[] hexChars = new char[bytes.length * 2];
         int j = 0;
-        for (int i = 0; i < bytes.length; i++) {
-            int v = bytes[i] & 0xFF;
+        for (byte aByte : bytes) {
+            int v = aByte & 0xFF;
             hexChars[j++] = HEX_LOWERCASE[v >>> 4];
             hexChars[j++] = HEX_LOWERCASE[v & 0x0F];
         }
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
index 743a8e7..71fc330 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
@@ -150,6 +150,7 @@
     private static final int LAST_USER_EXPERIENCE = 93;
     private static final long LOST_MILLIS = 393284L;
     private static final String MAC_ADDRESS = "MAC_ADDRESS";
+    private static final String NAME = "NAME";
     private static final String PACKAGE_NAME = "PACKAGE_NAME";
     private static final long PENDING_APP_INSTALL_TIMESTAMP_MILLIS = 832393L;
     private static final int RSSI = 9;
@@ -707,6 +708,7 @@
         builder.setInitialPairingDescription(INITIAL_PAIRING_DESCRIPTION);
         builder.setIntentUri(INTENT_URI);
         builder.setLocale(LOCALE);
+        builder.setName(NAME);
         builder.setOpenCompanionAppDescription(OPEN_COMPANION_APP_DESCRIPTION);
         builder.setRetroactivePairingDescription(RETRO_ACTIVE_PAIRING_DESCRIPTION);
         builder.setSubsequentPairingDescription(SUBSEQUENT_PAIRING_DESCRIPTION);
@@ -751,6 +753,7 @@
         parcel.initialPairingDescription = INITIAL_PAIRING_DESCRIPTION;
         parcel.intentUri = INTENT_URI;
         parcel.locale = LOCALE;
+        parcel.name = NAME;
         parcel.openCompanionAppDescription = OPEN_COMPANION_APP_DESCRIPTION;
         parcel.retroactivePairingDescription = RETRO_ACTIVE_PAIRING_DESCRIPTION;
         parcel.subsequentPairingDescription = SUBSEQUENT_PAIRING_DESCRIPTION;
@@ -890,6 +893,7 @@
         assertThat(metadataParcel.intentUri).isEqualTo(INTENT_URI);
 
         assertThat(metadataParcel.locale).isEqualTo(LOCALE);
+        assertThat(metadataParcel.name).isEqualTo(NAME);
 
         assertThat(metadataParcel.openCompanionAppDescription).isEqualTo(
                 OPEN_COMPANION_APP_DESCRIPTION);
@@ -949,6 +953,7 @@
         assertThat(metadata.getInitialPairingDescription()).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
         assertThat(metadata.getIntentUri()).isEqualTo(INTENT_URI);
         assertThat(metadata.getLocale()).isEqualTo(LOCALE);
+        assertThat(metadata.getName()).isEqualTo(NAME);
         assertThat(metadata.getOpenCompanionAppDescription())
                 .isEqualTo(OPEN_COMPANION_APP_DESCRIPTION);
         assertThat(metadata.getRetroactivePairingDescription())