Merge history of Nearby

BUG: 222234190
TEST: TH
Merged-In: I7fd9cc67244f2533057e679b0bc5e1db126cd399
Change-Id: Ie7a308b2a0294a50467443dc935082c2e88d27f7
diff --git a/nearby/framework/Android.bp b/nearby/framework/Android.bp
new file mode 100644
index 0000000..e223b54
--- /dev/null
+++ b/nearby/framework/Android.bp
@@ -0,0 +1,55 @@
+// Copyright (C) 2021 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// Sources included in the framework-connectivity-t jar
+// TODO: consider moving files to packages/modules/Connectivity
+filegroup {
+    name: "framework-nearby-java-sources",
+    srcs: [
+        "java/**/*.java",
+        "java/**/*.aidl",
+    ],
+    path: "java",
+    visibility: [
+        "//packages/modules/Connectivity/framework-t:__subpackages__",
+    ],
+}
+
+filegroup {
+    name: "framework-nearby-sources",
+    srcs: [
+        ":framework-nearby-java-sources",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+// Build of only framework-nearby (not as part of connectivity) for
+// unit tests
+java_library {
+    name: "framework-nearby-static",
+    srcs: [":framework-nearby-java-sources"],
+    sdk_version: "module_current",
+    libs: [
+        "framework-annotations-lib",
+        "framework-bluetooth",
+    ],
+    static_libs: [
+        "modules-utils-preconditions",
+    ],
+    visibility: ["//packages/modules/Connectivity/nearby/tests:__subpackages__"],
+}
diff --git a/nearby/framework/java/android/nearby/BroadcastCallback.java b/nearby/framework/java/android/nearby/BroadcastCallback.java
new file mode 100644
index 0000000..cc94308
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastCallback.java
@@ -0,0 +1,64 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Callback when broadcasting request using nearby specification.
+ *
+ * @hide
+ */
+@SystemApi
+public interface BroadcastCallback {
+    /** Broadcast was successful. */
+    int STATUS_OK = 0;
+
+    /** General status code when broadcast failed. */
+    int STATUS_FAILURE = 1;
+
+    /**
+     * Broadcast failed as the callback was already registered.
+     */
+    int STATUS_FAILURE_ALREADY_REGISTERED = 2;
+
+    /**
+     * Broadcast failed as the request contains excessive data.
+     */
+    int STATUS_FAILURE_SIZE_EXCEED_LIMIT = 3;
+
+    /**
+     * Broadcast failed as the client doesn't hold required permissions.
+     */
+    int STATUS_FAILURE_MISSING_PERMISSIONS = 4;
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATUS_OK, STATUS_FAILURE, STATUS_FAILURE_ALREADY_REGISTERED,
+            STATUS_FAILURE_SIZE_EXCEED_LIMIT, STATUS_FAILURE_MISSING_PERMISSIONS})
+    @interface BroadcastStatus {
+    }
+
+    /**
+     * Called when broadcast status changes.
+     */
+    void onStatusChanged(@BroadcastStatus int status);
+}
diff --git a/nearby/framework/java/android/nearby/BroadcastRequest.java b/nearby/framework/java/android/nearby/BroadcastRequest.java
new file mode 100644
index 0000000..3273ea1
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastRequest.java
@@ -0,0 +1,171 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a {@link BroadcastRequest}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class BroadcastRequest {
+
+    /** An unknown nearby broadcast request type. */
+    public static final int BROADCAST_TYPE_UNKNOWN = -1;
+
+    /** Broadcast type for advertising using nearby presence protocol. */
+    public static final int BROADCAST_TYPE_NEARBY_PRESENCE = 3;
+
+    /** @hide **/
+    // Currently, only Nearby Presence broadcast is supported, in the future
+    // broadcasting using other nearby specifications will be added.
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({BROADCAST_TYPE_UNKNOWN, BROADCAST_TYPE_NEARBY_PRESENCE})
+    public @interface BroadcastType {
+    }
+
+    /**
+     * Tx Power when the value is not set in the broadcast.
+     */
+    public static final int UNKNOWN_TX_POWER = -127;
+
+    /**
+     * An unknown version of presence broadcast request.
+     */
+    public static final int PRESENCE_VERSION_UNKNOWN = -1;
+
+    /**
+     * A legacy presence version that is only suitable for legacy (31 bytes) BLE advertisements.
+     * This exists to support legacy presence version, and not recommended for use.
+     */
+    public static final int PRESENCE_VERSION_V0 = 0;
+
+    /**
+     * V1 of Nearby Presence Protocol. This version supports both legacy (31 bytes) BLE
+     * advertisements, and extended BLE advertisements.
+     */
+    public static final int PRESENCE_VERSION_V1 = 1;
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({PRESENCE_VERSION_UNKNOWN, PRESENCE_VERSION_V0, PRESENCE_VERSION_V1})
+    public @interface BroadcastVersion {
+    }
+
+    /**
+     * The medium where the broadcast request should be sent.
+     *
+     * @hide
+     */
+    @IntDef({Medium.BLE, Medium.MDNS})
+    public @interface Medium {
+        int BLE = 1;
+        int MDNS = 2;
+    }
+
+    /**
+     * Creates a {@link BroadcastRequest} from parcel.
+     *
+     * @hide
+     */
+    @NonNull
+    public static BroadcastRequest createFromParcel(Parcel in) {
+        int type = in.readInt();
+        switch (type) {
+            case BroadcastRequest.BROADCAST_TYPE_NEARBY_PRESENCE:
+                return PresenceBroadcastRequest.createFromParcelBody(in);
+            default:
+                throw new IllegalStateException(
+                        "Unexpected broadcast type (value " + type + ") in parcel.");
+        }
+    }
+
+    private final @BroadcastType int mType;
+    private final @BroadcastVersion int mVersion;
+    private final int mTxPower;
+    private final @Medium List<Integer> mMediums;
+
+    BroadcastRequest(@BroadcastType int type, @BroadcastVersion int version, int txPower,
+            @Medium List<Integer> mediums) {
+        this.mType = type;
+        this.mVersion = version;
+        this.mTxPower = txPower;
+        this.mMediums = mediums;
+    }
+
+    BroadcastRequest(@BroadcastType int type, Parcel in) {
+        mType = type;
+        mVersion = in.readInt();
+        mTxPower = in.readInt();
+        mMediums = new ArrayList<>();
+        in.readList(mMediums, Integer.class.getClassLoader(), Integer.class);
+    }
+
+    /**
+     * Returns the type of the broadcast.
+     */
+    public @BroadcastType int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the version of the broadcast.
+     */
+    public @BroadcastVersion int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Returns the calibrated TX power when this request is broadcast.
+     */
+    @IntRange(from = -127, to = 126)
+    public int getTxPower() {
+        return mTxPower;
+    }
+
+    /**
+     * Returns the list of broadcast mediums.
+     */
+    @NonNull
+    @Medium
+    public List<Integer> getMediums() {
+        return mMediums;
+    }
+
+    /**
+     * Writes the BroadcastRequest to the parcel.
+     *
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mVersion);
+        dest.writeInt(mTxPower);
+        dest.writeList(mMediums);
+    }
+}
diff --git a/nearby/framework/java/android/nearby/BroadcastRequestParcelable.aidl b/nearby/framework/java/android/nearby/BroadcastRequestParcelable.aidl
new file mode 100644
index 0000000..818f8d5
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastRequestParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.nearby;
+
+parcelable BroadcastRequestParcelable;
diff --git a/nearby/framework/java/android/nearby/BroadcastRequestParcelable.java b/nearby/framework/java/android/nearby/BroadcastRequestParcelable.java
new file mode 100644
index 0000000..4a2ff6d
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastRequestParcelable.java
@@ -0,0 +1,64 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A wrapper of {@link BroadcastRequest} that is parcelable.
+ *
+ * @hide
+ */
+public class BroadcastRequestParcelable implements Parcelable {
+    private final BroadcastRequest mBroadcastRequest;
+
+    public static final Creator<BroadcastRequestParcelable> CREATOR =
+            new Creator<BroadcastRequestParcelable>() {
+                @Override
+                public BroadcastRequestParcelable createFromParcel(Parcel in) {
+                    return new BroadcastRequestParcelable(BroadcastRequest.createFromParcel(in));
+                }
+
+                @Override
+                public BroadcastRequestParcelable[] newArray(int size) {
+                    return new BroadcastRequestParcelable[size];
+                }
+            };
+
+    BroadcastRequestParcelable(BroadcastRequest broadcastRequest) {
+        mBroadcastRequest = broadcastRequest;
+    }
+
+    /**
+     * Returns the broadcastRequest.
+     */
+    public BroadcastRequest getBroadcastRequest() {
+        return mBroadcastRequest;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        mBroadcastRequest.writeToParcel(dest, flags);
+    }
+}
diff --git a/nearby/framework/java/android/nearby/CredentialElement.java b/nearby/framework/java/android/nearby/CredentialElement.java
new file mode 100644
index 0000000..d2049d1
--- /dev/null
+++ b/nearby/framework/java/android/nearby/CredentialElement.java
@@ -0,0 +1,90 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents an element in {@link PresenceCredential}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CredentialElement implements Parcelable {
+    private final String mKey;
+    private final byte[] mValue;
+
+    /**
+     * Constructs a {@link CredentialElement}.
+     */
+    public CredentialElement(@NonNull String key, @NonNull byte[] value) {
+        Preconditions.checkState(key != null && value != null,
+                "neither key or value can be null");
+        mKey = key;
+        mValue = value;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<CredentialElement> CREATOR =
+            new Parcelable.Creator<CredentialElement>() {
+                @Override
+                public CredentialElement createFromParcel(Parcel in) {
+                    String key = in.readString();
+                    byte[] value = new byte[in.readInt()];
+                    in.readByteArray(value);
+                    return new CredentialElement(key, value);
+                }
+
+                @Override
+                public CredentialElement[] newArray(int size) {
+                    return new CredentialElement[size];
+                }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mKey);
+        dest.writeInt(mValue.length);
+        dest.writeByteArray(mValue);
+    }
+
+    /**
+     * Returns the key of the credential element.
+     */
+    @NonNull
+    public String getKey() {
+        return mKey;
+    }
+
+    /**
+     * Returns the value of the credential element.
+     */
+    @NonNull
+    public byte[] getValue() {
+        return mValue;
+    }
+}
diff --git a/nearby/framework/java/android/nearby/DataElement.java b/nearby/framework/java/android/nearby/DataElement.java
new file mode 100644
index 0000000..6fa5fb5
--- /dev/null
+++ b/nearby/framework/java/android/nearby/DataElement.java
@@ -0,0 +1,89 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+
+/**
+ * Represents a data element in Nearby Presence.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DataElement implements Parcelable {
+
+    private final int mKey;
+    private final byte[] mValue;
+
+    /**
+     * Constructs a {@link DataElement}.
+     */
+    public DataElement(int key, @NonNull byte[] value) {
+        Preconditions.checkState(value != null, "value cannot be null");
+        mKey = key;
+        mValue = value;
+    }
+
+    @NonNull
+    public static final Creator<DataElement> CREATOR = new Creator<DataElement>() {
+        @Override
+        public DataElement createFromParcel(Parcel in) {
+            int key = in.readInt();
+            byte[] value = new byte[in.readInt()];
+            in.readByteArray(value);
+            return new DataElement(key, value);
+        }
+
+        @Override
+        public DataElement[] newArray(int size) {
+            return new DataElement[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mKey);
+        dest.writeInt(mValue.length);
+        dest.writeByteArray(mValue);
+    }
+
+    /**
+     * Returns the key of the data element, as defined in the nearby presence specification.
+     */
+    public int getKey() {
+        return mKey;
+    }
+
+    /**
+     * Returns the value of the data element.
+     */
+    @NonNull
+    public byte[] getValue() {
+        return mValue;
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java
new file mode 100644
index 0000000..160ad75
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
+
+/**
+ * Class for metadata of a Fast Pair device associated with an account.
+ *
+ * @hide
+ */
+@SystemApi
+public class FastPairAccountKeyDeviceMetadata {
+
+    FastPairAccountKeyDeviceMetadataParcel mMetadataParcel;
+
+    FastPairAccountKeyDeviceMetadata(FastPairAccountKeyDeviceMetadataParcel metadataParcel) {
+        this.mMetadataParcel = metadataParcel;
+    }
+
+    /**
+     * Get Device Account Key, which uniquely identifies a Fast Pair device associated with an
+     * account. AccountKey is 16 bytes: first byte is 0x04. Other 15 bytes are randomly generated.
+     *
+     * @return 16-byte Account Key.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getDeviceAccountKey() {
+        return mMetadataParcel.deviceAccountKey;
+    }
+
+    /**
+     * Get a hash value of device's account key and public bluetooth address without revealing the
+     * public bluetooth address. Sha256 hash value is 32 bytes.
+     *
+     * @return 32-byte Sha256 hash value.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getSha256DeviceAccountKeyPublicAddress() {
+        return mMetadataParcel.sha256DeviceAccountKeyPublicAddress;
+    }
+
+    /**
+     * Get metadata of a Fast Pair device type.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public FastPairDeviceMetadata getFastPairDeviceMetadata() {
+        if (mMetadataParcel.metadata == null) {
+            return null;
+        }
+        return new FastPairDeviceMetadata(mMetadataParcel.metadata);
+    }
+
+    /**
+     * Get Fast Pair discovery item, which is tied to both the device type and the account.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public FastPairDiscoveryItem getFastPairDiscoveryItem() {
+        if (mMetadataParcel.discoveryItem == null) {
+            return null;
+        }
+        return new FastPairDiscoveryItem(mMetadataParcel.discoveryItem);
+    }
+
+    /**
+     * Builder used to create FastPairAccountKeyDeviceMetadata.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final FastPairAccountKeyDeviceMetadataParcel mBuilderParcel;
+
+        /**
+         * Default constructor of Builder.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {
+            mBuilderParcel = new FastPairAccountKeyDeviceMetadataParcel();
+            mBuilderParcel.deviceAccountKey = null;
+            mBuilderParcel.sha256DeviceAccountKeyPublicAddress = null;
+            mBuilderParcel.metadata = null;
+            mBuilderParcel.discoveryItem = null;
+        }
+
+        /**
+         * Set Account Key.
+         *
+         * @param deviceAccountKey Fast Pair device account key, which is 16 bytes: first byte is
+         *                         0x04. Next 15 bytes are randomly generated.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDeviceAccountKey(@Nullable byte[] deviceAccountKey) {
+            mBuilderParcel.deviceAccountKey = deviceAccountKey;
+            return this;
+        }
+
+        /**
+         * Set sha256 hash value of account key and public bluetooth address.
+         *
+         * @param sha256DeviceAccountKeyPublicAddress 32-byte sha256 hash value of account key and
+         *                                            public bluetooth address.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSha256DeviceAccountKeyPublicAddress(
+                @Nullable byte[] sha256DeviceAccountKeyPublicAddress) {
+            mBuilderParcel.sha256DeviceAccountKeyPublicAddress =
+                    sha256DeviceAccountKeyPublicAddress;
+            return this;
+        }
+
+
+        /**
+         * Set Fast Pair metadata.
+         *
+         * @param metadata Fast Pair metadata.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFastPairDeviceMetadata(@Nullable FastPairDeviceMetadata metadata) {
+            if (metadata == null) {
+                mBuilderParcel.metadata = null;
+            } else {
+                mBuilderParcel.metadata = metadata.mMetadataParcel;
+            }
+            return this;
+        }
+
+        /**
+         * Set Fast Pair discovery item.
+         *
+         * @param discoveryItem Fast Pair discovery item.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFastPairDiscoveryItem(@Nullable FastPairDiscoveryItem discoveryItem) {
+            if (discoveryItem == null) {
+                mBuilderParcel.discoveryItem = null;
+            } else {
+                mBuilderParcel.discoveryItem = discoveryItem.mMetadataParcel;
+            }
+            return this;
+        }
+
+        /**
+         * Build {@link FastPairAccountKeyDeviceMetadata} with the currently set configuration.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public FastPairAccountKeyDeviceMetadata build() {
+            return new FastPairAccountKeyDeviceMetadata(mBuilderParcel);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java
new file mode 100644
index 0000000..1837671
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataParcel;
+
+/**
+ * Class for a type of registered Fast Pair device keyed by modelID, or antispoofKey.
+ *
+ * @hide
+ */
+@SystemApi
+public class FastPairAntispoofKeyDeviceMetadata {
+
+    FastPairAntispoofKeyDeviceMetadataParcel mMetadataParcel;
+    FastPairAntispoofKeyDeviceMetadata(
+            FastPairAntispoofKeyDeviceMetadataParcel metadataParcel) {
+        this.mMetadataParcel = metadataParcel;
+    }
+
+    /**
+     * Get Antispoof public key.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getAntispoofPublicKey() {
+        return this.mMetadataParcel.antispoofPublicKey;
+    }
+
+    /**
+     * Get metadata of a Fast Pair device type.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public FastPairDeviceMetadata getFastPairDeviceMetadata() {
+        if (this.mMetadataParcel.deviceMetadata == null) {
+            return null;
+        }
+        return new FastPairDeviceMetadata(this.mMetadataParcel.deviceMetadata);
+    }
+
+    /**
+     * Builder used to create FastPairAntispoofkeyDeviceMetadata.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final FastPairAntispoofKeyDeviceMetadataParcel mBuilderParcel;
+
+        /**
+         * Default constructor of Builder.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {
+            mBuilderParcel = new FastPairAntispoofKeyDeviceMetadataParcel();
+            mBuilderParcel.antispoofPublicKey = null;
+            mBuilderParcel.deviceMetadata = null;
+        }
+
+        /**
+         * Set AntiSpoof public key, which uniquely identify a Fast Pair device type.
+         *
+         * @param antispoofPublicKey is 64 bytes, see <a href="https://developers.google.com/nearby/fast-pair/spec#data_format">Data Format</a>.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAntispoofPublicKey(@Nullable byte[] antispoofPublicKey) {
+            mBuilderParcel.antispoofPublicKey = antispoofPublicKey;
+            return this;
+        }
+
+        /**
+         * Set Fast Pair metadata, which is the property of a Fast Pair device type, including
+         * device images and strings.
+         *
+         * @param metadata Fast Pair device meta data.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFastPairDeviceMetadata(@Nullable FastPairDeviceMetadata metadata) {
+            if (metadata != null) {
+                mBuilderParcel.deviceMetadata = metadata.mMetadataParcel;
+            } else {
+                mBuilderParcel.deviceMetadata = null;
+            }
+            return this;
+        }
+
+        /**
+         * Build {@link FastPairAntispoofKeyDeviceMetadata} with the currently set configuration.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public FastPairAntispoofKeyDeviceMetadata build() {
+            return new FastPairAntispoofKeyDeviceMetadata(mBuilderParcel);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairClient.java b/nearby/framework/java/android/nearby/FastPairClient.java
new file mode 100644
index 0000000..dc70d71
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairClient.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.BinderThread;
+import android.content.Context;
+import android.nearby.aidl.IFastPairClient;
+import android.nearby.aidl.IFastPairStatusCallback;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * 0p API for controlling Fast Pair. It communicates between main thread and service.
+ *
+ * @hide
+ */
+public class FastPairClient {
+
+    private static final String TAG = "FastPairClient";
+    private final IBinder mBinder;
+    private final WeakReference<Context> mWeakContext;
+    IFastPairClient mFastPairClient;
+    PairStatusCallbackIBinder mPairStatusCallbackIBinder;
+
+    /**
+     * The Ibinder instance should be from
+     * {@link com.android.server.nearby.fastpair.halfsheet.FastPairService} so that the client can
+     * talk with the service.
+     */
+    public FastPairClient(Context context, IBinder binder) {
+        mBinder = binder;
+        mFastPairClient = IFastPairClient.Stub.asInterface(mBinder);
+        mWeakContext = new WeakReference<>(context);
+    }
+
+    /**
+     * Registers a callback at service to get UI updates.
+     */
+    public void registerHalfSheet(FastPairStatusCallback fastPairStatusCallback) {
+        if (mPairStatusCallbackIBinder != null) {
+            return;
+        }
+        mPairStatusCallbackIBinder = new PairStatusCallbackIBinder(fastPairStatusCallback);
+        try {
+            mFastPairClient.registerHalfSheet(mPairStatusCallbackIBinder);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to register fastPairStatusCallback", e);
+        }
+    }
+
+    /**
+     * Pairs the device at service.
+     */
+    public void connect(FastPairDevice fastPairDevice) {
+        try {
+            mFastPairClient.connect(fastPairDevice);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to connect Fast Pair device" + fastPairDevice, e);
+        }
+    }
+
+    private class PairStatusCallbackIBinder extends IFastPairStatusCallback.Stub {
+        private final FastPairStatusCallback mStatusCallback;
+
+        private PairStatusCallbackIBinder(FastPairStatusCallback fastPairStatusCallback) {
+            mStatusCallback = fastPairStatusCallback;
+        }
+
+        @BinderThread
+        @Override
+        public synchronized void onPairUpdate(FastPairDevice fastPairDevice,
+                PairStatusMetadata pairStatusMetadata) {
+            Context context = mWeakContext.get();
+            if (context != null) {
+                Handler handler = new Handler(context.getMainLooper());
+                handler.post(() ->
+                        mStatusCallback.onPairUpdate(fastPairDevice, pairStatusMetadata));
+            }
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairDataProviderService.java b/nearby/framework/java/android/nearby/FastPairDataProviderService.java
new file mode 100644
index 0000000..c6a1a65
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairDataProviderService.java
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.accounts.Account;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.nearby.aidl.ByteArrayParcel;
+import android.nearby.aidl.FastPairAccountDevicesMetadataRequestParcel;
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
+import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataRequestParcel;
+import android.nearby.aidl.FastPairEligibleAccountParcel;
+import android.nearby.aidl.FastPairEligibleAccountsRequestParcel;
+import android.nearby.aidl.FastPairManageAccountDeviceRequestParcel;
+import android.nearby.aidl.FastPairManageAccountRequestParcel;
+import android.nearby.aidl.IFastPairAccountDevicesMetadataCallback;
+import android.nearby.aidl.IFastPairAntispoofKeyDeviceMetadataCallback;
+import android.nearby.aidl.IFastPairDataProvider;
+import android.nearby.aidl.IFastPairEligibleAccountsCallback;
+import android.nearby.aidl.IFastPairManageAccountCallback;
+import android.nearby.aidl.IFastPairManageAccountDeviceCallback;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A service class for fast pair data providers outside the system server.
+ *
+ * Fast pair providers should be wrapped in a non-exported service which returns the result of
+ * {@link #getBinder()} from the service's {@link android.app.Service#onBind(Intent)} method. The
+ * service should not be exported so that components other than the system server cannot bind to it.
+ * Alternatively, the service may be guarded by a permission that only system server can obtain.
+ *
+ * <p>Fast Pair providers are identified by their UID / package name.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class FastPairDataProviderService extends Service {
+    /**
+     * The action the wrapping service should have in its intent filter to implement the
+     * {@link android.nearby.FastPairDataProviderBase}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_FAST_PAIR_DATA_PROVIDER =
+            "android.nearby.action.FAST_PAIR_DATA_PROVIDER";
+
+    /**
+     * Manage request type to add, or opt-in.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int MANAGE_REQUEST_ADD = 0;
+
+    /**
+     * Manage request type to remove, or opt-out.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int MANAGE_REQUEST_REMOVE = 1;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MANAGE_REQUEST_ADD,
+            MANAGE_REQUEST_REMOVE})
+    @interface ManageRequestType {}
+
+    /**
+     * Error code for bad request.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CODE_BAD_REQUEST = 0;
+
+    /**
+     * Error code for internal error.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CODE_INTERNAL_ERROR = 1;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            ERROR_CODE_BAD_REQUEST,
+            ERROR_CODE_INTERNAL_ERROR})
+    @interface ErrorCode {}
+
+    private final IBinder mBinder;
+    private final String mTag;
+
+    /**
+     * Constructor of FastPairDataProviderService.
+     *
+     * @param tag TAG for on device logging.
+     * @hide
+     */
+    @SystemApi
+    public FastPairDataProviderService(@NonNull String tag) {
+        mBinder = new Service();
+        mTag = tag;
+    }
+
+    @Override
+    @NonNull
+    public final IBinder onBind(@NonNull Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * Callback to be invoked when an AntispoofKeyed device metadata is loaded.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface FastPairAntispoofKeyDeviceMetadataCallback {
+
+        /**
+         * Invoked once the meta data is loaded.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onFastPairAntispoofKeyDeviceMetadataReceived(
+                @NonNull FastPairAntispoofKeyDeviceMetadata metadata);
+
+        /** Invoked in case of error.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onError(@ErrorCode int code, @Nullable String message);
+    }
+
+    /**
+     * Callback to be invoked when Fast Pair devices of a given account is loaded.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface FastPairAccountDevicesMetadataCallback {
+
+        /**
+         * Should be invoked once the metadatas are loaded.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onFastPairAccountDevicesMetadataReceived(
+                @NonNull Collection<FastPairAccountKeyDeviceMetadata> metadatas);
+        /**
+         * Invoked in case of error.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onError(@ErrorCode int code, @Nullable String message);
+    }
+
+    /**
+     * Callback to be invoked when FastPair eligible accounts are loaded.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface FastPairEligibleAccountsCallback {
+
+        /**
+         * Should be invoked once the eligible accounts are loaded.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onFastPairEligibleAccountsReceived(
+                @NonNull Collection<FastPairEligibleAccount> accounts);
+        /**
+         * Invoked in case of error.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onError(@ErrorCode int code, @Nullable String message);
+    }
+
+    /**
+     * Callback to be invoked when a management action is finished.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface FastPairManageActionCallback {
+
+        /**
+         * Should be invoked once the manage action is successful.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onSuccess();
+        /**
+         * Invoked in case of error.
+         *
+         * @hide
+         */
+        @SystemApi
+        void onError(@ErrorCode int code, @Nullable String message);
+    }
+
+    /**
+     * Fulfills the Fast Pair device metadata request by using callback to send back the
+     * device meta data of a given modelId.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract void onLoadFastPairAntispoofKeyDeviceMetadata(
+            @NonNull FastPairAntispoofKeyDeviceMetadataRequest request,
+            @NonNull FastPairAntispoofKeyDeviceMetadataCallback callback);
+
+    /**
+     * Fulfills the account tied Fast Pair devices metadata request by using callback to send back
+     * all Fast Pair device's metadata of a given account.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract void onLoadFastPairAccountDevicesMetadata(
+            @NonNull FastPairAccountDevicesMetadataRequest request,
+            @NonNull FastPairAccountDevicesMetadataCallback callback);
+
+    /**
+     * Fulfills the Fast Pair eligible accounts request by using callback to send back Fast Pair
+     * eligible accounts.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract void onLoadFastPairEligibleAccounts(
+            @NonNull FastPairEligibleAccountsRequest request,
+            @NonNull FastPairEligibleAccountsCallback callback);
+
+    /**
+     * Fulfills the Fast Pair account management request by using callback to send back result.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract void onManageFastPairAccount(
+            @NonNull FastPairManageAccountRequest request,
+            @NonNull FastPairManageActionCallback callback);
+
+    /**
+     * Fulfills the request to manage device-account mapping by using callback to send back result.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract void onManageFastPairAccountDevice(
+            @NonNull FastPairManageAccountDeviceRequest request,
+            @NonNull FastPairManageActionCallback callback);
+
+    /**
+     * Class for reading FastPairAntispoofKeyDeviceMetadataRequest, which specifies the model ID of
+     * a Fast Pair device. To fulfill this request, corresponding
+     * {@link FastPairAntispoofKeyDeviceMetadata} should be fetched and returned.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static class FastPairAntispoofKeyDeviceMetadataRequest {
+
+        private final FastPairAntispoofKeyDeviceMetadataRequestParcel mMetadataRequestParcel;
+
+        private FastPairAntispoofKeyDeviceMetadataRequest(
+                final FastPairAntispoofKeyDeviceMetadataRequestParcel metaDataRequestParcel) {
+            this.mMetadataRequestParcel = metaDataRequestParcel;
+        }
+
+        /**
+         * Get modelId (24 bit), the key for FastPairAntispoofKeyDeviceMetadata in the same format
+         * returned by Google at device registration time.
+         *
+         * ModelId format is defined at device registration time, see
+         * <a href="https://developers.google.com/nearby/fast-pair/spec#model_id">Model ID</a>.
+         * @return raw bytes of modelId in the same format returned by Google at device registration
+         *         time.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull byte[] getModelId() {
+            return this.mMetadataRequestParcel.modelId;
+        }
+    }
+
+    /**
+     * Class for reading FastPairAccountDevicesMetadataRequest, which specifies the Fast Pair
+     * account and the allow list of the FastPair device keys saved to the account (i.e., FastPair
+     * accountKeys).
+     *
+     * A Fast Pair accountKey is created when a Fast Pair device is saved to an account. It is per
+     * Fast Pair device per account.
+     *
+     * To retrieve all Fast Pair accountKeys saved to an account, the caller needs to set
+     * account with an empty allow list.
+     *
+     * To retrieve metadata of a selected list of Fast Pair devices saved to an account, the caller
+     * needs to set account with a non-empty allow list.
+     * @hide
+     */
+    @SystemApi
+    public static class FastPairAccountDevicesMetadataRequest {
+
+        private final FastPairAccountDevicesMetadataRequestParcel mMetadataRequestParcel;
+
+        private FastPairAccountDevicesMetadataRequest(
+                final FastPairAccountDevicesMetadataRequestParcel metaDataRequestParcel) {
+            this.mMetadataRequestParcel = metaDataRequestParcel;
+        }
+
+        /**
+         * Get FastPair account, whose Fast Pair devices' metadata is requested.
+         *
+         * @return a FastPair account.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Account getAccount() {
+            return this.mMetadataRequestParcel.account;
+        }
+
+        /**
+         * Get allowlist of Fast Pair devices using a collection of deviceAccountKeys.
+         * Note that as a special case, empty list actually means all FastPair devices under the
+         * account instead of none.
+         *
+         * DeviceAccountKey is 16 bytes: first byte is 0x04. Other 15 bytes are randomly generated.
+         *
+         * @return allowlist of Fast Pair devices using a collection of deviceAccountKeys.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Collection<byte[]> getDeviceAccountKeys()  {
+            if (this.mMetadataRequestParcel.deviceAccountKeys == null) {
+                return new ArrayList<byte[]>(0);
+            }
+            List<byte[]> deviceAccountKeys =
+                    new ArrayList<>(this.mMetadataRequestParcel.deviceAccountKeys.length);
+            for (ByteArrayParcel deviceAccountKey : this.mMetadataRequestParcel.deviceAccountKeys) {
+                deviceAccountKeys.add(deviceAccountKey.byteArray);
+            }
+            return deviceAccountKeys;
+        }
+    }
+
+    /**
+     *  Class for reading FastPairEligibleAccountsRequest. Upon receiving this request, Fast Pair
+     *  eligible accounts should be returned to bind Fast Pair devices.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static class FastPairEligibleAccountsRequest {
+        @SuppressWarnings("UnusedVariable")
+        private final FastPairEligibleAccountsRequestParcel mAccountsRequestParcel;
+
+        private FastPairEligibleAccountsRequest(
+                final FastPairEligibleAccountsRequestParcel accountsRequestParcel) {
+            this.mAccountsRequestParcel = accountsRequestParcel;
+        }
+    }
+
+    /**
+     * Class for reading FastPairManageAccountRequest. If the request type is MANAGE_REQUEST_ADD,
+     * the account is enabled to bind Fast Pair devices; If the request type is
+     * MANAGE_REQUEST_REMOVE, the account is disabled to bind more Fast Pair devices. Furthermore,
+     * all existing bounded Fast Pair devices are unbounded.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static class FastPairManageAccountRequest {
+
+        private final FastPairManageAccountRequestParcel mAccountRequestParcel;
+
+        private FastPairManageAccountRequest(
+                final FastPairManageAccountRequestParcel accountRequestParcel) {
+            this.mAccountRequestParcel = accountRequestParcel;
+        }
+
+        /**
+         * Get request type: MANAGE_REQUEST_ADD, or MANAGE_REQUEST_REMOVE.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @ManageRequestType int getRequestType() {
+            return this.mAccountRequestParcel.requestType;
+        }
+        /**
+         * Get account.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Account getAccount() {
+            return this.mAccountRequestParcel.account;
+        }
+    }
+
+    /**
+     *  Class for reading FastPairManageAccountDeviceRequest. If the request type is
+     *  MANAGE_REQUEST_ADD, then a Fast Pair device is bounded to a Fast Pair account. If the
+     *  request type is MANAGE_REQUEST_REMOVE, then a Fast Pair device is removed from a Fast Pair
+     *  account.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static class FastPairManageAccountDeviceRequest {
+
+        private final FastPairManageAccountDeviceRequestParcel mRequestParcel;
+
+        private FastPairManageAccountDeviceRequest(
+                final FastPairManageAccountDeviceRequestParcel requestParcel) {
+            this.mRequestParcel = requestParcel;
+        }
+
+        /**
+         * Get request type: MANAGE_REQUEST_ADD, or MANAGE_REQUEST_REMOVE.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @ManageRequestType int getRequestType() {
+            return this.mRequestParcel.requestType;
+        }
+        /**
+         * Get account.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Account getAccount() {
+            return this.mRequestParcel.account;
+        }
+        /**
+         * Get BleAddress.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @Nullable String getBleAddress() {
+            return this.mRequestParcel.bleAddress;
+        }
+        /**
+         * Get account key device metadata.
+         *
+         * @hide
+         */
+        @SystemApi
+        public @NonNull FastPairAccountKeyDeviceMetadata getAccountKeyDeviceMetadata() {
+            return new FastPairAccountKeyDeviceMetadata(
+                    this.mRequestParcel.accountKeyDeviceMetadata);
+        }
+    }
+
+    /**
+     * Callback class that sends back FastPairAntispoofKeyDeviceMetadata.
+     */
+    private final class WrapperFastPairAntispoofKeyDeviceMetadataCallback implements
+            FastPairAntispoofKeyDeviceMetadataCallback {
+
+        private IFastPairAntispoofKeyDeviceMetadataCallback mCallback;
+
+        private WrapperFastPairAntispoofKeyDeviceMetadataCallback(
+                IFastPairAntispoofKeyDeviceMetadataCallback callback) {
+            mCallback = callback;
+        }
+
+        /**
+         * Sends back FastPairAntispoofKeyDeviceMetadata.
+         */
+        @Override
+        public void onFastPairAntispoofKeyDeviceMetadataReceived(
+                @NonNull FastPairAntispoofKeyDeviceMetadata metadata) {
+            try {
+                mCallback.onFastPairAntispoofKeyDeviceMetadataReceived(metadata.mMetadataParcel);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+
+        @Override
+        public void onError(@ErrorCode int code, @Nullable String message) {
+            try {
+                mCallback.onError(code, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    /**
+     * Callback class that sends back collection of FastPairAccountKeyDeviceMetadata.
+     */
+    private final class WrapperFastPairAccountDevicesMetadataCallback implements
+            FastPairAccountDevicesMetadataCallback {
+
+        private IFastPairAccountDevicesMetadataCallback mCallback;
+
+        private WrapperFastPairAccountDevicesMetadataCallback(
+                IFastPairAccountDevicesMetadataCallback callback) {
+            mCallback = callback;
+        }
+
+        /**
+         * Sends back collection of FastPairAccountKeyDeviceMetadata.
+         */
+        @Override
+        public void onFastPairAccountDevicesMetadataReceived(
+                @NonNull Collection<FastPairAccountKeyDeviceMetadata> metadatas) {
+            FastPairAccountKeyDeviceMetadataParcel[] metadataParcels =
+                    new FastPairAccountKeyDeviceMetadataParcel[metadatas.size()];
+            int i = 0;
+            for (FastPairAccountKeyDeviceMetadata metadata : metadatas) {
+                metadataParcels[i] = metadata.mMetadataParcel;
+                i = i + 1;
+            }
+            try {
+                mCallback.onFastPairAccountDevicesMetadataReceived(metadataParcels);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+
+        @Override
+        public void onError(@ErrorCode int code, @Nullable String message) {
+            try {
+                mCallback.onError(code, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    /**
+     * Callback class that sends back eligible Fast Pair accounts.
+     */
+    private final class WrapperFastPairEligibleAccountsCallback implements
+            FastPairEligibleAccountsCallback {
+
+        private IFastPairEligibleAccountsCallback mCallback;
+
+        private WrapperFastPairEligibleAccountsCallback(
+                IFastPairEligibleAccountsCallback callback) {
+            mCallback = callback;
+        }
+
+        /**
+         * Sends back the eligible Fast Pair accounts.
+         */
+        @Override
+        public void onFastPairEligibleAccountsReceived(
+                @NonNull Collection<FastPairEligibleAccount> accounts) {
+            int i = 0;
+            FastPairEligibleAccountParcel[] accountParcels =
+                    new FastPairEligibleAccountParcel[accounts.size()];
+            for (FastPairEligibleAccount account: accounts) {
+                accountParcels[i] = account.mAccountParcel;
+                i = i + 1;
+            }
+            try {
+                mCallback.onFastPairEligibleAccountsReceived(accountParcels);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+
+        @Override
+        public void onError(@ErrorCode int code, @Nullable String message) {
+            try {
+                mCallback.onError(code, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    /**
+     * Callback class that sends back Fast Pair account management result.
+     */
+    private final class WrapperFastPairManageAccountCallback implements
+            FastPairManageActionCallback {
+
+        private IFastPairManageAccountCallback mCallback;
+
+        private WrapperFastPairManageAccountCallback(
+                IFastPairManageAccountCallback callback) {
+            mCallback = callback;
+        }
+
+        /**
+         * Sends back Fast Pair account opt in result.
+         */
+        @Override
+        public void onSuccess() {
+            try {
+                mCallback.onSuccess();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+
+        @Override
+        public void onError(@ErrorCode int code, @Nullable String message) {
+            try {
+                mCallback.onError(code, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    /**
+     * Call back class that sends back account-device mapping management result.
+     */
+    private final class WrapperFastPairManageAccountDeviceCallback implements
+            FastPairManageActionCallback {
+
+        private IFastPairManageAccountDeviceCallback mCallback;
+
+        private WrapperFastPairManageAccountDeviceCallback(
+                IFastPairManageAccountDeviceCallback callback) {
+            mCallback = callback;
+        }
+
+        /**
+         * Sends back the account-device mapping management result.
+         */
+        @Override
+        public void onSuccess() {
+            try {
+                mCallback.onSuccess();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+
+        @Override
+        public void onError(@ErrorCode int code, @Nullable String message) {
+            try {
+                mCallback.onError(code, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } catch (RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    private final class Service extends IFastPairDataProvider.Stub {
+
+        Service() {
+        }
+
+        @Override
+        public void loadFastPairAntispoofKeyDeviceMetadata(
+                @NonNull FastPairAntispoofKeyDeviceMetadataRequestParcel requestParcel,
+                IFastPairAntispoofKeyDeviceMetadataCallback callback) {
+            onLoadFastPairAntispoofKeyDeviceMetadata(
+                    new FastPairAntispoofKeyDeviceMetadataRequest(requestParcel),
+                    new WrapperFastPairAntispoofKeyDeviceMetadataCallback(callback));
+        }
+
+        @Override
+        public void loadFastPairAccountDevicesMetadata(
+                @NonNull FastPairAccountDevicesMetadataRequestParcel requestParcel,
+                IFastPairAccountDevicesMetadataCallback callback) {
+            onLoadFastPairAccountDevicesMetadata(
+                    new FastPairAccountDevicesMetadataRequest(requestParcel),
+                    new WrapperFastPairAccountDevicesMetadataCallback(callback));
+        }
+
+        @Override
+        public void loadFastPairEligibleAccounts(
+                @NonNull FastPairEligibleAccountsRequestParcel requestParcel,
+                IFastPairEligibleAccountsCallback callback) {
+            onLoadFastPairEligibleAccounts(new FastPairEligibleAccountsRequest(requestParcel),
+                    new WrapperFastPairEligibleAccountsCallback(callback));
+        }
+
+        @Override
+        public void manageFastPairAccount(
+                @NonNull FastPairManageAccountRequestParcel requestParcel,
+                IFastPairManageAccountCallback callback) {
+            onManageFastPairAccount(new FastPairManageAccountRequest(requestParcel),
+                    new WrapperFastPairManageAccountCallback(callback));
+        }
+
+        @Override
+        public void manageFastPairAccountDevice(
+                @NonNull FastPairManageAccountDeviceRequestParcel requestParcel,
+                IFastPairManageAccountDeviceCallback callback) {
+            onManageFastPairAccountDevice(new FastPairManageAccountDeviceRequest(requestParcel),
+                    new WrapperFastPairManageAccountDeviceCallback(callback));
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairDevice.aidl b/nearby/framework/java/android/nearby/FastPairDevice.aidl
new file mode 100644
index 0000000..5942966
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairDevice.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.nearby;
+
+/**
+ * A class represents a Fast Pair device that can be discovered by multiple mediums.
+ *
+ * {@hide}
+ */
+parcelable FastPairDevice;
diff --git a/nearby/framework/java/android/nearby/FastPairDevice.java b/nearby/framework/java/android/nearby/FastPairDevice.java
new file mode 100644
index 0000000..e12b4f8
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairDevice.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class represents a Fast Pair device that can be discovered by multiple mediums.
+ *
+ * @hide
+ */
+public class FastPairDevice extends NearbyDevice implements Parcelable {
+    /**
+     * Used to read a FastPairDevice from a Parcel.
+     */
+    public static final Creator<FastPairDevice> CREATOR = new Creator<FastPairDevice>() {
+        @Override
+        public FastPairDevice createFromParcel(Parcel in) {
+            FastPairDevice.Builder builder = new FastPairDevice.Builder();
+            if (in.readInt() == 1) {
+                builder.setName(in.readString());
+            }
+            int size = in.readInt();
+            for (int i = 0; i < size; i++) {
+                builder.addMedium(in.readInt());
+            }
+            builder.setRssi(in.readInt());
+            if (in.readInt() == 1) {
+                builder.setModelId(in.readString());
+            }
+            builder.setBluetoothAddress(in.readString());
+            if (in.readInt() == 1) {
+                int dataLength = in.readInt();
+                byte[] data = new byte[dataLength];
+                in.readByteArray(data);
+                builder.setData(data);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public FastPairDevice[] newArray(int size) {
+            return new FastPairDevice[size];
+        }
+    };
+
+    // Some OEM devices devices don't have model Id.
+    @Nullable private final String mModelId;
+
+    // Bluetooth hardware address as string. Can be read from BLE ScanResult.
+    private final String mBluetoothAddress;
+
+    @Nullable
+    private final byte[] mData;
+
+    /**
+     * Creates a new FastPairDevice.
+     *
+     * @param name Name of the FastPairDevice. Can be {@code null} if there is no name.
+     * @param mediums The {@link Medium}s over which the device is discovered.
+     * @param rssi The received signal strength in dBm.
+     * @param modelId The identifier of the Fast Pair device.
+     *                Can be {@code null} if there is no Model ID.
+     * @param bluetoothAddress The hardware address of this BluetoothDevice.
+     * @param data Extra data for a Fast Pair device.
+     */
+    public FastPairDevice(@Nullable String name,
+            List<Integer> mediums,
+            int rssi,
+            @Nullable String modelId,
+            @NonNull String bluetoothAddress,
+            @Nullable byte[] data) {
+        super(name, mediums, rssi);
+        this.mModelId = modelId;
+        this.mBluetoothAddress = bluetoothAddress;
+        this.mData = data;
+    }
+
+    /**
+     * Gets the identifier of the Fast Pair device. Can be {@code null} if there is no Model ID.
+     */
+    @Nullable
+    public String getModelId() {
+        return this.mModelId;
+    }
+
+    /**
+     * Gets the hardware address of this BluetoothDevice.
+     */
+    @NonNull
+    public String getBluetoothAddress() {
+        return mBluetoothAddress;
+    }
+
+    /**
+     * Gets the extra data for a Fast Pair device. Can be {@code null} if there is extra data.
+     *
+     * @hide
+     */
+    @Nullable
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * No special parcel contents.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Returns a string representation of this FastPairDevice.
+     */
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("FastPairDevice [");
+        String name = getName();
+        if (getName() != null && !name.isEmpty()) {
+            stringBuilder.append("name=").append(name).append(", ");
+        }
+        stringBuilder.append("medium={");
+        for (int medium: getMediums()) {
+            stringBuilder.append(mediumToString(medium));
+        }
+        stringBuilder.append("} rssi=").append(getRssi());
+        stringBuilder.append(" modelId=").append(mModelId);
+        stringBuilder.append(" bluetoothAddress=").append(mBluetoothAddress);
+        stringBuilder.append("]");
+        return stringBuilder.toString();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof FastPairDevice) {
+            FastPairDevice otherDevice = (FastPairDevice) other;
+            if (!super.equals(other)) {
+                return false;
+            }
+            return Objects.equals(mModelId, otherDevice.mModelId)
+                    && Objects.equals(mBluetoothAddress, otherDevice.mBluetoothAddress)
+                    && Arrays.equals(mData, otherDevice.mData);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                getName(), getMediums(), getRssi(), mModelId, mBluetoothAddress,
+                Arrays.hashCode(mData));
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        String name = getName();
+        dest.writeInt(name == null ? 0 : 1);
+        if (name != null) {
+            dest.writeString(name);
+        }
+        List<Integer> mediums = getMediums();
+        dest.writeInt(mediums.size());
+        for (int medium : mediums) {
+            dest.writeInt(medium);
+        }
+        dest.writeInt(getRssi());
+        dest.writeInt(mModelId == null ? 0 : 1);
+        if (mModelId != null) {
+            dest.writeString(mModelId);
+        }
+        dest.writeString(mBluetoothAddress);
+        dest.writeInt(mData == null ? 0 : 1);
+        if (mData != null) {
+            dest.writeInt(mData.length);
+            dest.writeByteArray(mData);
+        }
+    }
+
+    /**
+     * A builder class for {@link FastPairDevice}
+     *
+     * @hide
+     */
+    public static final class Builder {
+        private final List<Integer> mMediums;
+
+        @Nullable private String mName;
+        private int mRssi;
+        @Nullable private String mModelId;
+        private String mBluetoothAddress;
+        @Nullable private byte[] mData;
+
+        public Builder() {
+            mMediums = new ArrayList<>();
+        }
+
+        /**
+         * Sets the name of the Fast Pair device.
+         *
+         * @param name Name of the FastPairDevice. Can be {@code null} if there is no name.
+         */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Sets the medium over which the Fast Pair device is discovered.
+         *
+         * @param medium The {@link Medium} over which the device is discovered.
+         */
+        @NonNull
+        public Builder addMedium(@Medium int medium) {
+            mMediums.add(medium);
+            return this;
+        }
+
+        /**
+         * Sets the RSSI between the scan device and the discovered Fast Pair device.
+         *
+         * @param rssi The received signal strength in dBm.
+         */
+        @NonNull
+        public Builder setRssi(@IntRange(from = -127, to = 126) int rssi) {
+            mRssi = rssi;
+            return this;
+        }
+
+        /**
+         * Sets the model Id of this Fast Pair device.
+         *
+         * @param modelId The identifier of the Fast Pair device. Can be {@code null}
+         *                if there is no Model ID.
+         */
+        @NonNull
+        public Builder setModelId(@Nullable String modelId) {
+            mModelId = modelId;
+            return this;
+        }
+
+        /**
+         * Sets the hardware address of this BluetoothDevice.
+         *
+         * @param bluetoothAddress The hardware address of this BluetoothDevice.
+         */
+        @NonNull
+        public Builder setBluetoothAddress(@NonNull String bluetoothAddress) {
+            Objects.requireNonNull(bluetoothAddress);
+            mBluetoothAddress = bluetoothAddress;
+            return this;
+        }
+
+        /**
+         * Sets the raw data for a FastPairDevice. Can be {@code null} if there is no extra data.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setData(@Nullable byte[] data) {
+            mData = data;
+            return this;
+        }
+
+        /**
+         * Builds a FastPairDevice and return it.
+         */
+        @NonNull
+        public FastPairDevice build() {
+            return new FastPairDevice(mName, mMediums, mRssi, mModelId,
+                    mBluetoothAddress, mData);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
new file mode 100644
index 0000000..ea75271
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nearby.aidl.FastPairDeviceMetadataParcel;
+
+/**
+ * Class for the properties of a given type of Fast Pair device, including images and text.
+ *
+ * @hide
+ */
+@SystemApi
+public class FastPairDeviceMetadata {
+
+    FastPairDeviceMetadataParcel mMetadataParcel;
+
+    FastPairDeviceMetadata(
+            FastPairDeviceMetadataParcel metadataParcel) {
+        this.mMetadataParcel = metadataParcel;
+    }
+
+    /**
+     * Get ImageUrl, which will be displayed in notification.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getImageUrl() {
+        return mMetadataParcel.imageUrl;
+    }
+
+    /**
+     * Get IntentUri, which will be launched to install companion app.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getIntentUri() {
+        return mMetadataParcel.intentUri;
+    }
+
+    /**
+     * Get BLE transmit power, as described in Fast Pair spec, see
+     * <a href="https://developers.google.com/nearby/fast-pair/spec#transmit_power">Transmit Power</a>
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getBleTxPower() {
+        return mMetadataParcel.bleTxPower;
+    }
+
+    /**
+     * Get Fast Pair Half Sheet trigger distance in meters.
+     *
+     * @hide
+     */
+    @SystemApi
+    public float getTriggerDistance() {
+        return mMetadataParcel.triggerDistance;
+    }
+
+    /**
+     * Get Fast Pair device image, which is submitted at device registration time to display on
+     * notification. It is a 32-bit PNG with dimensions of 512px by 512px.
+     *
+     * @return Fast Pair device image in 32-bit PNG with dimensions of 512px by 512px.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getImage() {
+        return mMetadataParcel.image;
+    }
+
+    /**
+     * Get Fast Pair device type.
+     * DEVICE_TYPE_UNSPECIFIED = 0;
+     * HEADPHONES = 1;
+     * TRUE_WIRELESS_HEADPHONES = 7;
+     * @hide
+     */
+    @SystemApi
+    public int getDeviceType() {
+        return mMetadataParcel.deviceType;
+    }
+
+    /**
+     * Get Fast Pair device name. e.g., "Pixel Buds A-Series".
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getName() {
+        return mMetadataParcel.name;
+    }
+
+    /**
+     * Get true wireless image url for left bud.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getTrueWirelessImageUrlLeftBud() {
+        return mMetadataParcel.trueWirelessImageUrlLeftBud;
+    }
+
+    /**
+     * Get true wireless image url for right bud.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getTrueWirelessImageUrlRightBud() {
+        return mMetadataParcel.trueWirelessImageUrlRightBud;
+    }
+
+    /**
+     * Get true wireless image url for case.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getTrueWirelessImageUrlCase() {
+        return mMetadataParcel.trueWirelessImageUrlCase;
+    }
+
+    /**
+     * Get Locale of the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getLocale() {
+        return mMetadataParcel.locale;
+    }
+
+    /**
+     * Get InitialNotificationDescription, which is a translated string of
+     * "Tap to pair. Earbuds will be tied to %s" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getInitialNotificationDescription() {
+        return mMetadataParcel.initialNotificationDescription;
+    }
+
+    /**
+     * Get InitialNotificationDescriptionNoAccount, which is a translated string of
+     * "Tap to pair with this device" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getInitialNotificationDescriptionNoAccount() {
+        return mMetadataParcel.initialNotificationDescriptionNoAccount;
+    }
+
+    /**
+     * Get OpenCompanionAppDescription, which is a translated string of
+     * "Tap to finish setup" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getOpenCompanionAppDescription() {
+        return mMetadataParcel.openCompanionAppDescription;
+    }
+
+    /**
+     * Get UpdateCompanionAppDescription, which is a translated string of
+     * "Tap to update device settings and finish setup" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getUpdateCompanionAppDescription() {
+        return mMetadataParcel.updateCompanionAppDescription;
+    }
+
+    /**
+     * Get DownloadCompanionAppDescription, which is a translated string of
+     * "Tap to download device app on Google Play and see all features" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getDownloadCompanionAppDescription() {
+        return mMetadataParcel.downloadCompanionAppDescription;
+    }
+
+    /**
+     * Get UnableToConnectTitle, which is a translated string of
+     * "Unable to connect" based on locale.
+     */
+    @Nullable
+    public String getUnableToConnectTitle() {
+        return mMetadataParcel.unableToConnectTitle;
+    }
+
+    /**
+     * Get UnableToConnectDescription, which is a translated string of
+     * "Try manually pairing to the device" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getUnableToConnectDescription() {
+        return mMetadataParcel.unableToConnectDescription;
+    }
+
+    /**
+     * Get InitialPairingDescription, which is a translated string of
+     * "%s will appear on devices linked with %s" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getInitialPairingDescription() {
+        return mMetadataParcel.initialPairingDescription;
+    }
+
+    /**
+     * Get ConnectSuccessCompanionAppInstalled, which is a translated string of
+     * "Your device is ready to be set up" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getConnectSuccessCompanionAppInstalled() {
+        return mMetadataParcel.connectSuccessCompanionAppInstalled;
+    }
+
+    /**
+     * Get ConnectSuccessCompanionAppNotInstalled, which is a translated string of
+     * "Download the device app on Google Play to see all available features" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getConnectSuccessCompanionAppNotInstalled() {
+        return mMetadataParcel.connectSuccessCompanionAppNotInstalled;
+    }
+
+    /**
+     * Get SubsequentPairingDescription, which is a translated string of
+     * "Connect %s to this phone" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getSubsequentPairingDescription() {
+        return mMetadataParcel.subsequentPairingDescription;
+    }
+
+    /**
+     * Get RetroactivePairingDescription, which is a translated string of
+     * "Save device to %s for faster pairing to your other devices" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getRetroactivePairingDescription() {
+        return mMetadataParcel.retroactivePairingDescription;
+    }
+
+    /**
+     * Get WaitLaunchCompanionAppDescription, which is a translated string of
+     * "This will take a few moments" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getWaitLaunchCompanionAppDescription() {
+        return mMetadataParcel.waitLaunchCompanionAppDescription;
+    }
+
+    /**
+     * Get FailConnectGoToSettingsDescription, which is a translated string of
+     * "Try manually pairing to the device by going to Settings" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getFailConnectGoToSettingsDescription() {
+        return mMetadataParcel.failConnectGoToSettingsDescription;
+    }
+
+    /**
+     * Get ConfirmPinTitle, which is a translated string of
+     * based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getConfirmPinTitle() {
+        return mMetadataParcel.confirmPinTitle;
+    }
+
+    /**
+     * Get ConfirmPinDescription, which is a translated string of "confirm pin" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getConfirmPinDescription() {
+        return mMetadataParcel.confirmPinDescription;
+    }
+
+    /**
+     * Get SyncContactsTitle, which is a translated string of "sync contacts title" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getSyncContactsTitle() {
+        return mMetadataParcel.syncContactsTitle;
+    }
+
+    /**
+     * Get SyncContactsDescription, which is a translated string of "sync contacts description"
+     * based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getSyncContactsDescription() {
+        return mMetadataParcel.syncContactsDescription;
+    }
+
+    /**
+     * Get SyncSmsTitle, which is a translated string of "sync sms title" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getSyncSmsTitle() {
+        return mMetadataParcel.syncSmsTitle;
+    }
+
+    /**
+     * Get SyncSmsDescription, which is a translated string of "sync sms description" based on
+     * locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getSyncSmsDescription() {
+        return mMetadataParcel.syncSmsDescription;
+    }
+
+    /**
+     * Get AssistantSetupHalfSheet, which is a translated string of
+     * "Tap to set up your Google Assistant" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getAssistantSetupHalfSheet() {
+        return mMetadataParcel.assistantSetupHalfSheet;
+    }
+
+    /**
+     * Get AssistantSetupNotification, which is a translated string of
+     * "Tap to set up your Google Assistant" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getAssistantSetupNotification() {
+        return mMetadataParcel.assistantSetupNotification;
+    }
+
+    /**
+     * Get FastPairTvConnectDeviceNoAccountDescription, which is a translated string of
+     * "Select connect to pair your %s with this device" based on locale.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getFastPairTvConnectDeviceNoAccountDescription() {
+        return mMetadataParcel.fastPairTvConnectDeviceNoAccountDescription;
+    }
+
+    /**
+     * Builder used to create FastPairDeviceMetadata.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final FastPairDeviceMetadataParcel mBuilderParcel;
+
+        /**
+         * Default constructor of Builder.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {
+            mBuilderParcel = new FastPairDeviceMetadataParcel();
+            mBuilderParcel.imageUrl = null;
+            mBuilderParcel.intentUri = null;
+            mBuilderParcel.name = null;
+            mBuilderParcel.bleTxPower = 0;
+            mBuilderParcel.triggerDistance = 0;
+            mBuilderParcel.image = null;
+            mBuilderParcel.deviceType = 0;  // DEVICE_TYPE_UNSPECIFIED
+            mBuilderParcel.trueWirelessImageUrlLeftBud = null;
+            mBuilderParcel.trueWirelessImageUrlRightBud = null;
+            mBuilderParcel.trueWirelessImageUrlCase = null;
+            mBuilderParcel.locale = null;
+            mBuilderParcel.initialNotificationDescription = null;
+            mBuilderParcel.initialNotificationDescriptionNoAccount = null;
+            mBuilderParcel.openCompanionAppDescription = null;
+            mBuilderParcel.updateCompanionAppDescription = null;
+            mBuilderParcel.downloadCompanionAppDescription = null;
+            mBuilderParcel.unableToConnectTitle = null;
+            mBuilderParcel.unableToConnectDescription = null;
+            mBuilderParcel.initialPairingDescription = null;
+            mBuilderParcel.connectSuccessCompanionAppInstalled = null;
+            mBuilderParcel.connectSuccessCompanionAppNotInstalled = null;
+            mBuilderParcel.subsequentPairingDescription = null;
+            mBuilderParcel.retroactivePairingDescription = null;
+            mBuilderParcel.waitLaunchCompanionAppDescription = null;
+            mBuilderParcel.failConnectGoToSettingsDescription = null;
+            mBuilderParcel.confirmPinTitle = null;
+            mBuilderParcel.confirmPinDescription = null;
+            mBuilderParcel.syncContactsTitle = null;
+            mBuilderParcel.syncContactsDescription = null;
+            mBuilderParcel.syncSmsTitle = null;
+            mBuilderParcel.syncSmsDescription = null;
+            mBuilderParcel.assistantSetupHalfSheet = null;
+            mBuilderParcel.assistantSetupNotification = null;
+            mBuilderParcel.fastPairTvConnectDeviceNoAccountDescription = null;
+        }
+
+        /**
+         * Set ImageUlr.
+         *
+         * @param imageUrl Image Ulr.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setImageUrl(@Nullable String imageUrl) {
+            mBuilderParcel.imageUrl = imageUrl;
+            return this;
+        }
+
+        /**
+         * Set IntentUri.
+         *
+         * @param intentUri Intent uri.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setIntentUri(@Nullable String intentUri) {
+            mBuilderParcel.intentUri = intentUri;
+            return this;
+        }
+
+        /**
+         * Set device name.
+         *
+         * @param name Device name.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mBuilderParcel.name = name;
+            return this;
+        }
+
+        /**
+         * Set ble transmission power.
+         *
+         * @param bleTxPower Ble transmission power.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setBleTxPower(int bleTxPower) {
+            mBuilderParcel.bleTxPower = bleTxPower;
+            return this;
+        }
+
+        /**
+         * Set trigger distance.
+         *
+         * @param triggerDistance Fast Pair trigger distance.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTriggerDistance(float triggerDistance) {
+            mBuilderParcel.triggerDistance = triggerDistance;
+            return this;
+        }
+
+        /**
+         * Set image.
+         *
+         * @param image Fast Pair device image, which is submitted at device registration time to
+         *              display on notification. It is a 32-bit PNG with dimensions of
+         *              512px by 512px.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setImage(@Nullable byte[] image) {
+            mBuilderParcel.image = image;
+            return this;
+        }
+
+        /**
+         * Set device type.
+         *
+         * @param deviceType Fast Pair device type.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDeviceType(int deviceType) {
+            mBuilderParcel.deviceType = deviceType;
+            return this;
+        }
+
+        /**
+         * Set true wireless image url for left bud.
+         *
+         * @param trueWirelessImageUrlLeftBud True wireless image url for left bud.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTrueWirelessImageUrlLeftBud(
+                @Nullable String trueWirelessImageUrlLeftBud) {
+            mBuilderParcel.trueWirelessImageUrlLeftBud = trueWirelessImageUrlLeftBud;
+            return this;
+        }
+
+        /**
+         * Set true wireless image url for right bud.
+         *
+         * @param trueWirelessImageUrlRightBud True wireless image url for right bud.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTrueWirelessImageUrlRightBud(
+                @Nullable String trueWirelessImageUrlRightBud) {
+            mBuilderParcel.trueWirelessImageUrlRightBud = trueWirelessImageUrlRightBud;
+            return this;
+        }
+
+        /**
+         * Set true wireless image url for case.
+         *
+         * @param trueWirelessImageUrlCase True wireless image url for case.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTrueWirelessImageUrlCase(@Nullable String trueWirelessImageUrlCase) {
+            mBuilderParcel.trueWirelessImageUrlCase = trueWirelessImageUrlCase;
+            return this;
+        }
+
+        /**
+         * Set Locale.
+         *
+         * @param locale Device locale.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setLocale(@Nullable String locale) {
+            mBuilderParcel.locale = locale;
+            return this;
+        }
+
+        /**
+         * Set InitialNotificationDescription.
+         *
+         * @param initialNotificationDescription Initial notification description.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setInitialNotificationDescription(
+                @Nullable String initialNotificationDescription) {
+            mBuilderParcel.initialNotificationDescription = initialNotificationDescription;
+            return this;
+        }
+
+        /**
+         * Set InitialNotificationDescriptionNoAccount.
+         *
+         * @param initialNotificationDescriptionNoAccount Initial notification description when
+         *                                                account is not present.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setInitialNotificationDescriptionNoAccount(
+                @Nullable String initialNotificationDescriptionNoAccount) {
+            mBuilderParcel.initialNotificationDescriptionNoAccount =
+                    initialNotificationDescriptionNoAccount;
+            return this;
+        }
+
+        /**
+         * Set OpenCompanionAppDescription.
+         *
+         * @param openCompanionAppDescription Description for opening companion app.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setOpenCompanionAppDescription(
+                @Nullable String openCompanionAppDescription) {
+            mBuilderParcel.openCompanionAppDescription = openCompanionAppDescription;
+            return this;
+        }
+
+        /**
+         * Set UpdateCompanionAppDescription.
+         *
+         * @param updateCompanionAppDescription Description for updating companion app.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setUpdateCompanionAppDescription(
+                @Nullable String updateCompanionAppDescription) {
+            mBuilderParcel.updateCompanionAppDescription = updateCompanionAppDescription;
+            return this;
+        }
+
+        /**
+         * Set DownloadCompanionAppDescription.
+         *
+         * @param downloadCompanionAppDescription Description for downloading companion app.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDownloadCompanionAppDescription(
+                @Nullable String downloadCompanionAppDescription) {
+            mBuilderParcel.downloadCompanionAppDescription = downloadCompanionAppDescription;
+            return this;
+        }
+
+        /**
+         * Set UnableToConnectTitle.
+         *
+         * @param unableToConnectTitle Title when Fast Pair device is unable to be connected to.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setUnableToConnectTitle(@Nullable String unableToConnectTitle) {
+            mBuilderParcel.unableToConnectTitle = unableToConnectTitle;
+            return this;
+        }
+
+        /**
+         * Set UnableToConnectDescription.
+         *
+         * @param unableToConnectDescription Description when Fast Pair device is unable to be
+         *                                   connected to.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setUnableToConnectDescription(
+                @Nullable String unableToConnectDescription) {
+            mBuilderParcel.unableToConnectDescription = unableToConnectDescription;
+            return this;
+        }
+
+        /**
+         * Set InitialPairingDescription.
+         *
+         * @param initialPairingDescription Description for Fast Pair initial pairing.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setInitialPairingDescription(@Nullable String initialPairingDescription) {
+            mBuilderParcel.initialPairingDescription = initialPairingDescription;
+            return this;
+        }
+
+        /**
+         * Set ConnectSuccessCompanionAppInstalled.
+         *
+         * @param connectSuccessCompanionAppInstalled Description that let user open the companion
+         *                                            app.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setConnectSuccessCompanionAppInstalled(
+                @Nullable String connectSuccessCompanionAppInstalled) {
+            mBuilderParcel.connectSuccessCompanionAppInstalled =
+                    connectSuccessCompanionAppInstalled;
+            return this;
+        }
+
+        /**
+         * Set ConnectSuccessCompanionAppNotInstalled.
+         *
+         * @param connectSuccessCompanionAppNotInstalled Description that let user download the
+         *                                               companion app.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setConnectSuccessCompanionAppNotInstalled(
+                @Nullable String connectSuccessCompanionAppNotInstalled) {
+            mBuilderParcel.connectSuccessCompanionAppNotInstalled =
+                    connectSuccessCompanionAppNotInstalled;
+            return this;
+        }
+
+        /**
+         * Set SubsequentPairingDescription.
+         *
+         * @param subsequentPairingDescription Description that reminds user there is a paired
+         *                                     device nearby.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSubsequentPairingDescription(
+                @Nullable String subsequentPairingDescription) {
+            mBuilderParcel.subsequentPairingDescription = subsequentPairingDescription;
+            return this;
+        }
+
+        /**
+         * Set RetroactivePairingDescription.
+         *
+         * @param retroactivePairingDescription Description that reminds users opt in their device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setRetroactivePairingDescription(
+                @Nullable String retroactivePairingDescription) {
+            mBuilderParcel.retroactivePairingDescription = retroactivePairingDescription;
+            return this;
+        }
+
+        /**
+         * Set WaitLaunchCompanionAppDescription.
+         *
+         * @param waitLaunchCompanionAppDescription Description that indicates companion app is
+         *                                          about to launch.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setWaitLaunchCompanionAppDescription(
+                @Nullable String waitLaunchCompanionAppDescription) {
+            mBuilderParcel.waitLaunchCompanionAppDescription =
+                    waitLaunchCompanionAppDescription;
+            return this;
+        }
+
+        /**
+         * Set FailConnectGoToSettingsDescription.
+         *
+         * @param failConnectGoToSettingsDescription Description that indicates go to bluetooth
+         *                                           settings when connection fail.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFailConnectGoToSettingsDescription(
+                @Nullable String failConnectGoToSettingsDescription) {
+            mBuilderParcel.failConnectGoToSettingsDescription =
+                    failConnectGoToSettingsDescription;
+            return this;
+        }
+
+        /**
+         * Set ConfirmPinTitle.
+         *
+         * @param confirmPinTitle Title of the UI to ask the user to confirm the pin code.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setConfirmPinTitle(@Nullable String confirmPinTitle) {
+            mBuilderParcel.confirmPinTitle = confirmPinTitle;
+            return this;
+        }
+
+        /**
+         * Set ConfirmPinDescription.
+         *
+         * @param confirmPinDescription Description of the UI to ask the user to confirm the pin
+         *                              code.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setConfirmPinDescription(@Nullable String confirmPinDescription) {
+            mBuilderParcel.confirmPinDescription = confirmPinDescription;
+            return this;
+        }
+
+        /**
+         * Set SyncContactsTitle.
+         *
+         * @param syncContactsTitle Title of the UI to ask the user to confirm to sync contacts.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSyncContactsTitle(@Nullable String syncContactsTitle) {
+            mBuilderParcel.syncContactsTitle = syncContactsTitle;
+            return this;
+        }
+
+        /**
+         * Set SyncContactsDescription.
+         *
+         * @param syncContactsDescription Description of the UI to ask the user to confirm to sync
+         *                                contacts.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSyncContactsDescription(@Nullable String syncContactsDescription) {
+            mBuilderParcel.syncContactsDescription = syncContactsDescription;
+            return this;
+        }
+
+        /**
+         * Set SyncSmsTitle.
+         *
+         * @param syncSmsTitle Title of the UI to ask the user to confirm to sync SMS.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSyncSmsTitle(@Nullable String syncSmsTitle) {
+            mBuilderParcel.syncSmsTitle = syncSmsTitle;
+            return this;
+        }
+
+        /**
+         * Set SyncSmsDescription.
+         *
+         * @param syncSmsDescription Description of the UI to ask the user to confirm to sync SMS.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setSyncSmsDescription(@Nullable String syncSmsDescription) {
+            mBuilderParcel.syncSmsDescription = syncSmsDescription;
+            return this;
+        }
+
+        /**
+         * Set AssistantSetupHalfSheet.
+         *
+         * @param assistantSetupHalfSheet Description in half sheet to ask user setup google
+         * assistant.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAssistantSetupHalfSheet(@Nullable String assistantSetupHalfSheet) {
+            mBuilderParcel.assistantSetupHalfSheet = assistantSetupHalfSheet;
+            return this;
+        }
+
+        /**
+         * Set AssistantSetupNotification.
+         *
+         * @param assistantSetupNotification Description in notification to ask user setup google
+         *                                   assistant.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAssistantSetupNotification(
+                @Nullable String assistantSetupNotification) {
+            mBuilderParcel.assistantSetupNotification = assistantSetupNotification;
+            return this;
+        }
+
+        /**
+         * Set FastPairTvConnectDeviceNoAccountDescription.
+         *
+         * @param fastPairTvConnectDeviceNoAccountDescription Description of the connect device
+         *                                                    action on TV, when user is not logged
+         *                                                    in.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFastPairTvConnectDeviceNoAccountDescription(
+                @Nullable String fastPairTvConnectDeviceNoAccountDescription) {
+            mBuilderParcel.fastPairTvConnectDeviceNoAccountDescription =
+                    fastPairTvConnectDeviceNoAccountDescription;
+            return this;
+        }
+
+        /**
+         * Build {@link FastPairDeviceMetadata} with the currently set configuration.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public FastPairDeviceMetadata build() {
+            return new FastPairDeviceMetadata(mBuilderParcel);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java b/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java
new file mode 100644
index 0000000..bc6a6f8
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nearby.aidl.FastPairDiscoveryItemParcel;
+
+/**
+ * Class for FastPairDiscoveryItem and its builder.
+ *
+ * @hide
+ */
+@SystemApi
+public class FastPairDiscoveryItem {
+
+    FastPairDiscoveryItemParcel mMetadataParcel;
+
+    FastPairDiscoveryItem(
+            FastPairDiscoveryItemParcel metadataParcel) {
+        this.mMetadataParcel = metadataParcel;
+    }
+
+    /**
+     * Get Id.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getId() {
+        return mMetadataParcel.id;
+    }
+
+    /**
+     * Get Type.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getType() {
+        return mMetadataParcel.type;
+    }
+
+    /**
+     * Get MacAddress.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getMacAddress() {
+        return mMetadataParcel.macAddress;
+    }
+
+    /**
+     * Get ActionUrl.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getActionUrl() {
+        return mMetadataParcel.actionUrl;
+    }
+
+    /**
+     * Get DeviceName.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getDeviceName() {
+        return mMetadataParcel.deviceName;
+    }
+
+    /**
+     * Get Title.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getTitle() {
+        return mMetadataParcel.title;
+    }
+
+    /**
+     * Get Description.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getDescription() {
+        return mMetadataParcel.description;
+    }
+
+    /**
+     * Get DisplayUrl.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getDisplayUrl() {
+        return mMetadataParcel.displayUrl;
+    }
+
+    /**
+     * Get LastObservationTimestampMillis.
+     *
+     * @hide
+     */
+    @SystemApi
+    public long getLastObservationTimestampMillis() {
+        return mMetadataParcel.lastObservationTimestampMillis;
+    }
+
+    /**
+     * Get FirstObservationTimestampMillis.
+     *
+     * @hide
+     */
+    @SystemApi
+    public long getFirstObservationTimestampMillis() {
+        return mMetadataParcel.firstObservationTimestampMillis;
+    }
+
+    /**
+     * Get State.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getState() {
+        return mMetadataParcel.state;
+    }
+
+    /**
+     * Get ActionUrlType.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getActionUrlType() {
+        return mMetadataParcel.actionUrlType;
+    }
+
+    /**
+     * Get Rssi.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getRssi() {
+        return mMetadataParcel.rssi;
+    }
+
+    /**
+     * Get PendingAppInstallTimestampMillis.
+     *
+     * @hide
+     */
+    @SystemApi
+    public long getPendingAppInstallTimestampMillis() {
+        return mMetadataParcel.pendingAppInstallTimestampMillis;
+    }
+
+    /**
+     * Get TxPower.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getTxPower() {
+        return mMetadataParcel.txPower;
+    }
+
+    /**
+     * Get AppName.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getAppName() {
+        return mMetadataParcel.appName;
+    }
+
+    /**
+     * Get GroupId.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getGroupId() {
+        return mMetadataParcel.groupId;
+    }
+
+    /**
+     * Get AttachmentType.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getAttachmentType() {
+        return mMetadataParcel.attachmentType;
+    }
+
+    /**
+     * Get PackageName.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getPackageName() {
+        return mMetadataParcel.packageName;
+    }
+
+    /**
+     * Get FeatureGraphicUrl.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getFeatureGraphicUrl() {
+        return mMetadataParcel.featureGraphicUrl;
+    }
+
+    /**
+     * Get TriggerId.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getTriggerId() {
+        return mMetadataParcel.triggerId;
+    }
+
+    /**
+     * Get IconPng, which is submitted at device registration time to display on notification. It is
+     * a 32-bit PNG with dimensions of 512px by 512px.
+     *
+     * @return IconPng in 32-bit PNG with dimensions of 512px by 512px.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getIconPng() {
+        return mMetadataParcel.iconPng;
+    }
+
+    /**
+     * Get IconFifeUrl.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getIconFfeUrl() {
+        return mMetadataParcel.iconFifeUrl;
+    }
+
+    /**
+     * Get DebugMessage.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getDebugMessage() {
+        return mMetadataParcel.debugMessage;
+    }
+
+    /**
+     * Get DebugCategory.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getDebugCategory() {
+        return mMetadataParcel.debugCategory;
+    }
+
+    /**
+     * Get LostMillis.
+     */
+    public long getLostMillis() {
+        return mMetadataParcel.lostMillis;
+    }
+
+    /**
+     * Get LastUserExperience.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getLastUserExperience() {
+        return mMetadataParcel.lastUserExperience;
+    }
+
+    /**
+     * Get BleRecordBytes. Raw bytes of {@link android.bluetooth.le.ScanRecord}.
+     * It is the most recent BLE advertisement related to this item.
+     *
+     * @return the most recent BLE advertisement in raw bytes of
+     *         {@link android.bluetooth.le.ScanRecord}.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getBleRecordBytes() {
+        return mMetadataParcel.bleRecordBytes;
+    }
+
+    /**
+     * Get EntityId.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getEntityId() {
+        return mMetadataParcel.entityId;
+    }
+
+    /**
+     * Get authenticationPublicKeySecp256r1, which is same as AntiSpoof public key, see
+     * <a href="https://developers.google.com/nearby/fast-pair/spec#data_format">Data Format</a>.
+     *
+     * @return 64-byte authenticationPublicKeySecp256r1.
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public byte[] getAuthenticationPublicKeySecp256r1() {
+        return mMetadataParcel.authenticationPublicKeySecp256r1;
+    }
+
+    /**
+     * Builder used to create FastPairDiscoveryItem.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final FastPairDiscoveryItemParcel mBuilderParcel;
+
+        /**
+         * Default constructor of Builder.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {
+            mBuilderParcel = new FastPairDiscoveryItemParcel();
+        }
+
+        /**
+         * Set Id.
+         *
+         * @param id Unique id.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setId(@Nullable String id) {
+            mBuilderParcel.id = id;
+            return this;
+        }
+
+        /**
+         * Set Nearby Type.
+         *
+         * @param type Nearby type.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setType(int type) {
+            mBuilderParcel.type = type;
+            return this;
+        }
+
+        /**
+         * Set MacAddress.
+         *
+         * @param macAddress Fast Pair device rotating mac address.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setMacAddress(@Nullable String macAddress) {
+            mBuilderParcel.macAddress = macAddress;
+            return this;
+        }
+
+        /**
+         * Set ActionUrl.
+         *
+         * @param actionUrl Action Url of Fast Pair device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setActionUrl(@Nullable String actionUrl) {
+            mBuilderParcel.actionUrl = actionUrl;
+            return this;
+        }
+
+        /**
+         * Set DeviceName.
+         * @param deviceName Fast Pair device name.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDeviceName(@Nullable String deviceName) {
+            mBuilderParcel.deviceName = deviceName;
+            return this;
+        }
+
+        /**
+         * Set Title.
+         *
+         * @param title Title of Fast Pair device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTitle(@Nullable String title) {
+            mBuilderParcel.title = title;
+            return this;
+        }
+
+        /**
+         * Set Description.
+         *
+         * @param description Description of Fast Pair device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDescription(@Nullable String description) {
+            mBuilderParcel.description = description;
+            return this;
+        }
+
+        /**
+         * Set DisplayUrl.
+         *
+         * @param displayUrl Display Url of Fast Pair device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDisplayUrl(@Nullable String displayUrl) {
+            mBuilderParcel.displayUrl = displayUrl;
+            return this;
+        }
+
+        /**
+         * Set LastObservationTimestampMillis.
+         *
+         * @param lastObservationTimestampMillis Last observed timestamp of Fast Pair device, keyed
+         *                                       by a rotating id.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setLastObservationTimestampMillis(
+                long lastObservationTimestampMillis) {
+            mBuilderParcel.lastObservationTimestampMillis = lastObservationTimestampMillis;
+            return this;
+        }
+
+        /**
+         * Set FirstObservationTimestampMillis.
+         *
+         * @param firstObservationTimestampMillis First observed timestamp of Fast Pair device,
+         *                                        keyed by a rotating id.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFirstObservationTimestampMillis(
+                long firstObservationTimestampMillis) {
+            mBuilderParcel.firstObservationTimestampMillis = firstObservationTimestampMillis;
+            return this;
+        }
+
+        /**
+         * Set State.
+         *
+         * @param state Item's current state. e.g. if the item is blocked.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setState(int state) {
+            mBuilderParcel.state = state;
+            return this;
+        }
+
+        /**
+         * Set ActionUrlType.
+         *
+         * @param actionUrlType The resolved url type for the action_url.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setActionUrlType(int actionUrlType) {
+            mBuilderParcel.actionUrlType = actionUrlType;
+            return this;
+        }
+
+        /**
+         * Set Rssi.
+         *
+         * @param rssi Beacon's RSSI value.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setRssi(int rssi) {
+            mBuilderParcel.rssi = rssi;
+            return this;
+        }
+
+        /**
+         * Set PendingAppInstallTimestampMillis.
+         *
+         * @param pendingAppInstallTimestampMillis The timestamp when the user is redirected to App
+         *                                         Store after clicking on the item.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setPendingAppInstallTimestampMillis(long pendingAppInstallTimestampMillis) {
+            mBuilderParcel.pendingAppInstallTimestampMillis = pendingAppInstallTimestampMillis;
+            return this;
+        }
+
+        /**
+         * Set TxPower.
+         *
+         * @param txPower Beacon's tx power.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTxPower(int txPower) {
+            mBuilderParcel.txPower = txPower;
+            return this;
+        }
+
+        /**
+         * Set AppName.
+         *
+         * @param appName Human readable name of the app designated to open the uri.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAppName(@Nullable String appName) {
+            mBuilderParcel.appName = appName;
+            return this;
+        }
+
+        /**
+         * Set GroupId.
+         *
+         * @param groupId ID used for associating several DiscoveryItems. These items may be
+         *                visually displayed together.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setGroupId(@Nullable String groupId) {
+            mBuilderParcel.groupId = groupId;
+            return this;
+        }
+
+        /**
+         * Set AttachmentType.
+         *
+         * @param attachmentType Whether the attachment is created in debug namespace.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAttachmentType(int attachmentType) {
+            mBuilderParcel.attachmentType = attachmentType;
+            return this;
+        }
+
+        /**
+         * Set PackageName.
+         *
+         * @param packageName Package name of the App that owns this item.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setPackageName(@Nullable String packageName) {
+            mBuilderParcel.packageName = packageName;
+            return this;
+        }
+
+        /**
+         * Set FeatureGraphicUrl.
+         *
+         * @param featureGraphicUrl The "feature" graphic image url used for large sized list view
+         *                          entries.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setFeatureGraphicUrl(@Nullable String featureGraphicUrl) {
+            mBuilderParcel.featureGraphicUrl = featureGraphicUrl;
+            return this;
+        }
+
+        /**
+         * Set TriggerId.
+         *
+         * @param triggerId TriggerId identifies the trigger/beacon that is attached with a message.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setTriggerId(@Nullable String triggerId) {
+            mBuilderParcel.triggerId = triggerId;
+            return this;
+        }
+
+        /**
+         * Set IconPng.
+         *
+         * @param iconPng Bytes of item icon in PNG format displayed in Discovery item list.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setIconPng(@Nullable byte[] iconPng) {
+            mBuilderParcel.iconPng = iconPng;
+            return this;
+        }
+
+        /**
+         * Set IconFifeUrl.
+         *
+         * @param iconFifeUrl A FIFE URL of the item icon displayed in Discovery item list.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setIconFfeUrl(@Nullable String iconFifeUrl) {
+            mBuilderParcel.iconFifeUrl = iconFifeUrl;
+            return this;
+        }
+
+        /**
+         * Set DebugMessage.
+         *
+         * @param debugMessage Message written to bugreport for 3P developers.(No sensitive info)
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDebugMessage(@Nullable String debugMessage) {
+            mBuilderParcel.debugMessage = debugMessage;
+            return this;
+        }
+
+        /**
+         * Set DebugCategory.
+         *
+         * @param debugCategory Weather the item is filtered out on server.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setDebugCategory(int debugCategory) {
+            mBuilderParcel.debugCategory = debugCategory;
+            return this;
+        }
+
+        /**
+         * Set LostMillis.
+         *
+         * @param lostMillis Client timestamp when the trigger (e.g. beacon) was last lost
+         *                   (e.g. when Messages told us the beacon's no longer nearby).
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setLostMillis(long lostMillis) {
+            mBuilderParcel.lostMillis = lostMillis;
+            return this;
+        }
+
+        /**
+         * Set LastUserExperience.
+         *
+         * @param lastUserExperience The kind of experience the user last had with this (e.g. if
+         *                           they dismissed the notification, that's bad; but if they tapped
+         *                           it, that's good).
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setLastUserExperience(int lastUserExperience) {
+            mBuilderParcel.lastUserExperience = lastUserExperience;
+            return this;
+        }
+
+        /**
+         * Set BleRecordBytes.
+         *
+         * @param bleRecordBytes The most recent BLE advertisement related to this item. Raw bytes
+         *                       of {@link android.bluetooth.le.ScanRecord}.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setBleRecordBytes(@Nullable byte[] bleRecordBytes) {
+            mBuilderParcel.bleRecordBytes = bleRecordBytes;
+            return this;
+        }
+
+        /**
+         * Set EntityId.
+         *
+         * @param entityId An ID generated on the server to uniquely identify content.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setEntityId(@Nullable String entityId) {
+            mBuilderParcel.entityId = entityId;
+            return this;
+        }
+
+        /**
+         * Set authenticationPublicKeySecp256r1, which is same as AntiSpoof public key, see
+         * <a href="https://developers.google.com/nearby/fast-pair/spec#data_format">Data Format</a>
+         *
+         * @param authenticationPublicKeySecp256r1 64-byte Fast Pair device public key.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAuthenticationPublicKeySecp256r1(
+                @Nullable byte[] authenticationPublicKeySecp256r1) {
+            mBuilderParcel.authenticationPublicKeySecp256r1 = authenticationPublicKeySecp256r1;
+            return this;
+        }
+
+        /**
+         * Build {@link FastPairDiscoveryItem} with the currently set configuration.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public FastPairDiscoveryItem build() {
+            return new FastPairDiscoveryItem(mBuilderParcel);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairEligibleAccount.java b/nearby/framework/java/android/nearby/FastPairEligibleAccount.java
new file mode 100644
index 0000000..e6c3047
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairEligibleAccount.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.accounts.Account;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nearby.aidl.FastPairEligibleAccountParcel;
+
+/**
+ * Class for FastPairEligibleAccount and its builder.
+ *
+ * @hide
+ */
+@SystemApi
+public class FastPairEligibleAccount {
+
+    FastPairEligibleAccountParcel mAccountParcel;
+
+    FastPairEligibleAccount(FastPairEligibleAccountParcel accountParcel) {
+        this.mAccountParcel = accountParcel;
+    }
+
+    /**
+     * Get Account.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public Account getAccount() {
+        return this.mAccountParcel.account;
+    }
+
+    /**
+     * Get OptIn Status.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isOptIn() {
+        return this.mAccountParcel.optIn;
+    }
+
+    /**
+     * Builder used to create FastPairEligibleAccount.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final FastPairEligibleAccountParcel mBuilderParcel;
+
+        /**
+         * Default constructor of Builder.
+         *
+         * @hide
+         */
+        @SystemApi
+        public Builder() {
+            mBuilderParcel = new FastPairEligibleAccountParcel();
+            mBuilderParcel.account = null;
+            mBuilderParcel.optIn = false;
+        }
+
+        /**
+         * Set Account.
+         *
+         * @param account Fast Pair eligible account.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAccount(@Nullable Account account) {
+            mBuilderParcel.account = account;
+            return this;
+        }
+
+        /**
+         * Set whether the account is opt into Fast Pair.
+         *
+         * @param optIn Whether the Fast Pair eligible account opts into Fast Pair.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public Builder setOptIn(boolean optIn) {
+            mBuilderParcel.optIn = optIn;
+            return this;
+        }
+
+        /**
+         * Build {@link FastPairEligibleAccount} with the currently set configuration.
+         *
+         * @hide
+         */
+        @SystemApi
+        @NonNull
+        public FastPairEligibleAccount build() {
+            return new FastPairEligibleAccount(mBuilderParcel);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/FastPairStatusCallback.java b/nearby/framework/java/android/nearby/FastPairStatusCallback.java
new file mode 100644
index 0000000..1567828
--- /dev/null
+++ b/nearby/framework/java/android/nearby/FastPairStatusCallback.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+
+/**
+ * Reports the pair status for an ongoing pair with a {@link FastPairDevice}.
+ * @hide
+ */
+public interface FastPairStatusCallback {
+
+    /** Reports a pair status related metadata associated with a {@link FastPairDevice} */
+    void onPairUpdate(@NonNull FastPairDevice fastPairDevice,
+            PairStatusMetadata pairStatusMetadata);
+}
diff --git a/nearby/framework/java/android/nearby/IBroadcastListener.aidl b/nearby/framework/java/android/nearby/IBroadcastListener.aidl
new file mode 100644
index 0000000..98c7e17
--- /dev/null
+++ b/nearby/framework/java/android/nearby/IBroadcastListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 android.nearby;
+
+/**
+ * Callback when brodacast status changes.
+ *
+ * {@hide}
+ */
+oneway interface IBroadcastListener {
+    /** Called when the broadcast status changes. */
+    void onStatusChanged(int status);
+}
diff --git a/nearby/framework/java/android/nearby/IFastPairHalfSheetCallback.aidl b/nearby/framework/java/android/nearby/IFastPairHalfSheetCallback.aidl
new file mode 100644
index 0000000..2e6fc87
--- /dev/null
+++ b/nearby/framework/java/android/nearby/IFastPairHalfSheetCallback.aidl
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 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 android.nearby;
+
+import android.content.Intent;
+/**
+  * Provides callback interface for halfsheet to send FastPair call back.
+  *
+  * {@hide}
+  */
+interface IFastPairHalfSheetCallback {
+     void onHalfSheetConnectionConfirm(in Intent intent);
+ }
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/INearbyManager.aidl b/nearby/framework/java/android/nearby/INearbyManager.aidl
new file mode 100644
index 0000000..62e109e
--- /dev/null
+++ b/nearby/framework/java/android/nearby/INearbyManager.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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 android.nearby;
+
+import android.nearby.IBroadcastListener;
+import android.nearby.IScanListener;
+import android.nearby.BroadcastRequestParcelable;
+import android.nearby.ScanRequest;
+
+/**
+ * Interface for communicating with the nearby services.
+ *
+ * @hide
+ */
+interface INearbyManager {
+
+    int registerScanListener(in ScanRequest scanRequest, in IScanListener listener);
+
+    void unregisterScanListener(in IScanListener listener);
+
+    void startBroadcast(in BroadcastRequestParcelable broadcastRequest,
+            in IBroadcastListener callback);
+
+    void stopBroadcast(in IBroadcastListener callback);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/IScanListener.aidl b/nearby/framework/java/android/nearby/IScanListener.aidl
new file mode 100644
index 0000000..54033aa
--- /dev/null
+++ b/nearby/framework/java/android/nearby/IScanListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.nearby;
+
+import android.nearby.NearbyDeviceParcelable;
+
+/**
+ * Binder callback for ScanCallback.
+ *
+ * {@hide}
+ */
+oneway interface IScanListener {
+        /** Reports a {@link NearbyDevice} being discovered. */
+        void onDiscovered(in NearbyDeviceParcelable nearbyDeviceParcelable);
+
+        /** Reports a {@link NearbyDevice} information(distance, packet, and etc) changed. */
+        void onUpdated(in NearbyDeviceParcelable nearbyDeviceParcelable);
+
+        /** Reports a {@link NearbyDevice} is no longer within range. */
+        void onLost(in NearbyDeviceParcelable nearbyDeviceParcelable);
+}
diff --git a/nearby/framework/java/android/nearby/NearbyDevice.java b/nearby/framework/java/android/nearby/NearbyDevice.java
new file mode 100644
index 0000000..538940c
--- /dev/null
+++ b/nearby/framework/java/android/nearby/NearbyDevice.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class represents a device that can be discovered by multiple mediums.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class NearbyDevice {
+
+    @Nullable
+    private final String mName;
+
+    @Medium
+    private final List<Integer> mMediums;
+
+    private final int mRssi;
+
+    /**
+     * Creates a new NearbyDevice.
+     *
+     * @param name Local device name. Can be {@code null} if there is no name.
+     * @param mediums The {@link Medium}s over which the device is discovered.
+     * @param rssi The received signal strength in dBm.
+     * @hide
+     */
+    public NearbyDevice(@Nullable String name, List<Integer> mediums, int rssi) {
+        for (int medium : mediums) {
+            Preconditions.checkState(isValidMedium(medium),
+                    "Not supported medium: " + medium
+                            + ", scan medium must be one of NearbyDevice#Medium.");
+        }
+        mName = name;
+        mMediums = mediums;
+        mRssi = rssi;
+    }
+
+    static String mediumToString(@Medium int medium) {
+        switch (medium) {
+            case Medium.BLE:
+                return "BLE";
+            case Medium.BLUETOOTH:
+                return "Bluetooth Classic";
+            default:
+                return "Unknown";
+        }
+    }
+
+    /**
+     * True if the medium is defined in {@link Medium}.
+     *
+     * @param medium Integer that may represent a medium type.
+     */
+    public static boolean isValidMedium(@Medium int medium) {
+        return medium == Medium.BLE
+                || medium == Medium.BLUETOOTH;
+    }
+
+    /**
+     * The name of the device, or null if not available.
+     */
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
+    /** The medium over which this device was discovered. */
+    @NonNull
+    @Medium public List<Integer> getMediums() {
+        return mMediums;
+    }
+
+    /**
+     * Returns the received signal strength in dBm.
+     */
+    @IntRange(from = -127, to = 126)
+    public int getRssi() {
+        return mRssi;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("NearbyDevice [");
+        if (mName != null && !mName.isEmpty()) {
+            stringBuilder.append("name=").append(mName).append(", ");
+        }
+        stringBuilder.append("medium={");
+        for (int medium : mMediums) {
+            stringBuilder.append(mediumToString(medium));
+        }
+        stringBuilder.append("} rssi=").append(mRssi);
+        stringBuilder.append("]");
+        return stringBuilder.toString();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof NearbyDevice) {
+            NearbyDevice otherDevice = (NearbyDevice) other;
+            return Objects.equals(mName, otherDevice.mName)
+                    && mMediums == otherDevice.mMediums
+                    && mRssi == otherDevice.mRssi;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mName, mMediums, mRssi);
+    }
+
+    /**
+     * The medium where a NearbyDevice was discovered on.
+     *
+     * @hide
+     */
+    @IntDef({Medium.BLE, Medium.BLUETOOTH})
+    public @interface Medium {
+        int BLE = 1;
+        int BLUETOOTH = 2;
+    }
+}
+
diff --git a/nearby/framework/java/android/nearby/NearbyDeviceParcelable.aidl b/nearby/framework/java/android/nearby/NearbyDeviceParcelable.aidl
new file mode 100644
index 0000000..1a88181
--- /dev/null
+++ b/nearby/framework/java/android/nearby/NearbyDeviceParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012, 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 android.nearby;
+
+parcelable NearbyDeviceParcelable;
+
diff --git a/nearby/framework/java/android/nearby/NearbyDeviceParcelable.java b/nearby/framework/java/android/nearby/NearbyDeviceParcelable.java
new file mode 100644
index 0000000..f137de4
--- /dev/null
+++ b/nearby/framework/java/android/nearby/NearbyDeviceParcelable.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.le.ScanRecord;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A data class representing scan result from Nearby Service. Scan result can come from multiple
+ * mediums like BLE, Wi-Fi Aware, and etc.
+ * A scan result  consists of
+ * An encapsulation of various parameters for requesting nearby scans.
+ *
+ * <p>All scan results generated through {@link NearbyManager} are guaranteed to have a valid
+ * medium, identifier, timestamp (both UTC time and elapsed real-time since boot), and accuracy.
+ * All other parameters are optional.
+ *
+ * @hide
+ */
+public final class NearbyDeviceParcelable implements Parcelable {
+
+    /**
+     * Used to read a NearbyDeviceParcelable from a Parcel.
+     */
+    @NonNull
+    public static final Creator<NearbyDeviceParcelable> CREATOR =
+            new Creator<NearbyDeviceParcelable>() {
+                @Override
+                public NearbyDeviceParcelable createFromParcel(Parcel in) {
+                    Builder builder = new Builder();
+                    if (in.readInt() == 1) {
+                        builder.setName(in.readString());
+                    }
+                    builder.setMedium(in.readInt());
+                    builder.setRssi(in.readInt());
+                    if (in.readInt() == 1) {
+                        builder.setFastPairModelId(in.readString());
+                    }
+                    if (in.readInt() == 1) {
+                        builder.setBluetoothAddress(in.readString());
+                    }
+                    if (in.readInt() == 1) {
+                        int dataLength = in.readInt();
+                        byte[] data = new byte[dataLength];
+                        in.readByteArray(data);
+                        builder.setData(data);
+                    }
+                    return builder.build();
+                }
+
+                @Override
+                public NearbyDeviceParcelable[] newArray(int size) {
+                    return new NearbyDeviceParcelable[size];
+                }
+            };
+
+    @ScanRequest.ScanType int mScanType;
+    @Nullable
+    private final String mName;
+    @NearbyDevice.Medium
+    private final int mMedium;
+    private final int mRssi;
+
+    @Nullable
+    private final String mBluetoothAddress;
+    @Nullable
+    private final String mFastPairModelId;
+    @Nullable
+    private final byte[] mData;
+
+    private NearbyDeviceParcelable(@ScanRequest.ScanType int scanType, @Nullable String name,
+            int medium, int rssi, @Nullable String fastPairModelId,
+            @Nullable String bluetoothAddress, @Nullable byte[] data) {
+        mScanType = scanType;
+        mName = name;
+        mMedium = medium;
+        mRssi = rssi;
+        mFastPairModelId = fastPairModelId;
+        mBluetoothAddress = bluetoothAddress;
+        mData = data;
+    }
+
+    /**
+     * No special parcel contents.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Flatten this NearbyDeviceParcelable in to a Parcel.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     */
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mName == null ? 0 : 1);
+        if (mName != null) {
+            dest.writeString(mName);
+        }
+        dest.writeInt(mMedium);
+        dest.writeInt(mRssi);
+        dest.writeInt(mFastPairModelId == null ? 0 : 1);
+        if (mFastPairModelId != null) {
+            dest.writeString(mFastPairModelId);
+        }
+        dest.writeInt(mBluetoothAddress == null ? 0 : 1);
+        if (mBluetoothAddress != null) {
+            dest.writeString(mBluetoothAddress);
+        }
+        dest.writeInt(mData == null ? 0 : 1);
+        if (mData != null) {
+            dest.writeInt(mData.length);
+            dest.writeByteArray(mData);
+        }
+    }
+
+    /**
+     * Returns a string representation of this ScanRequest.
+     */
+    @Override
+    public String toString() {
+        return "NearbyDeviceParcelable["
+                + "name=" + mName
+                + ", medium=" + NearbyDevice.mediumToString(mMedium)
+                + ", rssi=" + mRssi
+                + ", bluetoothAddress=" + mBluetoothAddress
+                + ", fastPairModelId=" + mFastPairModelId
+                + ", data=" + Arrays.toString(mData)
+                + "]";
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof NearbyDeviceParcelable) {
+            NearbyDeviceParcelable otherNearbyDeviceParcelable = (NearbyDeviceParcelable) other;
+            return  Objects.equals(mName, otherNearbyDeviceParcelable.mName)
+                    && (mMedium == otherNearbyDeviceParcelable.mMedium)
+                    && (mRssi == otherNearbyDeviceParcelable.mRssi)
+                    && (Objects.equals(
+                            mBluetoothAddress, otherNearbyDeviceParcelable.mBluetoothAddress))
+                    && (Objects.equals(
+                            mFastPairModelId, otherNearbyDeviceParcelable.mFastPairModelId))
+                    && (Arrays.equals(mData, otherNearbyDeviceParcelable.mData));
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mName, mMedium, mRssi, mBluetoothAddress, mFastPairModelId, Arrays.hashCode(mData));
+    }
+
+    /**
+     * Returns the type of the scan.
+     *
+     * @hide
+     */
+    @ScanRequest.ScanType
+    public int getScanType() {
+        return mScanType;
+    }
+
+    /**
+     * Gets the name of the NearbyDeviceParcelable. Returns {@code null} If there is no name.
+     */
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the {@link android.nearby.NearbyDevice.Medium} of the NearbyDeviceParcelable over which
+     * it is discovered.
+     */
+    @NearbyDevice.Medium
+    public int getMedium() {
+        return mMedium;
+    }
+
+    /**
+     * Gets the received signal strength in dBm.
+     */
+    @IntRange(from = -127, to = 126)
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * Gets the Fast Pair identifier. Returns {@code null} if there is no Model ID or this is not a
+     * Fast Pair device.
+     */
+    @Nullable
+    public String getFastPairModelId() {
+        return mFastPairModelId;
+    }
+
+    /**
+     * Gets the Bluetooth device hardware address. Returns {@code null} if the device is not
+     * discovered by Bluetooth.
+     */
+    @Nullable
+    public String getBluetoothAddress() {
+        return mBluetoothAddress;
+    }
+
+    /**
+     * Gets the raw data from the scanning. Returns {@code null} if there is no extra data.
+     */
+    @Nullable
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Builder class for {@link NearbyDeviceParcelable}.
+     */
+    public static final class Builder {
+        @Nullable
+        private String mName;
+        @NearbyDevice.Medium
+        private int mMedium;
+        private int mRssi;
+        @ScanRequest.ScanType int mScanType;
+        @Nullable
+        private String mFastPairModelId;
+        @Nullable
+        private String mBluetoothAddress;
+        @Nullable
+        private byte[] mData;
+
+        /**
+         * Sets the scan type of the NearbyDeviceParcelable.
+         *
+         * @hide
+         */
+        public Builder setScanType(@ScanRequest.ScanType int scanType) {
+            mScanType = scanType;
+            return this;
+        }
+
+        /**
+         * Sets the name of the scanned device.
+         *
+         * @param name The local name of the scanned device.
+         */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Sets the medium over which the device is discovered.
+         *
+         * @param medium The {@link NearbyDevice.Medium} over which the device is discovered.
+         */
+        @NonNull
+        public Builder setMedium(@NearbyDevice.Medium int medium) {
+            mMedium = medium;
+            return this;
+        }
+
+        /**
+         * Sets the RSSI between scanned device and the discovered device.
+         *
+         * @param rssi The received signal strength in dBm.
+         */
+        @NonNull
+        public Builder setRssi(int rssi) {
+            mRssi = rssi;
+            return this;
+        }
+
+        /**
+         * Sets the Fast Pair model Id.
+         *
+         * @param fastPairModelId Fast Pair device identifier.
+         */
+        @NonNull
+        public Builder setFastPairModelId(@Nullable String fastPairModelId) {
+            mFastPairModelId = fastPairModelId;
+            return this;
+        }
+
+        /**
+         * Sets the bluetooth address.
+         *
+         * @param bluetoothAddress The hardware address of the bluetooth device.
+         */
+        @NonNull
+        public Builder setBluetoothAddress(@Nullable String bluetoothAddress) {
+            mBluetoothAddress = bluetoothAddress;
+            return this;
+        }
+
+        /**
+         * Sets the scanned raw data.
+         *
+         * @param data Data the scan.
+         * For example, {@link ScanRecord#getServiceData()} if scanned by Bluetooth.
+         */
+        @NonNull
+        public Builder setData(@Nullable byte[] data) {
+            mData = data;
+            return this;
+        }
+
+        /**
+         * Builds a ScanResult.
+         */
+        @NonNull
+        public NearbyDeviceParcelable build() {
+            return new NearbyDeviceParcelable(mScanType, mName, mMedium, mRssi, mFastPairModelId,
+                    mBluetoothAddress, mData);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/NearbyFrameworkInitializer.java b/nearby/framework/java/android/nearby/NearbyFrameworkInitializer.java
new file mode 100644
index 0000000..3780fbb
--- /dev/null
+++ b/nearby/framework/java/android/nearby/NearbyFrameworkInitializer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * Class for performing registration for all Nearby services.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class NearbyFrameworkInitializer {
+
+    private NearbyFrameworkInitializer() {}
+
+    /**
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers all
+     * Nearby services to {@link Context}, so that {@link Context#getSystemService} can return them.
+     *
+     * @throws IllegalStateException if this is called from anywhere besides
+     * {@link SystemServiceRegistry}
+     */
+    public static void registerServiceWrappers() {
+        SystemServiceRegistry.registerContextAwareService(
+                Context.NEARBY_SERVICE,
+                NearbyManager.class,
+                (context, serviceBinder) -> {
+                    INearbyManager service = INearbyManager.Stub.asInterface(serviceBinder);
+                    return new NearbyManager(service);
+                }
+        );
+    }
+}
diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java
new file mode 100644
index 0000000..2654046
--- /dev/null
+++ b/nearby/framework/java/android/nearby/NearbyManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2021 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 android.nearby;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.provider.Settings;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.WeakHashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides a way to perform Nearby related operations such as scanning, broadcasting
+ * and connecting to nearby devices.
+ *
+ * <p> To get a {@link NearbyManager} instance, call the
+ * <code>Context.getSystemService(NearbyManager.class)</code>.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.NEARBY_SERVICE)
+public class NearbyManager {
+
+    /**
+     * Represents the scanning state.
+     *
+     * @hide
+     */
+    @IntDef({
+            ScanStatus.UNKNOWN,
+            ScanStatus.SUCCESS,
+            ScanStatus.ERROR,
+    })
+    public @interface ScanStatus {
+        // Default, invalid state.
+        int UNKNOWN = 0;
+        // The successful state.
+        int SUCCESS = 1;
+        // Failed state.
+        int ERROR = 2;
+    }
+
+    /**
+     * Whether allows Fast Pair to scan.
+     *
+     * (0 = disabled, 1 = enabled)
+     *
+     * @hide
+     */
+    public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
+
+    @GuardedBy("sScanListeners")
+    private static final WeakHashMap<ScanCallback, WeakReference<ScanListenerTransport>>
+            sScanListeners = new WeakHashMap<>();
+    @GuardedBy("sBroadcastListeners")
+    private static final WeakHashMap<BroadcastCallback, WeakReference<BroadcastListenerTransport>>
+            sBroadcastListeners = new WeakHashMap<>();
+
+    private final INearbyManager mService;
+
+    /**
+     * Creates a new NearbyManager.
+     *
+     * @param service the service object
+     */
+    NearbyManager(@NonNull INearbyManager service) {
+        mService = service;
+    }
+
+    private static NearbyDevice toClientNearbyDevice(
+            NearbyDeviceParcelable nearbyDeviceParcelable,
+            @ScanRequest.ScanType int scanType) {
+        if (scanType == ScanRequest.SCAN_TYPE_FAST_PAIR) {
+            return new FastPairDevice.Builder()
+                    .setName(nearbyDeviceParcelable.getName())
+                    .addMedium(nearbyDeviceParcelable.getMedium())
+                    .setRssi(nearbyDeviceParcelable.getRssi())
+                    .setModelId(nearbyDeviceParcelable.getFastPairModelId())
+                    .setBluetoothAddress(nearbyDeviceParcelable.getBluetoothAddress())
+                    .setData(nearbyDeviceParcelable.getData()).build();
+        }
+        return null;
+    }
+
+    /**
+     * Start scan for nearby devices with given parameters. Devices matching {@link ScanRequest}
+     * will be delivered through the given callback.
+     *
+     * @param scanRequest various parameters clients send when requesting scanning
+     * @param executor executor where the listener method is called
+     * @param scanCallback the callback to notify clients when there is a scan result
+     *
+     * @return whether scanning was successfully started
+     */
+    @RequiresPermission(allOf = {android.Manifest.permission.BLUETOOTH_SCAN,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+    @ScanStatus
+    public int startScan(@NonNull ScanRequest scanRequest,
+            @CallbackExecutor @NonNull Executor executor,
+            @NonNull ScanCallback scanCallback) {
+        Objects.requireNonNull(scanRequest, "scanRequest must not be null");
+        Objects.requireNonNull(scanCallback, "scanCallback must not be null");
+        Objects.requireNonNull(executor, "executor must not be null");
+
+        try {
+            synchronized (sScanListeners) {
+                WeakReference<ScanListenerTransport> reference = sScanListeners.get(scanCallback);
+                ScanListenerTransport transport = reference != null ? reference.get() : null;
+                if (transport == null) {
+                    transport = new ScanListenerTransport(scanRequest.getScanType(), scanCallback,
+                            executor);
+                } else {
+                    Preconditions.checkState(transport.isRegistered());
+                    transport.setExecutor(executor);
+                }
+                @ScanStatus int status = mService.registerScanListener(scanRequest, transport);
+                if (status != ScanStatus.SUCCESS) {
+                    return status;
+                }
+                sScanListeners.put(scanCallback, new WeakReference<>(transport));
+                return ScanStatus.SUCCESS;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stops the nearby device scan for the specified callback. The given callback
+     * is guaranteed not to receive any invocations that happen after this method
+     * is invoked.
+     *
+     * Suppressed lint: Registration methods should have overload that accepts delivery Executor.
+     * Already have executor in startScan() method.
+     *
+     * @param scanCallback the callback that was used to start the scan
+     */
+    @SuppressLint("ExecutorRegistration")
+    @RequiresPermission(allOf = {android.Manifest.permission.BLUETOOTH_SCAN,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+    public void stopScan(@NonNull ScanCallback scanCallback) {
+        Preconditions.checkArgument(scanCallback != null,
+                "invalid null scanCallback");
+        try {
+            synchronized (sScanListeners) {
+                WeakReference<ScanListenerTransport> reference = sScanListeners.remove(
+                        scanCallback);
+                ScanListenerTransport transport = reference != null ? reference.get() : null;
+                if (transport != null) {
+                    transport.unregister();
+                    mService.unregisterScanListener(transport);
+                }
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Start broadcasting the request using nearby specification.
+     *
+     * @param broadcastRequest request for the nearby broadcast
+     * @param executor executor for running the callback
+     * @param callback callback for notifying the client
+     */
+    @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_ADVERTISE,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+    public void startBroadcast(@NonNull BroadcastRequest broadcastRequest,
+            @CallbackExecutor @NonNull Executor executor, @NonNull BroadcastCallback callback) {
+        try {
+            synchronized (sBroadcastListeners) {
+                WeakReference<BroadcastListenerTransport> reference = sBroadcastListeners.get(
+                        callback);
+                BroadcastListenerTransport transport = reference != null ? reference.get() : null;
+                if (transport == null) {
+                    transport = new BroadcastListenerTransport(callback, executor);
+                } else {
+                    Preconditions.checkState(transport.isRegistered());
+                    transport.setExecutor(executor);
+                }
+                mService.startBroadcast(new BroadcastRequestParcelable(broadcastRequest),
+                        transport);
+                sBroadcastListeners.put(callback, new WeakReference<>(transport));
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop the broadcast associated with the given callback.
+     *
+     * @param callback the callback that was used for starting the broadcast
+     */
+    @SuppressLint("ExecutorRegistration")
+    @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_ADVERTISE,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+    public void stopBroadcast(@NonNull BroadcastCallback callback) {
+        try {
+            synchronized (sBroadcastListeners) {
+                WeakReference<BroadcastListenerTransport> reference = sBroadcastListeners.remove(
+                        callback);
+                BroadcastListenerTransport transport = reference != null ? reference.get() : null;
+                if (transport != null) {
+                    transport.unregister();
+                    mService.stopBroadcast(transport);
+                }
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Read from {@link Settings} whether Fast Pair scan is enabled.
+     *
+     * @param context the {@link Context} to query the setting
+     * @param def the default value if no setting value
+     * @return whether the Fast Pair is enabled
+     */
+    public static boolean getFastPairScanEnabled(@NonNull Context context, boolean def) {
+        final int enabled = Settings.Secure.getInt(
+                context.getContentResolver(), FAST_PAIR_SCAN_ENABLED, (def ? 1 : 0));
+        return enabled != 0;
+    }
+
+    /**
+     * Write into {@link Settings} whether Fast Pair scan is enabled
+     *
+     * @param context the {@link Context} to set the setting
+     * @param enable whether the Fast Pair scan should be enabled
+     */
+    public static void setFastPairScanEnabled(@NonNull Context context, boolean enable) {
+        Settings.Secure.putInt(
+                context.getContentResolver(), FAST_PAIR_SCAN_ENABLED, enable ? 1 : 0);
+    }
+
+    private static class ScanListenerTransport extends IScanListener.Stub {
+
+        private @ScanRequest.ScanType int mScanType;
+        private volatile @Nullable ScanCallback mScanCallback;
+        private Executor mExecutor;
+
+        ScanListenerTransport(@ScanRequest.ScanType int scanType, ScanCallback scanCallback,
+                @CallbackExecutor Executor executor) {
+            Preconditions.checkArgument(scanCallback != null,
+                    "invalid null callback");
+            Preconditions.checkState(ScanRequest.isValidScanType(scanType),
+                    "invalid scan type : " + scanType
+                            + ", scan type must be one of ScanRequest#SCAN_TYPE_");
+            mScanType = scanType;
+            mScanCallback = scanCallback;
+            mExecutor = executor;
+        }
+
+        void setExecutor(Executor executor) {
+            Preconditions.checkArgument(
+                    executor != null, "invalid null executor");
+            mExecutor = executor;
+        }
+
+        boolean isRegistered() {
+            return mScanCallback != null;
+        }
+
+        void unregister() {
+            mScanCallback = null;
+        }
+
+        @Override
+        public void onDiscovered(NearbyDeviceParcelable nearbyDeviceParcelable)
+                throws RemoteException {
+            mExecutor.execute(() -> mScanCallback.onDiscovered(
+                    toClientNearbyDevice(nearbyDeviceParcelable, mScanType)));
+        }
+
+        @Override
+        public void onUpdated(NearbyDeviceParcelable nearbyDeviceParcelable)
+                throws RemoteException {
+            mExecutor.execute(
+                    () -> mScanCallback.onUpdated(
+                            toClientNearbyDevice(nearbyDeviceParcelable, mScanType)));
+        }
+
+        @Override
+        public void onLost(NearbyDeviceParcelable nearbyDeviceParcelable) throws RemoteException {
+            mExecutor.execute(
+                    () -> mScanCallback.onLost(
+                            toClientNearbyDevice(nearbyDeviceParcelable, mScanType)));
+        }
+    }
+
+    private static class BroadcastListenerTransport extends IBroadcastListener.Stub {
+        private volatile @Nullable BroadcastCallback mBroadcastCallback;
+        private Executor mExecutor;
+
+        BroadcastListenerTransport(BroadcastCallback broadcastCallback,
+                @CallbackExecutor Executor executor) {
+            mBroadcastCallback = broadcastCallback;
+            mExecutor = executor;
+        }
+
+        void setExecutor(Executor executor) {
+            Preconditions.checkArgument(
+                    executor != null, "invalid null executor");
+            mExecutor = executor;
+        }
+
+        boolean isRegistered() {
+            return mBroadcastCallback != null;
+        }
+
+        void unregister() {
+            mBroadcastCallback = null;
+        }
+
+        @Override
+        public void onStatusChanged(int status) {
+            mExecutor.execute(() -> {
+                if (mBroadcastCallback != null) {
+                    mBroadcastCallback.onStatusChanged(status);
+                }
+            });
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PairStatusMetadata.aidl b/nearby/framework/java/android/nearby/PairStatusMetadata.aidl
new file mode 100644
index 0000000..911a300
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PairStatusMetadata.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.nearby;
+
+/**
+ * Metadata about an ongoing paring. Wraps transient data like status and progress.
+ *
+ * @hide
+ */
+parcelable PairStatusMetadata;
diff --git a/nearby/framework/java/android/nearby/PairStatusMetadata.java b/nearby/framework/java/android/nearby/PairStatusMetadata.java
new file mode 100644
index 0000000..438cd6b
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PairStatusMetadata.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Metadata about an ongoing paring. Wraps transient data like status and progress.
+ *
+ * @hide
+ */
+public final class PairStatusMetadata implements Parcelable {
+
+    @Status
+    private final int mStatus;
+
+    /** The status of the pairing. */
+    @IntDef({
+            Status.UNKNOWN,
+            Status.SUCCESS,
+            Status.FAIL,
+            Status.DISMISS
+    })
+    public @interface Status {
+        int UNKNOWN = 1000;
+        int SUCCESS = 1001;
+        int FAIL = 1002;
+        int DISMISS = 1003;
+    }
+
+    /** Converts the status to readable string. */
+    public static String statusToString(@Status int status) {
+        switch (status) {
+            case Status.SUCCESS:
+                return "SUCCESS";
+            case Status.FAIL:
+                return "FAIL";
+            case Status.DISMISS:
+                return "DISMISS";
+            case Status.UNKNOWN:
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    public int getStatus() {
+        return mStatus;
+    }
+
+    @Override
+    public String toString() {
+        return "PairStatusMetadata[ status=" + statusToString(mStatus) + "]";
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof PairStatusMetadata) {
+            return mStatus == ((PairStatusMetadata) other).mStatus;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStatus);
+    }
+
+    public PairStatusMetadata(@Status int status) {
+        mStatus = status;
+    }
+
+    public static final Creator<PairStatusMetadata> CREATOR = new Creator<PairStatusMetadata>() {
+        @Override
+        public PairStatusMetadata createFromParcel(Parcel in) {
+            return new PairStatusMetadata(in.readInt());
+        }
+
+        @Override
+        public PairStatusMetadata[] newArray(int size) {
+            return new PairStatusMetadata[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int getStability() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStatus);
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java b/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java
new file mode 100644
index 0000000..d01be06
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java
@@ -0,0 +1,208 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Request for Nearby Presence Broadcast.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PresenceBroadcastRequest extends BroadcastRequest implements Parcelable {
+    private final byte[] mSalt;
+    private final List<Integer> mActions;
+    private final PrivateCredential mCredential;
+    private final List<DataElement> mExtendedProperties;
+
+    private PresenceBroadcastRequest(@BroadcastVersion int version, int txPower,
+            List<Integer> mediums, byte[] salt, List<Integer> actions,
+            PrivateCredential credential, List<DataElement> extendedProperties) {
+        super(BROADCAST_TYPE_NEARBY_PRESENCE, version, txPower, mediums);
+        mSalt = salt;
+        mActions = actions;
+        mCredential = credential;
+        mExtendedProperties = extendedProperties;
+    }
+
+    private PresenceBroadcastRequest(Parcel in) {
+        super(BROADCAST_TYPE_NEARBY_PRESENCE, in);
+        mSalt = new byte[in.readInt()];
+        in.readByteArray(mSalt);
+
+        mActions = new ArrayList<>();
+        in.readList(mActions, Integer.class.getClassLoader(), Integer.class);
+        mCredential = in.readParcelable(PrivateCredential.class.getClassLoader(),
+                PrivateCredential.class);
+        mExtendedProperties = new ArrayList<>();
+        in.readList(mExtendedProperties, DataElement.class.getClassLoader(), DataElement.class);
+    }
+
+    @NonNull
+    public static final Creator<PresenceBroadcastRequest> CREATOR =
+            new Creator<PresenceBroadcastRequest>() {
+                @Override
+                public PresenceBroadcastRequest createFromParcel(Parcel in) {
+                    // Skip Broadcast request type - it's used by parent class.
+                    in.readInt();
+                    return createFromParcelBody(in);
+                }
+
+                @Override
+                public PresenceBroadcastRequest[] newArray(int size) {
+                    return new PresenceBroadcastRequest[size];
+                }
+            };
+
+    static PresenceBroadcastRequest createFromParcelBody(Parcel in) {
+        return new PresenceBroadcastRequest(in);
+    }
+
+    /**
+     * Returns the salt associated with this broadcast request.
+     */
+    @NonNull
+    public byte[] getSalt() {
+        return mSalt;
+    }
+
+    /**
+     * Returns actions associated with this broadcast request.
+     */
+    @NonNull
+    public List<Integer> getActions() {
+        return mActions;
+    }
+
+    /**
+     * Returns the private credential associated with this broadcast request.
+     */
+    @NonNull
+    public PrivateCredential getCredential() {
+        return mCredential;
+    }
+
+    /**
+     * Returns extended property information associated with this broadcast request.
+     */
+    @NonNull
+    public List<DataElement> getExtendedProperties() {
+        return mExtendedProperties;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mSalt.length);
+        dest.writeByteArray(mSalt);
+        dest.writeList(mActions);
+        dest.writeParcelable(mCredential, /** parcelableFlags= */0);
+        dest.writeList(mExtendedProperties);
+    }
+
+    /**
+     * Builder for {@link PresenceBroadcastRequest}.
+     */
+    public static final class Builder {
+        private final List<Integer> mMediums;
+        private final List<Integer> mActions;
+        private final List<DataElement> mExtendedProperties;
+        private final byte[] mSalt;
+        private final PrivateCredential mCredential;
+
+        private int mVersion;
+        private int mTxPower;
+
+        public Builder(@NonNull List<Integer> mediums, @NonNull byte[] salt,
+                @NonNull PrivateCredential credential) {
+            Preconditions.checkState(!mediums.isEmpty(), "mediums cannot be empty");
+            Preconditions.checkState(salt != null && salt.length > 0, "salt cannot be empty");
+
+            mVersion = PRESENCE_VERSION_V0;
+            mTxPower = UNKNOWN_TX_POWER;
+            mCredential = credential;
+            mActions = new ArrayList<>();
+            mExtendedProperties = new ArrayList<>();
+
+            mSalt = salt;
+            mMediums = mediums;
+        }
+
+        /**
+         * Sets the version for this request.
+         */
+        @NonNull
+        public Builder setVersion(@BroadcastVersion int version) {
+            mVersion = version;
+            return this;
+        }
+
+        /**
+         * Sets the calibrated tx power level in dBm for this request. The tx power level should
+         * be between -127 dBm and 126 dBm.
+         */
+        @NonNull
+        public Builder setTxPower(@IntRange(from = -127, to = 126) int txPower) {
+            mTxPower = txPower;
+            return this;
+        }
+
+        /**
+         * Adds an action for the presence broadcast request.
+         */
+        @NonNull
+        public Builder addAction(@IntRange(from = 1, to = 255) int action) {
+            mActions.add(action);
+            return this;
+        }
+
+        /**
+         * Adds an extended property for the presence broadcast request.
+         */
+        @NonNull
+        public Builder addExtendedProperty(@NonNull DataElement dataElement) {
+            Objects.requireNonNull(dataElement);
+            mExtendedProperties.add(dataElement);
+            return this;
+        }
+
+        /**
+         * Builds a {@link PresenceBroadcastRequest}.
+         */
+        @NonNull
+        public PresenceBroadcastRequest build() {
+            return new PresenceBroadcastRequest(mVersion, mTxPower, mMediums, mSalt, mActions,
+                    mCredential, mExtendedProperties);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PresenceCredential.java b/nearby/framework/java/android/nearby/PresenceCredential.java
new file mode 100644
index 0000000..7ad6ae9
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceCredential.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a credential for Nearby Presence.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class PresenceCredential {
+    /**
+     * Private credential type.
+     */
+    public static final int CREDENTIAL_TYPE_PRIVATE = 0;
+
+    /**
+     * Public credential type.
+     */
+    public static final int CREDENTIAL_TYPE_PUBLIC = 1;
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CREDENTIAL_TYPE_PUBLIC, CREDENTIAL_TYPE_PRIVATE})
+    public @interface CredentialType {
+    }
+
+    /**
+     * Unknown identity type.
+     */
+    public static final int IDENTITY_TYPE_UNKNOWN = 0;
+
+    /**
+     * Private identity type.
+     */
+    public static final int IDENTITY_TYPE_PRIVATE = 1;
+    /**
+     * Provisioned identity type.
+     */
+    public static final int IDENTITY_TYPE_PROVISIONED = 2;
+    /**
+     * Trusted identity type.
+     */
+    public static final int IDENTITY_TYPE_TRUSTED = 3;
+    /**
+     * Public identity type.
+     */
+    public static final int IDENTITY_TYPE_PUBLIC = 4;
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({IDENTITY_TYPE_UNKNOWN, IDENTITY_TYPE_PRIVATE, IDENTITY_TYPE_PROVISIONED,
+            IDENTITY_TYPE_TRUSTED, IDENTITY_TYPE_PUBLIC})
+    public @interface IdentityType {
+    }
+
+    private final @CredentialType int mType;
+    private final @IdentityType int mIdentityType;
+    private final byte[] mSecretId;
+    private final byte[] mAuthenticityKey;
+    private final List<CredentialElement> mCredentialElements;
+
+    PresenceCredential(@CredentialType int type, @IdentityType int identityType,
+            byte[] secretId, byte[] authenticityKey, List<CredentialElement> credentialElements) {
+        mType = type;
+        mIdentityType = identityType;
+        mSecretId = secretId;
+        mAuthenticityKey = authenticityKey;
+        mCredentialElements = credentialElements;
+    }
+
+    PresenceCredential(@CredentialType int type, Parcel in) {
+        mType = type;
+        mIdentityType = in.readInt();
+        mSecretId = new byte[in.readInt()];
+        in.readByteArray(mSecretId);
+        mAuthenticityKey = new byte[in.readInt()];
+        in.readByteArray(mAuthenticityKey);
+        mCredentialElements = new ArrayList<>();
+        in.readList(mCredentialElements, CredentialElement.class.getClassLoader(),
+                CredentialElement.class);
+    }
+
+    /**
+     * Returns the type of the credential.
+     */
+    public @CredentialType int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the identity type of the credential.
+     */
+    public @IdentityType int getIdentityType() {
+        return mIdentityType;
+    }
+
+    /**
+     * Returns the secret id of the credential.
+     */
+    @NonNull
+    public byte[] getSecretId() {
+        return mSecretId;
+    }
+
+    /**
+     * Returns the authenticity key of the credential.
+     */
+    @NonNull
+    public byte[] getAuthenticityKey() {
+        return mAuthenticityKey;
+    }
+
+    /**
+     * Returns the elements of the credential.
+     */
+    @NonNull
+    public List<CredentialElement> getCredentialElements() {
+        return mCredentialElements;
+    }
+
+    /**
+     * Writes the presence credential to the parcel.
+     *
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mIdentityType);
+        dest.writeInt(mSecretId.length);
+        dest.writeByteArray(mSecretId);
+        dest.writeInt(mAuthenticityKey.length);
+        dest.writeByteArray(mAuthenticityKey);
+        dest.writeList(mCredentialElements);
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PresenceDevice.java b/nearby/framework/java/android/nearby/PresenceDevice.java
new file mode 100644
index 0000000..12fc2a3
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceDevice.java
@@ -0,0 +1,373 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a Presence device from nearby scans.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PresenceDevice extends NearbyDevice implements Parcelable {
+
+    /** The type of presence device. */
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DeviceType.UNKNOWN,
+            DeviceType.PHONE,
+            DeviceType.TABLET,
+            DeviceType.DISPLAY,
+            DeviceType.LAPTOP,
+            DeviceType.TV,
+            DeviceType.WATCH,
+    })
+    public @interface DeviceType {
+        /** The type of the device is unknown. */
+        int UNKNOWN = 0;
+        /** The device is a phone. */
+        int PHONE = 1;
+        /** The device is a tablet. */
+        int TABLET = 2;
+        /** The device is a display. */
+        int DISPLAY = 3;
+        /** The device is a laptop. */
+        int LAPTOP = 4;
+        /** The device is a TV. */
+        int TV = 5;
+        /** The device is a watch. */
+        int WATCH = 6;
+    }
+
+    private final String mDeviceId;
+    private final byte[] mSalt;
+    private final byte[] mSecretId;
+    private final byte[] mEncryptedIdentity;
+    private final int mDeviceType;
+    private final String mDeviceImageUrl;
+    private final long mDiscoveryTimestampMillis;
+    private final List<DataElement> mExtendedProperties;
+
+    /**
+     * The id of the device.
+     *
+     * <p>This id is not a hardware id. It may rotate based on the remote device's broadcasts.
+     */
+    @NonNull
+    public String getDeviceId() {
+        return mDeviceId;
+    }
+
+    /**
+     * Returns the salt used when presence device is discovered.
+     */
+    @NonNull
+    public byte[] getSalt() {
+        return mSalt;
+    }
+
+    /**
+     * Returns the secret used when presence device is discovered.
+     */
+    @NonNull
+    public byte[] getSecretId() {
+        return mSecretId;
+    }
+
+    /**
+     * Returns the encrypted identity used when presence device is discovered.
+     */
+    @NonNull
+    public byte[] getEncryptedIdentity() {
+        return mEncryptedIdentity;
+    }
+
+    /** The type of the device. */
+    @DeviceType
+    public int getDeviceType() {
+        return mDeviceType;
+    }
+
+    /** An image URL representing the device. */
+    @Nullable
+    public String getDeviceImageUrl() {
+        return mDeviceImageUrl;
+    }
+
+    /** The timestamp (since boot) when the device is discovered. */
+    public long getDiscoveryTimestampMillis() {
+        return mDiscoveryTimestampMillis;
+    }
+
+    /**
+     * The extended properties of the device.
+     */
+    @NonNull
+    public List<DataElement> getExtendedProperties() {
+        return mExtendedProperties;
+    }
+
+    private PresenceDevice(String deviceName, List<Integer> mMediums, int rssi, String deviceId,
+            byte[] salt, byte[] secretId, byte[] encryptedIdentity, int deviceType,
+            String deviceImageUrl, long discoveryTimestampMillis,
+            List<DataElement> extendedProperties) {
+        super(deviceName, mMediums, rssi);
+        mDeviceId = deviceId;
+        mSalt = salt;
+        mSecretId = secretId;
+        mEncryptedIdentity = encryptedIdentity;
+        mDeviceType = deviceType;
+        mDeviceImageUrl = deviceImageUrl;
+        mDiscoveryTimestampMillis = discoveryTimestampMillis;
+        mExtendedProperties = extendedProperties;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        String name = getName();
+        dest.writeInt(name == null ? 0 : 1);
+        if (name != null) {
+            dest.writeString(name);
+        }
+        List<Integer> mediums = getMediums();
+        dest.writeInt(mediums.size());
+        for (int medium : mediums) {
+            dest.writeInt(medium);
+        }
+        dest.writeInt(getRssi());
+        dest.writeInt(mSalt.length);
+        dest.writeByteArray(mSalt);
+        dest.writeInt(mSecretId.length);
+        dest.writeByteArray(mSecretId);
+        dest.writeInt(mEncryptedIdentity.length);
+        dest.writeByteArray(mEncryptedIdentity);
+        dest.writeString(mDeviceId);
+        dest.writeInt(mDeviceType);
+        dest.writeInt(mDeviceImageUrl == null ? 0 : 1);
+        if (mDeviceImageUrl != null) {
+            dest.writeString(mDeviceImageUrl);
+        }
+        dest.writeLong(mDiscoveryTimestampMillis);
+        dest.writeInt(mExtendedProperties.size());
+        for (DataElement dataElement : mExtendedProperties) {
+            dest.writeParcelable(dataElement, 0);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<PresenceDevice> CREATOR = new Creator<PresenceDevice>() {
+        @Override
+        public PresenceDevice createFromParcel(Parcel in) {
+            String name = null;
+            if (in.readInt() == 1) {
+                name = in.readString();
+            }
+            int size = in.readInt();
+            List<Integer> mediums = new ArrayList<>();
+            for (int i = 0; i < size; i++) {
+                mediums.add(in.readInt());
+            }
+            int rssi = in.readInt();
+            byte[] salt = new byte[in.readInt()];
+            in.readByteArray(salt);
+            byte[] secretId = new byte[in.readInt()];
+            in.readByteArray(secretId);
+            byte[] encryptedIdentity = new byte[in.readInt()];
+            in.readByteArray(encryptedIdentity);
+            String deviceId = in.readString();
+            int deviceType = in.readInt();
+            String deviceImageUrl = null;
+            if (in.readInt() == 1) {
+                deviceImageUrl = in.readString();
+            }
+            long discoveryTimeMillis = in.readLong();
+            int dataElementSize = in.readInt();
+            List<DataElement> dataElements = new ArrayList<>();
+            for (int i = 0; i < dataElementSize; i++) {
+                dataElements.add(
+                        in.readParcelable(DataElement.class.getClassLoader(), DataElement.class));
+            }
+            Builder builder = new Builder(deviceId, salt, secretId, encryptedIdentity)
+                    .setName(name)
+                    .setRssi(rssi)
+                    .setDeviceType(deviceType)
+                    .setDeviceImageUrl(deviceImageUrl)
+                    .setDiscoveryTimestampMillis(discoveryTimeMillis);
+            for (int i = 0; i < mediums.size(); i++) {
+                builder.addMedium(mediums.get(i));
+            }
+            for (int i = 0; i < dataElements.size(); i++) {
+                builder.addExtendedProperty(dataElements.get(i));
+            }
+            return builder.build();
+        }
+
+        @Override
+        public PresenceDevice[] newArray(int size) {
+            return new PresenceDevice[size];
+        }
+    };
+
+    /**
+     * Builder class for {@link PresenceDevice}.
+     */
+    public static final class Builder {
+
+        private final List<DataElement> mExtendedProperties;
+        private final List<Integer> mMediums;
+        private final String mDeviceId;
+        private final byte[] mSalt;
+        private final byte[] mSecretId;
+        private final byte[] mEncryptedIdentity;
+
+        private String mName;
+        private int mRssi;
+        private int mDeviceType;
+        private String mDeviceImageUrl;
+        private long mDiscoveryTimestampMillis;
+
+        /**
+         * Constructs a {@link Builder}.
+         *
+         * @param deviceId the identifier on the discovered Presence device
+         * @param salt a random salt used in the beacon from the Presence device.
+         * @param secretId a secret identifier used in the beacon from the Presence device.
+         * @param encryptedIdentity the identity associated with the Presence device.
+         */
+        public Builder(@NonNull String deviceId, @NonNull byte[] salt, @NonNull byte[] secretId,
+                @NonNull byte[] encryptedIdentity) {
+            mDeviceId = deviceId;
+            mSalt = salt;
+            mSecretId = secretId;
+            mEncryptedIdentity = encryptedIdentity;
+            mMediums = new ArrayList<>();
+            mExtendedProperties = new ArrayList<>();
+            mRssi = -127;
+        }
+
+        /**
+         * Sets the name of the Presence device.
+         *
+         * @param name Name of the Presence. Can be {@code null} if there is no name.
+         */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Adds the medium over which the Presence device is discovered.
+         *
+         * @param medium The {@link Medium} over which the device is discovered.
+         */
+        @NonNull
+        public Builder addMedium(@Medium int medium) {
+            mMediums.add(medium);
+            return this;
+        }
+
+        /**
+         * Sets the RSSI on the discovered Presence device.
+         *
+         * @param rssi The received signal strength in dBm.
+         */
+        @NonNull
+        public Builder setRssi(int rssi) {
+            mRssi = rssi;
+            return this;
+        }
+
+        /**
+         * Sets the type of discovered Presence device.
+         *
+         * @param deviceType Type of the Presence device.
+         */
+        @NonNull
+        public Builder setDeviceType(@DeviceType int deviceType) {
+            mDeviceType = deviceType;
+            return this;
+        }
+
+
+        /**
+         * Sets the image url of the discovered Presence device.
+         *
+         * @param deviceImageUrl Url of the image for the Presence device.
+         */
+        @NonNull
+        public Builder setDeviceImageUrl(@Nullable String deviceImageUrl) {
+            mDeviceImageUrl = deviceImageUrl;
+            return this;
+        }
+
+
+        /**
+         * Sets discovery timestamp, the clock is based on elapsed time.
+         *
+         * @param discoveryTimestampMillis Timestamp when the presence device is discovered.
+         */
+        @NonNull
+        public Builder setDiscoveryTimestampMillis(long discoveryTimestampMillis) {
+            mDiscoveryTimestampMillis = discoveryTimestampMillis;
+            return this;
+        }
+
+
+        /**
+         * Adds an extended property of the discovered presence device.
+         *
+         * @param dataElement Data element of the extended property.
+         */
+        @NonNull
+        public Builder addExtendedProperty(@NonNull DataElement dataElement) {
+            Objects.requireNonNull(dataElement);
+            mExtendedProperties.add(dataElement);
+            return this;
+        }
+
+        /**
+         * Builds a Presence device.
+         */
+        @NonNull
+        public PresenceDevice build() {
+            return new PresenceDevice(mName, mMediums, mRssi, mDeviceId,
+                    mSalt, mSecretId, mEncryptedIdentity,
+                    mDeviceType,
+                    mDeviceImageUrl,
+                    mDiscoveryTimestampMillis, mExtendedProperties);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PresenceScanFilter.java b/nearby/framework/java/android/nearby/PresenceScanFilter.java
new file mode 100644
index 0000000..f0c3c06
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceScanFilter.java
@@ -0,0 +1,211 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Filter for scanning a nearby presence device.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PresenceScanFilter extends ScanFilter implements Parcelable {
+
+    private final List<PublicCredential> mCredentials;
+    private final List<Integer> mPresenceActions;
+    private final List<DataElement> mExtendedProperties;
+
+    /**
+     * A list of credentials to filter on.
+     */
+    @NonNull
+    public List<PublicCredential> getCredentials() {
+        return mCredentials;
+    }
+
+    /**
+     * A list of presence actions for matching.
+     */
+    @NonNull
+    public List<Integer> getPresenceActions() {
+        return mPresenceActions;
+    }
+
+    /**
+     * A bundle of extended properties for matching.
+     */
+    @NonNull
+    public List<DataElement> getExtendedProperties() {
+        return mExtendedProperties;
+    }
+
+    private PresenceScanFilter(int rssiThreshold, List<PublicCredential> credentials,
+            List<Integer> presenceActions, List<DataElement> extendedProperties) {
+        super(ScanRequest.SCAN_TYPE_NEARBY_PRESENCE, rssiThreshold);
+        mCredentials = new ArrayList<>(credentials);
+        mPresenceActions = new ArrayList<>(presenceActions);
+        mExtendedProperties = extendedProperties;
+    }
+
+    private PresenceScanFilter(Parcel in) {
+        super(ScanRequest.SCAN_TYPE_NEARBY_PRESENCE, in);
+        mCredentials = new ArrayList<>();
+        if (in.readInt() != 0) {
+            in.readParcelableList(mCredentials, PublicCredential.class.getClassLoader(),
+                    PublicCredential.class);
+        }
+        mPresenceActions = new ArrayList<>();
+        if (in.readInt() != 0) {
+            in.readList(mPresenceActions, Integer.class.getClassLoader(), Integer.class);
+        }
+        mExtendedProperties = new ArrayList<>();
+        if (in.readInt() != 0) {
+            in.readParcelableList(mExtendedProperties, DataElement.class.getClassLoader(),
+                    DataElement.class);
+        }
+    }
+
+    @NonNull
+    public static final Creator<PresenceScanFilter> CREATOR = new Creator<PresenceScanFilter>() {
+        @Override
+        public PresenceScanFilter createFromParcel(Parcel in) {
+            // Skip Scan Filter type as it's used for parent class.
+            in.readInt();
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public PresenceScanFilter[] newArray(int size) {
+            return new PresenceScanFilter[size];
+        }
+    };
+
+    /**
+     * Create a {@link PresenceScanFilter} from the parcel body. Scan Filter type is skipped.
+     */
+    static PresenceScanFilter createFromParcelBody(Parcel in) {
+        return new PresenceScanFilter(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mCredentials.size());
+        if (!mCredentials.isEmpty()) {
+            dest.writeParcelableList(mCredentials, 0);
+        }
+        dest.writeInt(mPresenceActions.size());
+        if (!mPresenceActions.isEmpty()) {
+            dest.writeList(mPresenceActions);
+        }
+        dest.writeInt(mExtendedProperties.size());
+        if (!mExtendedProperties.isEmpty()) {
+            dest.writeList(mExtendedProperties);
+        }
+    }
+
+    /**
+     * Builder for {@link PresenceScanFilter}.
+     */
+    public static final class Builder {
+        private int mMaxPathLoss;
+        private final Set<PublicCredential> mCredentials;
+        private final Set<Integer> mPresenceIdentities;
+        private final Set<Integer> mPresenceActions;
+        private final List<DataElement> mExtendedProperties;
+
+        public Builder() {
+            mMaxPathLoss = 127;
+            mCredentials = new ArraySet<>();
+            mPresenceIdentities = new ArraySet<>();
+            mPresenceActions = new ArraySet<>();
+            mExtendedProperties = new ArrayList<>();
+        }
+
+        /**
+         * Sets the max path loss (in dBm) for the scan request. The path loss is the attenuation
+         * of radio energy between sender and receiver. Path loss here is defined as (TxPower -
+         * Rssi).
+         */
+        @NonNull
+        public Builder setMaxPathLoss(@IntRange(from = 0, to = 127) int maxPathLoss) {
+            mMaxPathLoss = maxPathLoss;
+            return this;
+        }
+
+        /**
+         * Adds a credential the scan filter is expected to match.
+         */
+
+        @NonNull
+        public Builder addCredential(@NonNull PublicCredential credential) {
+            Objects.requireNonNull(credential);
+            mCredentials.add(credential);
+            return this;
+        }
+
+        /**
+         * Adds a presence action for filtering, which is an action the discoverer could take
+         * when it receives the broadcast of a presence device.
+         */
+        @NonNull
+        public Builder addPresenceAction(@IntRange(from = 1, to = 255) int action) {
+            mPresenceActions.add(action);
+            return this;
+        }
+
+        /**
+         * Add an extended property for scan filtering.
+         */
+        @NonNull
+        public Builder addExtendedProperty(@NonNull DataElement dataElement) {
+            Objects.requireNonNull(dataElement);
+            mExtendedProperties.add(dataElement);
+            return this;
+        }
+
+        /**
+         * Builds the scan filter.
+         */
+        @NonNull
+        public PresenceScanFilter build() {
+            Preconditions.checkState(!mCredentials.isEmpty(), "credentials cannot be empty");
+            return new PresenceScanFilter(mMaxPathLoss,
+                    new ArrayList<>(mCredentials),
+                    new ArrayList<>(mPresenceActions),
+                    mExtendedProperties);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PrivateCredential.java b/nearby/framework/java/android/nearby/PrivateCredential.java
new file mode 100644
index 0000000..d915cc6
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PrivateCredential.java
@@ -0,0 +1,161 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a private credential.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PrivateCredential extends PresenceCredential implements Parcelable {
+
+    @NonNull
+    public static final Creator<PrivateCredential> CREATOR = new Creator<PrivateCredential>() {
+        @Override
+        public PrivateCredential createFromParcel(Parcel in) {
+            in.readInt(); // Skip the type as it's used by parent class only.
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public PrivateCredential[] newArray(int size) {
+            return new PrivateCredential[size];
+        }
+    };
+
+    private byte[] mMetadataEncryptionKey;
+    private String mDeviceName;
+
+    private PrivateCredential(Parcel in) {
+        super(CREDENTIAL_TYPE_PRIVATE, in);
+        mMetadataEncryptionKey = new byte[in.readInt()];
+        in.readByteArray(mMetadataEncryptionKey);
+        mDeviceName = in.readString();
+    }
+
+    private PrivateCredential(int identityType, byte[] secretId,
+            String deviceName, byte[] authenticityKey, List<CredentialElement> credentialElements,
+            byte[] metadataEncryptionKey) {
+        super(CREDENTIAL_TYPE_PRIVATE, identityType, secretId, authenticityKey,
+                credentialElements);
+        mDeviceName = deviceName;
+        mMetadataEncryptionKey = metadataEncryptionKey;
+    }
+
+    static PrivateCredential createFromParcelBody(Parcel in) {
+        return new PrivateCredential(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mMetadataEncryptionKey.length);
+        dest.writeByteArray(mMetadataEncryptionKey);
+        dest.writeString(mDeviceName);
+    }
+
+    /**
+     * Returns the metadata encryption key associated with this credential.
+     */
+    @NonNull
+    public byte[] getMetadataEncryptionKey() {
+        return mMetadataEncryptionKey;
+    }
+
+    /**
+     * Returns the device name associated with this credential.
+     */
+    @NonNull
+    public String getDeviceName() {
+        return mDeviceName;
+    }
+
+    /**
+     * Builder class for {@link PresenceCredential}.
+     */
+    public static final class Builder {
+        private final List<CredentialElement> mCredentialElements;
+
+        private @IdentityType int mIdentityType;
+        private final byte[] mSecretId;
+        private final byte[] mAuthenticityKey;
+        private final byte[] mMetadataEncryptionKey;
+        private final String mDeviceName;
+
+        public Builder(@NonNull byte[] secretId, @NonNull byte[] authenticityKey,
+                @NonNull byte[] metadataEncryptionKey, @NonNull String deviceName) {
+            Preconditions.checkState(secretId != null && secretId.length > 0,
+                    "secret id cannot be empty");
+            Preconditions.checkState(authenticityKey != null && authenticityKey.length > 0,
+                    "authenticity key cannot be empty");
+            Preconditions.checkState(
+                    metadataEncryptionKey != null && metadataEncryptionKey.length > 0,
+                    "metadataEncryptionKey cannot be empty");
+            Preconditions.checkState(deviceName != null && deviceName.length() > 0,
+                    "deviceName cannot be empty");
+            mSecretId = secretId;
+            mAuthenticityKey = authenticityKey;
+            mMetadataEncryptionKey = metadataEncryptionKey;
+            mDeviceName = deviceName;
+            mCredentialElements = new ArrayList<>();
+        }
+
+        /**
+         * Sets the identity type for the presence credential.
+         */
+        @NonNull
+        public Builder setIdentityType(@IdentityType int identityType) {
+            mIdentityType = identityType;
+            return this;
+        }
+
+        /**
+         * Adds an element to the credential.
+         */
+        @NonNull
+        public Builder addCredentialElement(@NonNull CredentialElement credentialElement) {
+            mCredentialElements.add(credentialElement);
+            return this;
+        }
+
+        /**
+         * Builds the {@link PresenceCredential}.
+         */
+        @NonNull
+        public PrivateCredential build() {
+            return new PrivateCredential(mIdentityType, mSecretId, mDeviceName,
+                    mAuthenticityKey, mCredentialElements, mMetadataEncryptionKey);
+        }
+
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PublicCredential.java b/nearby/framework/java/android/nearby/PublicCredential.java
new file mode 100644
index 0000000..8aac323
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PublicCredential.java
@@ -0,0 +1,184 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a public credential.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PublicCredential extends PresenceCredential implements Parcelable {
+    @NonNull
+    public static final Creator<PublicCredential> CREATOR = new Creator<PublicCredential>() {
+        @Override
+        public PublicCredential createFromParcel(Parcel in) {
+            in.readInt(); // Skip the type as it's used by parent class only.
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public PublicCredential[] newArray(int size) {
+            return new PublicCredential[size];
+        }
+    };
+
+    private final byte[] mPublicKey;
+    private final byte[] mEncryptedMetadata;
+    private final byte[] mEncryptedMetadataKeyTag;
+
+    private PublicCredential(int identityType, byte[] secretId, byte[] authenticityKey,
+            List<CredentialElement> credentialElements, byte[] publicKey, byte[] encryptedMetadata,
+            byte[] metadataEncryptionKeyTag) {
+        super(CREDENTIAL_TYPE_PUBLIC, identityType, secretId, authenticityKey, credentialElements);
+        mPublicKey = publicKey;
+        mEncryptedMetadata = encryptedMetadata;
+        mEncryptedMetadataKeyTag = metadataEncryptionKeyTag;
+    }
+
+    private PublicCredential(Parcel in) {
+        super(CREDENTIAL_TYPE_PUBLIC, in);
+        mPublicKey = new byte[in.readInt()];
+        in.readByteArray(mPublicKey);
+        mEncryptedMetadata = new byte[in.readInt()];
+        in.readByteArray(mEncryptedMetadata);
+        mEncryptedMetadataKeyTag = new byte[in.readInt()];
+        in.readByteArray(mEncryptedMetadataKeyTag);
+    }
+
+    static PublicCredential createFromParcelBody(Parcel in) {
+        return new PublicCredential(in);
+    }
+
+    /**
+     * Returns the public key associated with this credential.
+     */
+    @NonNull
+    public byte[] getPublicKey() {
+        return mPublicKey;
+    }
+
+    /**
+     * Returns the encrypted metadata associated with this credential.
+     */
+    @NonNull
+    public byte[] getEncryptedMetadata() {
+        return mEncryptedMetadata;
+    }
+
+    /**
+     * Returns the metadata encryption key tag associated with this credential.
+     */
+    @NonNull
+    public byte[] getEncryptedMetadataKeyTag() {
+        return mEncryptedMetadataKeyTag;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mPublicKey.length);
+        dest.writeByteArray(mPublicKey);
+        dest.writeInt(mEncryptedMetadata.length);
+        dest.writeByteArray(mEncryptedMetadata);
+        dest.writeInt(mEncryptedMetadataKeyTag.length);
+        dest.writeByteArray(mEncryptedMetadataKeyTag);
+    }
+
+    /**
+     * Builder class for {@link PresenceCredential}.
+     */
+    public static final class Builder {
+        private final List<CredentialElement> mCredentialElements;
+
+        private @IdentityType int mIdentityType;
+        private final byte[] mSecretId;
+        private final byte[] mAuthenticityKey;
+        private final byte[] mPublicKey;
+        private final byte[] mEncryptedMetadata;
+        private final byte[] mEncryptedMetadataKeyTag;
+
+        public Builder(@NonNull byte[] secretId, @NonNull byte[] authenticityKey,
+                @NonNull byte[] publicKey, @NonNull byte[] encryptedMetadata,
+                @NonNull byte[] encryptedMetadataKeyTag) {
+            Preconditions.checkState(secretId != null && secretId.length > 0,
+                    "secret id cannot be empty");
+            Preconditions.checkState(authenticityKey != null && authenticityKey.length > 0,
+                    "authenticity key cannot be empty");
+            Preconditions.checkState(
+                    publicKey != null && publicKey.length > 0,
+                    "publicKey cannot be empty");
+            Preconditions.checkState(encryptedMetadata != null && encryptedMetadata.length > 0,
+                    "encryptedMetadata cannot be empty");
+            Preconditions.checkState(
+                    encryptedMetadataKeyTag != null && encryptedMetadataKeyTag.length > 0,
+                    "encryptedMetadataKeyTag cannot be empty");
+
+            mSecretId = secretId;
+            mAuthenticityKey = authenticityKey;
+            mPublicKey = publicKey;
+            mEncryptedMetadata = encryptedMetadata;
+            mEncryptedMetadataKeyTag = encryptedMetadataKeyTag;
+            mCredentialElements = new ArrayList<>();
+        }
+
+        /**
+         * Sets the identity type for the presence credential.
+         */
+        @NonNull
+        public Builder setIdentityType(@IdentityType int identityType) {
+            mIdentityType = identityType;
+            return this;
+        }
+
+        /**
+         * Adds an element to the credential.
+         */
+        @NonNull
+        public Builder addCredentialElement(@NonNull CredentialElement credentialElement) {
+            Objects.requireNonNull(credentialElement);
+            mCredentialElements.add(credentialElement);
+            return this;
+        }
+
+        /**
+         * Builds the {@link PresenceCredential}.
+         */
+        @NonNull
+        public PublicCredential build() {
+            return new PublicCredential(mIdentityType, mSecretId, mAuthenticityKey,
+                    mCredentialElements, mPublicKey, mEncryptedMetadata, mEncryptedMetadataKeyTag);
+        }
+
+    }
+}
diff --git a/nearby/framework/java/android/nearby/ScanCallback.java b/nearby/framework/java/android/nearby/ScanCallback.java
new file mode 100644
index 0000000..1b1b4bc
--- /dev/null
+++ b/nearby/framework/java/android/nearby/ScanCallback.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+/**
+ * Reports newly discovered devices.
+ * Note: The frequency of the callback is dependent on whether the caller
+ * is in the foreground or background. Foreground callbacks will occur
+ * as fast as the underlying medium supports, whereas background
+ * use cases will be rate limited to improve performance (ie, only on
+ * found/lost/significant changes).
+ *
+ * @hide
+ */
+@SystemApi
+public interface ScanCallback {
+    /**
+     * Reports a {@link NearbyDevice} being discovered.
+     *
+     * @param device {@link NearbyDevice} that is found.
+     */
+    void onDiscovered(@NonNull NearbyDevice device);
+
+    /**
+     * Reports a {@link NearbyDevice} information(distance, packet, and etc) changed.
+     *
+     * @param device {@link NearbyDevice} that has updates.
+     */
+    void onUpdated(@NonNull NearbyDevice device);
+
+    /**
+     * Reports a {@link NearbyDevice} is no longer within range.
+     *
+     * @param device {@link NearbyDevice} that is lost.
+     */
+    void onLost(@NonNull NearbyDevice device);
+}
diff --git a/nearby/framework/java/android/nearby/ScanFilter.java b/nearby/framework/java/android/nearby/ScanFilter.java
new file mode 100644
index 0000000..1409426
--- /dev/null
+++ b/nearby/framework/java/android/nearby/ScanFilter.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.nearby;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+
+/**
+ * Filter for scanning a nearby device.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class ScanFilter {
+    /**
+     * Creates a {@link ScanFilter} from the parcel.
+     *
+     * @hide
+     */
+    public static ScanFilter createFromParcel(Parcel in) {
+        int type = in.readInt();
+        switch (type) {
+            // Currently, only Nearby Presence filtering is supported, in the future
+            // filtering other nearby specifications will be added.
+            case ScanRequest.SCAN_TYPE_NEARBY_PRESENCE:
+                return PresenceScanFilter.createFromParcelBody(in);
+            default:
+                throw new IllegalStateException(
+                        "Unexpected scan type (value " + type + ") in parcel.");
+        }
+    }
+
+    private final @ScanRequest.ScanType int mType;
+    private final int mMaxPathLoss;
+
+    /**
+     * Constructs a Scan Filter.
+     *
+     * @hide
+     */
+    ScanFilter(@ScanRequest.ScanType int type, @IntRange(from = 0, to = 127) int maxPathLoss) {
+        mType = type;
+        mMaxPathLoss = maxPathLoss;
+    }
+
+    /**
+     * Constructs a Scan Filter.
+     *
+     * @hide
+     */
+    ScanFilter(@ScanRequest.ScanType int type, Parcel in) {
+        mType = type;
+        mMaxPathLoss = in.readInt();
+    }
+
+    /**
+     * Returns the type of this scan filter.
+     */
+    public @ScanRequest.ScanType int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the maximum path loss (in dBm) of the received scan result. The path loss is the
+     * attenuation of radio energy between sender and receiver. Path loss here is defined as
+     * (TxPower - Rssi).
+     */
+    @IntRange(from = 0, to = 127)
+    public int getMaxPathLoss() {
+        return mMaxPathLoss;
+    }
+
+    /**
+     *
+     * Writes the scan filter to the parcel.
+     *
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mMaxPathLoss);
+    }
+}
diff --git a/nearby/framework/java/android/nearby/ScanRequest.aidl b/nearby/framework/java/android/nearby/ScanRequest.aidl
new file mode 100644
index 0000000..438dfed
--- /dev/null
+++ b/nearby/framework/java/android/nearby/ScanRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.nearby;
+
+parcelable ScanRequest;
diff --git a/nearby/framework/java/android/nearby/ScanRequest.java b/nearby/framework/java/android/nearby/ScanRequest.java
new file mode 100644
index 0000000..a90b72d
--- /dev/null
+++ b/nearby/framework/java/android/nearby/ScanRequest.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2021 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 android.nearby;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.WorkSource;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * An encapsulation of various parameters for requesting nearby scans.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ScanRequest implements Parcelable {
+
+    /** Scan type for scanning devices using fast pair protocol. */
+    public static final int SCAN_TYPE_FAST_PAIR = 1;
+    /** Scan type for scanning devices using nearby share protocol. */
+    public static final int SCAN_TYPE_NEARBY_SHARE = 2;
+    /** Scan type for scanning devices using nearby presence protocol. */
+    public static final int SCAN_TYPE_NEARBY_PRESENCE = 3;
+    /** Scan type for scanning devices using exposure notification protocol. */
+    public static final int SCAN_TYPE_EXPOSURE_NOTIFICATION = 4;
+
+    /** Scan mode uses highest duty cycle. */
+    public static final int SCAN_MODE_LOW_LATENCY = 2;
+    /** Scan in balanced power mode.
+     *  Scan results are returned at a rate that provides a good trade-off between scan
+     *  frequency and power consumption.
+     */
+    public static final int SCAN_MODE_BALANCED = 1;
+    /** Perform scan in low power mode. This is the default scan mode. */
+    public static final int SCAN_MODE_LOW_POWER = 0;
+    /**
+     * A special scan mode. Applications using this scan mode will passively listen for other scan
+     * results without starting BLE scans themselves.
+     */
+    public static final int SCAN_MODE_NO_POWER = -1;
+    /**
+     * Used to read a ScanRequest from a Parcel.
+     */
+    @NonNull
+    public static final Creator<ScanRequest> CREATOR = new Creator<ScanRequest>() {
+        @Override
+        public ScanRequest createFromParcel(Parcel in) {
+            ScanRequest.Builder builder = new ScanRequest.Builder()
+                    .setScanType(in.readInt())
+                    .setScanMode(in.readInt())
+                    .setBleEnabled(in.readBoolean())
+                    .setWorkSource(in.readTypedObject(WorkSource.CREATOR));
+            for (int i = 0; i < in.readInt(); i++) {
+                builder.addScanFilter(ScanFilter.createFromParcel(in));
+            }
+            return builder.build();
+        }
+
+        @Override
+        public ScanRequest[] newArray(int size) {
+            return new ScanRequest[size];
+        }
+    };
+
+    private final @ScanType int mScanType;
+    private final @ScanMode int mScanMode;
+    private final boolean mBleEnabled;
+    private final @NonNull WorkSource mWorkSource;
+    private final List<ScanFilter> mScanFilters;
+
+    private ScanRequest(@ScanType int scanType, @ScanMode int scanMode, boolean bleEnabled,
+            @NonNull WorkSource workSource, List<ScanFilter> scanFilters) {
+        mScanType = scanType;
+        mScanMode = scanMode;
+        mBleEnabled = bleEnabled;
+        mWorkSource = workSource;
+        mScanFilters = scanFilters;
+    }
+
+    /**
+     * Convert scan mode to readable string.
+     *
+     * @param scanMode Integer that may represent a{@link ScanMode}.
+     */
+    @NonNull
+    public static String scanModeToString(@ScanMode int scanMode) {
+        switch (scanMode) {
+            case SCAN_MODE_LOW_LATENCY:
+                return "SCAN_MODE_LOW_LATENCY";
+            case SCAN_MODE_BALANCED:
+                return "SCAN_MODE_BALANCED";
+            case SCAN_MODE_LOW_POWER:
+                return "SCAN_MODE_LOW_POWER";
+            case SCAN_MODE_NO_POWER:
+                return "SCAN_MODE_NO_POWER";
+            default:
+                return "SCAN_MODE_INVALID";
+        }
+    }
+
+    /**
+     * Returns true if an integer is a defined scan type.
+     */
+    public static boolean isValidScanType(@ScanType int scanType) {
+        return scanType == SCAN_TYPE_FAST_PAIR
+                || scanType == SCAN_TYPE_NEARBY_SHARE
+                || scanType == SCAN_TYPE_NEARBY_PRESENCE
+                || scanType == SCAN_TYPE_EXPOSURE_NOTIFICATION;
+    }
+
+    /**
+     * Returns true if an integer is a defined scan mode.
+     */
+    public static boolean isValidScanMode(@ScanMode int scanMode) {
+        return scanMode == SCAN_MODE_LOW_LATENCY
+                || scanMode == SCAN_MODE_BALANCED
+                || scanMode == SCAN_MODE_LOW_POWER
+                || scanMode == SCAN_MODE_NO_POWER;
+    }
+
+    /**
+     * Returns the scan type for this request.
+     */
+    public @ScanType int getScanType() {
+        return mScanType;
+    }
+
+    /**
+     * Returns the scan mode for this request.
+     */
+    public @ScanMode int getScanMode() {
+        return mScanMode;
+    }
+
+    /**
+     * Returns if Bluetooth Low Energy enabled for scanning.
+     */
+    public boolean isBleEnabled() {
+        return mBleEnabled;
+    }
+
+    /**
+     * Returns Scan Filters for this request.
+     */
+    @NonNull
+    public List<ScanFilter> getScanFilters() {
+        return mScanFilters;
+    }
+
+    /**
+     * Returns the work source used for power attribution of this request.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public WorkSource getWorkSource() {
+        return mWorkSource;
+    }
+
+    /**
+     * No special parcel contents.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Returns a string representation of this ScanRequest.
+     */
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("Request[")
+                .append("scanType=").append(mScanType);
+        stringBuilder.append(", scanMode=").append(scanModeToString(mScanMode));
+        stringBuilder.append(", enableBle=").append(mBleEnabled);
+        stringBuilder.append(", workSource=").append(mWorkSource);
+        stringBuilder.append(", scanFilters=").append(mScanFilters);
+        stringBuilder.append("]");
+        return stringBuilder.toString();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mScanType);
+        dest.writeInt(mScanMode);
+        dest.writeBoolean(mBleEnabled);
+        dest.writeTypedObject(mWorkSource, /* parcelableFlags= */0);
+        dest.writeInt(mScanFilters.size());
+        for (int i = 0; i < mScanFilters.size(); ++i) {
+            mScanFilters.get(i).writeToParcel(dest, flags);
+        }
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof ScanRequest) {
+            ScanRequest otherRequest = (ScanRequest) other;
+            return mScanType == otherRequest.mScanType
+                    && (mScanMode == otherRequest.mScanMode)
+                    && (mBleEnabled == otherRequest.mBleEnabled)
+                    && (Objects.equals(mWorkSource, otherRequest.mWorkSource));
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mScanType, mScanMode, mBleEnabled, mWorkSource);
+    }
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SCAN_TYPE_FAST_PAIR, SCAN_TYPE_NEARBY_SHARE, SCAN_TYPE_NEARBY_PRESENCE,
+            SCAN_TYPE_EXPOSURE_NOTIFICATION})
+    public @interface ScanType {
+    }
+
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SCAN_MODE_LOW_LATENCY, SCAN_MODE_BALANCED,
+            SCAN_MODE_LOW_POWER,
+            SCAN_MODE_NO_POWER})
+    public @interface ScanMode {}
+
+    /** A builder class for {@link ScanRequest}. */
+    public static final class Builder {
+        private static final int INVALID_SCAN_TYPE = -1;
+        private @ScanType int mScanType;
+        private @ScanMode int mScanMode;
+
+        private boolean mBleEnabled;
+        private WorkSource mWorkSource;
+        private List<ScanFilter> mScanFilters;
+
+        /** Creates a new Builder with the given scan type. */
+        public Builder() {
+            mScanType = INVALID_SCAN_TYPE;
+            mBleEnabled = true;
+            mWorkSource = new WorkSource();
+            mScanFilters = new ArrayList<>();
+        }
+
+        /**
+         * Sets the scan type for the request. The scan type must be one of the SCAN_TYPE_ constants
+         * in {@link ScanRequest}.
+         *
+         * @param scanType The scan type for the request
+         */
+        @NonNull
+        public Builder setScanType(@ScanType int scanType) {
+            mScanType = scanType;
+            return this;
+        }
+
+        /**
+         * Sets the scan mode for the request. The scan type must be one of the SCAN_MODE_ constants
+         * in {@link ScanRequest}.
+         *
+         * @param scanMode The scan mode for the request
+         */
+        @NonNull
+        public Builder setScanMode(@ScanMode int scanMode) {
+            mScanMode = scanMode;
+            return this;
+        }
+
+        /**
+         * Sets if the ble is enabled for scanning.
+         *
+         * @param bleEnabled If the BluetoothLe is enabled in the device.
+         */
+        @NonNull
+        public Builder setBleEnabled(boolean bleEnabled) {
+            mBleEnabled = bleEnabled;
+            return this;
+        }
+
+        /**
+         * Sets the work source to use for power attribution for this scan request. Defaults to
+         * empty work source, which implies the caller that sends the scan request will be used
+         * for power attribution.
+         *
+         * <p>Permission enforcement occurs when the resulting scan request is used, not when
+         * this method is invoked.
+         *
+         * @param workSource identifying the application(s) for which to blame for the scan.
+         * @hide
+         */
+        @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
+        @NonNull
+        @SystemApi
+        public Builder setWorkSource(@Nullable WorkSource workSource) {
+            if (workSource == null) {
+                mWorkSource = new WorkSource();
+            } else {
+                mWorkSource = workSource;
+            }
+            return this;
+        }
+
+        /**
+         * Adds a scan filter to the request. Client can call this method multiple times to add
+         * more than one scan filter. Scan results that match any of these scan filters will
+         * be returned.
+         *
+         * <p>On devices with hardware support, scan filters can significantly improve the battery
+         * usage of Nearby scans.
+         *
+         * @param scanFilter Filter for scanning the request.
+         */
+        @NonNull
+        public Builder addScanFilter(@NonNull ScanFilter scanFilter) {
+            Objects.requireNonNull(scanFilter);
+            mScanFilters.add(scanFilter);
+            return this;
+        }
+
+        /**
+         * Builds a scan request from this builder.
+         *
+         * @return a new nearby scan request.
+         * @throws IllegalStateException if the scanType is not one of the SCAN_TYPE_ constants in
+         *                               {@link ScanRequest}.
+         */
+        @NonNull
+        public ScanRequest build() {
+            Preconditions.checkState(isValidScanType(mScanType),
+                    "invalid scan type : " + mScanType
+                            + ", scan type must be one of ScanRequest#SCAN_TYPE_");
+            Preconditions.checkState(isValidScanMode(mScanMode),
+                    "invalid scan mode : " + mScanMode
+                            + ", scan mode must be one of ScanMode#SCAN_MODE_");
+            return new ScanRequest(mScanType, mScanMode, mBleEnabled, mWorkSource, mScanFilters);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/aidl/ByteArrayParcel.aidl b/nearby/framework/java/android/nearby/aidl/ByteArrayParcel.aidl
new file mode 100644
index 0000000..53c73bd
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/ByteArrayParcel.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+ * This is to support 2D byte arrays.
+ * {@hide}
+ */
+parcelable ByteArrayParcel {
+    byte[] byteArray;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairAccountDevicesMetadataRequestParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairAccountDevicesMetadataRequestParcel.aidl
new file mode 100644
index 0000000..fc3ba22
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairAccountDevicesMetadataRequestParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.accounts.Account;
+import android.nearby.aidl.ByteArrayParcel;
+
+/**
+ * Request details for Metadata of Fast Pair devices associated with an account.
+ * {@hide}
+ */
+parcelable FastPairAccountDevicesMetadataRequestParcel {
+    Account account;
+    ByteArrayParcel[] deviceAccountKeys;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairAccountKeyDeviceMetadataParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairAccountKeyDeviceMetadataParcel.aidl
new file mode 100644
index 0000000..8014323
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairAccountKeyDeviceMetadataParcel.aidl
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.nearby.aidl.FastPairDeviceMetadataParcel;
+import android.nearby.aidl.FastPairDiscoveryItemParcel;
+
+/**
+ * Metadata of a Fast Pair device associated with an account.
+ * {@hide}
+ */
+ // TODO(b/204780849): remove unnecessary fields and polish comments.
+parcelable FastPairAccountKeyDeviceMetadataParcel {
+    // Key of the Fast Pair device associated with the account.
+    byte[] deviceAccountKey;
+    // Hash function of device account key and public bluetooth address.
+    byte[] sha256DeviceAccountKeyPublicAddress;
+    // Fast Pair device metadata for the Fast Pair device.
+    FastPairDeviceMetadataParcel metadata;
+    // Fast Pair discovery item tied to both the Fast Pair device and the
+    // account.
+    FastPairDiscoveryItemParcel discoveryItem;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataParcel.aidl
new file mode 100644
index 0000000..4fd4d4b
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataParcel.aidl
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.nearby.aidl.FastPairDeviceMetadataParcel;
+
+/**
+ * Metadata of a Fast Pair device keyed by AntispoofKey,
+ * Used by initial pairing without account association.
+ *
+ * {@hide}
+ */
+parcelable FastPairAntispoofKeyDeviceMetadataParcel {
+    // Anti-spoof public key.
+    byte[] antispoofPublicKey;
+
+    // Fast Pair device metadata for the Fast Pair device.
+    FastPairDeviceMetadataParcel deviceMetadata;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataRequestParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataRequestParcel.aidl
new file mode 100644
index 0000000..afdcf15
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairAntispoofKeyDeviceMetadataRequestParcel.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+ * Request details for metadata of a Fast Pair device keyed by either
+ * antispoofKey or modelId.
+ * {@hide}
+ */
+parcelable FastPairAntispoofKeyDeviceMetadataRequestParcel {
+    byte[] modelId;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl
new file mode 100644
index 0000000..ef00321
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairDeviceMetadataParcel.aidl
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+ * Fast Pair Device Metadata for a given device model ID.
+ * @hide
+ */
+// TODO(b/204780849): remove unnecessary fields and polish comments.
+parcelable FastPairDeviceMetadataParcel {
+    // The image to show on the notification.
+    String imageUrl;
+
+    // The intent that will be launched via the notification.
+    String intentUri;
+
+    // The transmit power of the device's BLE chip.
+    int bleTxPower;
+
+    // The distance that the device must be within to show a notification.
+    // If no distance is set, we default to 0.6 meters. Only Nearby admins can
+    // change this.
+    float triggerDistance;
+
+    // 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".
+    String trueWirelessImageUrlLeftBud;
+    String trueWirelessImageUrlRightBud;
+    String trueWirelessImageUrlCase;
+
+    // Stings to be displayed in notification surfaced for a device.
+    // The locale of all of the Strings.
+    String locale;
+
+    // The notification description for when the device is initially discovered.
+    String initialNotificationDescription;
+
+    // The notification description for when the device is initially discovered
+    // and no account is logged in.
+    String initialNotificationDescriptionNoAccount;
+
+    // The notification description for once we have finished pairing and the
+    // companion app has been opened. For Bisto devices, this String will point
+    // users to setting up the assistant.
+    String openCompanionAppDescription;
+
+    // The notification description for once we have finished pairing and the
+    // companion app needs to be updated before use.
+    String updateCompanionAppDescription;
+
+    // The notification description for once we have finished pairing and the
+    // companion app needs to be installed.
+    String downloadCompanionAppDescription;
+
+    // The notification title when a pairing fails.
+    String unableToConnectTitle;
+
+    // The notification summary when a pairing fails.
+    String unableToConnectDescription;
+
+    // The description that helps user initially paired with device.
+    String initialPairingDescription;
+
+    // The description that let user open the companion app.
+    String connectSuccessCompanionAppInstalled;
+
+    // The description that let user download the companion app.
+    String connectSuccessCompanionAppNotInstalled;
+
+    // The description that reminds user there is a paired device nearby.
+    String subsequentPairingDescription;
+
+    // The description that reminds users opt in their device.
+    String retroactivePairingDescription;
+
+    // The description that indicates companion app is about to launch.
+    String waitLaunchCompanionAppDescription;
+
+    // The description that indicates go to bluetooth settings when connection
+    // fail.
+    String failConnectGoToSettingsDescription;
+
+    // The title of the UI to ask the user to confirm the pin code.
+    String confirmPinTitle;
+
+    // The description of the UI to ask the user to confirm the pin code.
+    String confirmPinDescription;
+
+    // The title of the UI to ask the user to confirm to sync contacts.
+    String syncContactsTitle;
+
+    // The description of the UI to ask the user to confirm to sync contacts.
+    String syncContactsDescription;
+
+    // The title of the UI to ask the user to confirm to sync SMS.
+    String syncSmsTitle;
+
+    // The description of the UI to ask the user to confirm to sync SMS.
+    String syncSmsDescription;
+
+    // The description in half sheet to ask user setup google assistant
+    String assistantSetupHalfSheet;
+
+    // The description in notification to ask user setup google assistant
+    String assistantSetupNotification;
+
+    // Description of the connect device action on TV, when user is not logged in.
+    String fastPairTvConnectDeviceNoAccountDescription;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairDiscoveryItemParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairDiscoveryItemParcel.aidl
new file mode 100644
index 0000000..5ba18bb
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairDiscoveryItemParcel.aidl
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+ * Fast Pair Discovery Item.
+ * @hide
+ */
+// TODO(b/204780849): remove unnecessary fields and polish comments.
+parcelable FastPairDiscoveryItemParcel {
+  // Offline item: unique ID generated on client.
+  // Online item: unique ID generated on server.
+  String id;
+
+  int type;
+
+  // The most recent all upper case mac associated with this item.
+  // (Mac-to-DiscoveryItem is a many-to-many relationship)
+  String macAddress;
+
+  String actionUrl;
+
+  // The bluetooth device name from advertisement
+  String deviceName;
+
+  // Item's title
+  String title;
+
+  // Item's description.
+  String description;
+
+  // The URL for display
+  String displayUrl;
+
+  // Client timestamp when the beacon was last observed in BLE scan.
+  long lastObservationTimestampMillis;
+
+  // Client timestamp when the beacon was first observed in BLE scan.
+  long firstObservationTimestampMillis;
+
+  // Item's current state. e.g. if the item is blocked.
+  int state;
+
+  // The resolved url type for the action_url.
+  int actionUrlType;
+
+  // The timestamp when the user is redirected to Play Store after clicking on
+  // the item.
+  long pendingAppInstallTimestampMillis;
+
+  // Beacon's RSSI value
+  int rssi;
+
+  // Beacon's tx power
+  int txPower;
+
+  // Human readable name of the app designated to open the uri
+  // Used in the second line of the notification, "Open in {} app"
+  String appName;
+
+  // ID used for associating several DiscoveryItems.  These items may be
+  // visually displayed together.
+  String groupId;
+
+  // Whether the attachment is created in debug namespace
+  int attachmentType;
+
+  // Package name of the App that owns this item.
+  String packageName;
+
+  // The "feature" graphic image url used for large sized list view entries.
+  String featureGraphicUrl;
+
+  // TriggerId identifies the trigger/beacon that is attached with a message.
+  // It's generated from server for online messages to synchronize formatting
+  // across client versions.
+  // Example:
+  // * BLE_UID: 3||deadbeef
+  // * BLE_URL: http://trigger.id
+  // See go/discovery-store-message-and-trigger-id for more details.
+  String triggerId;
+
+  // Bytes of item icon in PNG format displayed in Discovery item list.
+  byte[] iconPng;
+
+  // A FIFE URL of the item icon displayed in Discovery item list.
+  String iconFifeUrl;
+
+  // Message written to bugreport for 3P developers.(No sensitive info)
+  // null if the item is valid
+  String debugMessage;
+
+  // Weather the item is filtered out on server.
+  int debugCategory;
+
+  // Client timestamp when the trigger (e.g. beacon) was last lost (e.g. when
+  // Messages told us the beacon's no longer nearby).
+  long lostMillis;
+
+  // The kind of experience the user last had with this (e.g. if they dismissed
+  // the notification, that's bad; but if they tapped it, that's good).
+  int lastUserExperience;
+
+  // The most recent BLE advertisement related to this item.
+  byte[] bleRecordBytes;
+
+  // An ID generated on the server to uniquely identify content.
+  String entityId;
+
+  // Fast Pair antispoof key.
+  byte[] authenticationPublicKeySecp256r1;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountParcel.aidl
new file mode 100644
index 0000000..747758d
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.accounts.Account;
+
+/**
+ * Fast Pair Eligible Account.
+ * {@hide}
+ */
+parcelable FastPairEligibleAccountParcel {
+    Account account;
+    // Whether the account opts in Fast Pair.
+    boolean optIn;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountsRequestParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountsRequestParcel.aidl
new file mode 100644
index 0000000..8db3356
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairEligibleAccountsRequestParcel.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+ * Request details for Fast Pair eligible accounts.
+ * Empty place holder for future expansion.
+ * {@hide}
+ */
+parcelable FastPairEligibleAccountsRequestParcel {
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairManageAccountDeviceRequestParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairManageAccountDeviceRequestParcel.aidl
new file mode 100644
index 0000000..82cf550
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairManageAccountDeviceRequestParcel.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.accounts.Account;
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
+
+/**
+ * Request details for managing Fast Pair device-account mapping.
+ * {@hide}
+ */
+ // TODO(b/204780849): remove unnecessary fields and polish comments.
+parcelable FastPairManageAccountDeviceRequestParcel {
+    Account account;
+    // MANAGE_ACCOUNT_DEVICE_ADD: add Fast Pair device to the account.
+    // MANAGE_ACCOUNT_DEVICE_REMOVE: remove Fast Pair device from the account.
+    int requestType;
+    // Fast Pair account key-ed device metadata.
+    FastPairAccountKeyDeviceMetadataParcel accountKeyDeviceMetadata;
+    // BLE address of the device at the device add time.
+    String bleAddress;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/FastPairManageAccountRequestParcel.aidl b/nearby/framework/java/android/nearby/aidl/FastPairManageAccountRequestParcel.aidl
new file mode 100644
index 0000000..3d92064
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/FastPairManageAccountRequestParcel.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.accounts.Account;
+
+/**
+ * Request details for managing a Fast Pair account.
+ *
+ * {@hide}
+ */
+parcelable FastPairManageAccountRequestParcel {
+    Account account;
+    // MANAGE_ACCOUNT_OPT_IN: opt account into Fast Pair.
+    // MANAGE_ACCOUNT_OPT_OUT: opt account out of Fast Pair.
+    int requestType;
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairAccountDevicesMetadataCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairAccountDevicesMetadataCallback.aidl
new file mode 100644
index 0000000..7db18d0
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairAccountDevicesMetadataCallback.aidl
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
+
+/**
+  * Provides callback interface for OEMs to send back metadata of FastPair
+  * devices associated with an account.
+  *
+  * {@hide}
+  */
+interface IFastPairAccountDevicesMetadataCallback {
+     void onFastPairAccountDevicesMetadataReceived(in FastPairAccountKeyDeviceMetadataParcel[] accountDevicesMetadata);
+     void onError(int code, String message);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairAntispoofKeyDeviceMetadataCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairAntispoofKeyDeviceMetadataCallback.aidl
new file mode 100644
index 0000000..38abba4
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairAntispoofKeyDeviceMetadataCallback.aidl
@@ -0,0 +1,27 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataParcel;
+
+/**
+  * Provides callback interface for OEMs to send FastPair AntispoofKey Device metadata back.
+  *
+  * {@hide}
+  */
+interface IFastPairAntispoofKeyDeviceMetadataCallback {
+     void onFastPairAntispoofKeyDeviceMetadataReceived(in FastPairAntispoofKeyDeviceMetadataParcel metadata);
+     void onError(int code, String message);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairClient.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairClient.aidl
new file mode 100644
index 0000000..4f666bc
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairClient.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.nearby.aidl;
+
+import android.nearby.aidl.IFastPairStatusCallback;
+import android.nearby.FastPairDevice;
+
+/**
+ * 0p API for controlling Fast Pair. Used to talk between foreground activities
+ * and background services.
+ *
+ * {@hide}
+ */
+interface IFastPairClient {
+
+    void registerHalfSheet(in IFastPairStatusCallback fastPairStatusCallback);
+
+    void unregisterHalfSheet(in IFastPairStatusCallback fastPairStatusCallback);
+
+    void connect(in FastPairDevice fastPairDevice);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairDataProvider.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairDataProvider.aidl
new file mode 100644
index 0000000..2956211
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairDataProvider.aidl
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataRequestParcel;
+import android.nearby.aidl.IFastPairAntispoofKeyDeviceMetadataCallback;
+import android.nearby.aidl.FastPairAccountDevicesMetadataRequestParcel;
+import android.nearby.aidl.IFastPairAccountDevicesMetadataCallback;
+import android.nearby.aidl.FastPairEligibleAccountsRequestParcel;
+import android.nearby.aidl.IFastPairEligibleAccountsCallback;
+import android.nearby.aidl.FastPairManageAccountRequestParcel;
+import android.nearby.aidl.IFastPairManageAccountCallback;
+import android.nearby.aidl.FastPairManageAccountDeviceRequestParcel;
+import android.nearby.aidl.IFastPairManageAccountDeviceCallback;
+
+/**
+ * Interface for communicating with the fast pair providers.
+ *
+ * {@hide}
+ */
+oneway interface IFastPairDataProvider {
+    void loadFastPairAntispoofKeyDeviceMetadata(in FastPairAntispoofKeyDeviceMetadataRequestParcel request,
+        in IFastPairAntispoofKeyDeviceMetadataCallback callback);
+    void loadFastPairAccountDevicesMetadata(in FastPairAccountDevicesMetadataRequestParcel request,
+        in IFastPairAccountDevicesMetadataCallback callback);
+    void loadFastPairEligibleAccounts(in FastPairEligibleAccountsRequestParcel request,
+        in IFastPairEligibleAccountsCallback callback);
+    void manageFastPairAccount(in FastPairManageAccountRequestParcel request,
+        in IFastPairManageAccountCallback callback);
+    void manageFastPairAccountDevice(in FastPairManageAccountDeviceRequestParcel request,
+        in IFastPairManageAccountDeviceCallback callback);
+}
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairEligibleAccountsCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairEligibleAccountsCallback.aidl
new file mode 100644
index 0000000..9990014
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairEligibleAccountsCallback.aidl
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+import android.accounts.Account;
+import android.nearby.aidl.FastPairEligibleAccountParcel;
+
+/**
+  * Provides callback interface for OEMs to return FastPair Eligible accounts.
+  *
+  * {@hide}
+  */
+interface IFastPairEligibleAccountsCallback {
+     void onFastPairEligibleAccountsReceived(in FastPairEligibleAccountParcel[] accounts);
+     void onError(int code, String message);
+ }
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountCallback.aidl
new file mode 100644
index 0000000..6b4aaee
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountCallback.aidl
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+  * Provides callback interface to send response for account management request.
+  *
+  * {@hide}
+  */
+interface IFastPairManageAccountCallback {
+     void onSuccess();
+     void onError(int code, String message);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountDeviceCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountDeviceCallback.aidl
new file mode 100644
index 0000000..bffc533
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairManageAccountDeviceCallback.aidl
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 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 android.nearby.aidl;
+
+/**
+  * Provides callback interface to send response for account-device mapping
+  * management request.
+  *
+  * {@hide}
+  */
+interface IFastPairManageAccountDeviceCallback {
+     void onSuccess();
+     void onError(int code, String message);
+}
\ No newline at end of file
diff --git a/nearby/framework/java/android/nearby/aidl/IFastPairStatusCallback.aidl b/nearby/framework/java/android/nearby/aidl/IFastPairStatusCallback.aidl
new file mode 100644
index 0000000..d844c06
--- /dev/null
+++ b/nearby/framework/java/android/nearby/aidl/IFastPairStatusCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 android.nearby.aidl;
+
+import android.nearby.FastPairDevice;
+import android.nearby.PairStatusMetadata;
+
+/**
+ *
+ * Provides callbacks for Fast Pair foreground activity to learn about paring status from backend.
+ *
+ * {@hide}
+ */
+interface IFastPairStatusCallback {
+
+    /** Reports a pair status related metadata associated with a {@link FastPairDevice} */
+    void onPairUpdate(in FastPairDevice fastPairDevice, in PairStatusMetadata pairStatusMetadata);
+}