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);
+}