Add APIs for Presence Broadcast.
Bug: 217283281
Test: atest CtsNearbyFastPairTests
Change-Id: Ic9f684f79a20ab4b546b7cb6833b900e55b35d2e
diff --git a/nearby/framework/java/android/nearby/BroadcastCallback.java b/nearby/framework/java/android/nearby/BroadcastCallback.java
new file mode 100644
index 0000000..84e19b0
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastCallback.java
@@ -0,0 +1,29 @@
+/*
+ * 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 broadcasting request using nearby specification.
+ *
+ * @hide
+ */
+public interface BroadcastCallback {
+ /**
+ * Called when broadcast status changes.
+ */
+ void onStatus(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..5fe07d5
--- /dev/null
+++ b/nearby/framework/java/android/nearby/BroadcastRequest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.SuppressLint;
+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;
+
+/**
+ * Represents a {@link BroadcastRequest}.
+ *
+ * @hide
+ */
+@SuppressLint("ParcelNotFinal") // BroadcastRequest constructor is not public
+public abstract class BroadcastRequest implements Parcelable {
+
+ /** Broadcast type for advertising using nearby presence protocol. */
+ public static final int BROADCAST_TYPE_NEARBY_PRESENCE = 3;
+
+ /**
+ * Tx Power when the value is not set in the broadcast.
+ */
+ public static final int UNKNOWN_TX_POWER = -100;
+
+ /** @hide **/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({BROADCAST_TYPE_NEARBY_PRESENCE})
+ public @interface BroadcastType {
+ }
+
+ public static final @NonNull Creator<BroadcastRequest> CREATOR =
+ new Creator<BroadcastRequest>() {
+ @Override
+ public 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.");
+ }
+ }
+
+ @Override
+ public BroadcastRequest[] newArray(int size) {
+ return new BroadcastRequest[size];
+ }
+ };
+
+ private final @BroadcastType int mType;
+ private final int mTxPower;
+ private final List<Integer> mMediums;
+
+ BroadcastRequest(@BroadcastType int type, int txPower, List<Integer> mediums) {
+ this.mType = type;
+ this.mTxPower = txPower;
+ this.mMediums = mediums;
+ }
+
+ BroadcastRequest(@BroadcastType int type, Parcel in) {
+ mType = type;
+ 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 calibrated TX power when this request is broadcast.
+ */
+ public int getTxPower() {
+ return mTxPower;
+ }
+
+ /**
+ * Returns the list broadcast mediums.
+ */
+ @NonNull
+ public List<Integer> getMediums() {
+ return mMediums;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeInt(mTxPower);
+ dest.writeList(mMediums);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/nearby/framework/java/android/nearby/CredentialElement.java b/nearby/framework/java/android/nearby/CredentialElement.java
new file mode 100644
index 0000000..a8b9ba9
--- /dev/null
+++ b/nearby/framework/java/android/nearby/CredentialElement.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents an element in {@link PresenceCredential}.
+ *
+ * @hide
+ */
+public class CredentialElement implements Parcelable {
+ private final String mKey;
+ private final byte[] mValue;
+
+ private CredentialElement(String key, byte[] value) {
+ 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.Builder().setElement(key, value).build();
+ }
+
+ @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;
+ }
+
+ /**
+ * Builder for {@link CredentialElement}.
+ */
+ public static class Builder {
+ private String mKey;
+ private byte[] mValue;
+
+ /**
+ * Set the key and value for this credential element.
+ */
+ @NonNull
+ public CredentialElement.Builder setElement(@NonNull String key, @NonNull byte[] value) {
+ mKey = key;
+ mValue = value;
+ return this;
+ }
+
+ /**
+ * Builds a {@link CredentialElement}.
+ */
+ @NonNull
+ public CredentialElement build() {
+ Preconditions.checkState(mKey != null && mValue != null,
+ "neither key or value can be null");
+ return new CredentialElement(mKey, 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..68818e1
--- /dev/null
+++ b/nearby/framework/java/android/nearby/DataElement.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import com.android.internal.util.Preconditions;
+
+
+/**
+ * Represents a data element in Nearby Presence.
+ *
+ * @hide
+ */
+public class DataElement implements Parcelable {
+
+ private final String mKey;
+ private final byte[] mValue;
+
+ private DataElement(String key, byte[] value) {
+ mKey = key;
+ mValue = value;
+ }
+
+ @NonNull
+ public static final Creator<DataElement> CREATOR = new Creator<DataElement>() {
+ @Override
+ public DataElement createFromParcel(Parcel in) {
+ String key = in.readString();
+ byte[] value = new byte[in.readInt()];
+ in.readByteArray(value);
+ return new Builder().setElement(key, value).build();
+ }
+
+ @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.writeString(mKey);
+ dest.writeInt(mValue.length);
+ dest.writeByteArray(mValue);
+ }
+
+ /**
+ * Returns the key of the data element.
+ */
+ @NonNull
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * Returns the value of the data element.
+ */
+ @NonNull
+ public byte[] getValue() {
+ return mValue;
+ }
+
+ /**
+ * Builder for {@link DataElement}.
+ */
+ public static class Builder {
+ private String mKey;
+ private byte[] mValue;
+
+ /**
+ * Set the key and value for this data element.
+ */
+ @NonNull
+ public Builder setElement(@NonNull String key, @NonNull byte[] value) {
+ mKey = key;
+ mValue = value;
+ return this;
+ }
+
+ /**
+ * Builds a {@link DataElement}.
+ */
+ @NonNull
+ public DataElement build() {
+ Preconditions.checkState(mKey != null && mValue != null,
+ "neither key or value can be null");
+ return new DataElement(mKey, mValue);
+ }
+ }
+}
diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java
index 20f9164..f8eef7f 100644
--- a/nearby/framework/java/android/nearby/NearbyManager.java
+++ b/nearby/framework/java/android/nearby/NearbyManager.java
@@ -34,8 +34,8 @@
import java.util.concurrent.Executor;
/**
- * This class provides a way to perform Nearby related operations such as scanning and connecting
- * to nearby devices.
+ * 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>.
@@ -139,6 +139,33 @@
}
}
+
+ /**
+ * 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..
+ *
+ * @hide
+ */
+ public void startBroadcast(@NonNull BroadcastRequest broadcastRequest,
+ @CallbackExecutor @NonNull Executor executor, @NonNull BroadcastCallback callback) {
+ // TODO(b/218187205): implement broadcast.
+ }
+
+ /**
+ * Stop the broadcast associated with the given callback.
+ *
+ * @param callback The callback that was used for starting the broadcast.
+ *
+ * @hide
+ */
+ @SuppressLint("ExecutorRegistration")
+ public void stopBroadcast(@NonNull BroadcastCallback callback) {
+ // TODO(b/218187205): implement broadcast.
+ }
+
private static class ScanListenerTransport extends IScanListener.Stub {
private @ScanRequest.ScanType int mScanType;
diff --git a/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java b/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java
new file mode 100644
index 0000000..223322a
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceBroadcastRequest.java
@@ -0,0 +1,214 @@
+/*
+ * 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;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Request for Nearby Presence Broadcast.
+ *
+ * @hide
+ */
+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(int txPower, List<Integer> mediums, byte[] salt,
+ List<Integer> actions,
+ PrivateCredential credential, List<DataElement> extendedProperties) {
+ super(BROADCAST_TYPE_NEARBY_PRESENCE, 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.
+ */
+ 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}.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private final List<Integer> mMediums;
+ private final List<Integer> mActions;
+ private final List<DataElement> mExtendedProperties;
+
+ private int mTxPower;
+ private byte[] mSalt;
+ private PrivateCredential mCredential;
+
+ public Builder() {
+ mTxPower = UNKNOWN_TX_POWER;
+ mMediums = new ArrayList<>();
+ mActions = new ArrayList<>();
+ mExtendedProperties = new ArrayList<>();
+ }
+
+ /**
+ * Sets the calibrated tx power level for this request.
+ */
+ @NonNull
+ public Builder setTxPower(int txPower) {
+ mTxPower = txPower;
+ return this;
+ }
+
+ /**
+ * Add a medium for the presence broadcast request.
+ */
+ @NonNull
+ public Builder addMediums(int medium) {
+ mMediums.add(medium);
+ return this;
+ }
+
+ /**
+ * Sets the salt for the presence broadcast request.
+ */
+ @NonNull
+ public Builder setSalt(byte[] salt) {
+ mSalt = salt;
+ return this;
+ }
+
+ /**
+ * Adds an action for the presence broadcast request.
+ */
+ @NonNull
+ public Builder addAction(int action) {
+ mActions.add(action);
+ return this;
+ }
+
+ /**
+ * Sets the credential associated with the presence broadcast request.
+ */
+ @NonNull
+ public Builder setCredential(@NonNull PrivateCredential credential) {
+ mCredential = credential;
+ return this;
+ }
+
+ /**
+ * Adds an extended property for the presence broadcast request.
+ */
+ @NonNull
+ public Builder addExtendedProperty(DataElement dataElement) {
+ mExtendedProperties.add(dataElement);
+ return this;
+ }
+
+ /**
+ * Builds a {@link PresenceBroadcastRequest}.
+ */
+ @NonNull
+ public PresenceBroadcastRequest build() {
+ Preconditions.checkState(!mMediums.isEmpty(), "mediums cannot be empty");
+ Preconditions.checkState(mSalt != null && mSalt.length > 0, "salt cannot be empty");
+ return new PresenceBroadcastRequest(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..5f0c201
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceCredential.java
@@ -0,0 +1,185 @@
+/*
+ * 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.SuppressLint;
+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;
+
+/**
+ * Represents a credential for Nearby Presence.
+ *
+ * @hide
+ */
+@SuppressLint("ParcelNotFinal") // PresenceCredential constructor is not public
+public abstract class PresenceCredential implements Parcelable {
+ /**
+ * 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[] mSecreteId;
+ private final byte[] mAuthenticityKey;
+ private final List<CredentialElement> mCredentialElements;
+
+ PresenceCredential(@CredentialType int type, @IdentityType int identityType,
+ byte[] secreteId, byte[] authenticityKey, List<CredentialElement> credentialElements) {
+ mType = type;
+ mIdentityType = identityType;
+ mSecreteId = secreteId;
+ mAuthenticityKey = authenticityKey;
+ mCredentialElements = credentialElements;
+ }
+
+ PresenceCredential(@CredentialType int type, Parcel in) {
+ mType = type;
+ mIdentityType = in.readInt();
+ mSecreteId = new byte[in.readInt()];
+ in.readByteArray(mSecreteId);
+ mAuthenticityKey = new byte[in.readInt()];
+ in.readByteArray(mAuthenticityKey);
+ mCredentialElements = new ArrayList<>();
+ in.readList(mCredentialElements, CredentialElement.class.getClassLoader(),
+ CredentialElement.class);
+ }
+
+
+ @NonNull
+ public static final Creator<PresenceCredential> CREATOR = new Creator<PresenceCredential>() {
+ @Override
+ public PresenceCredential createFromParcel(Parcel in) {
+ int type = in.readInt();
+ switch (type) {
+ case CREDENTIAL_TYPE_PRIVATE:
+ return PrivateCredential.createFromParcelBody(in);
+ case CREDENTIAL_TYPE_PUBLIC:
+ return PublicCredential.createFromParcelBody(in);
+ default:
+ throw new IllegalStateException(
+ "Unexpected credential type (value " + type + ") in parcel.");
+ }
+ }
+
+ @Override
+ public PresenceCredential[] newArray(int size) {
+ return new PresenceCredential[size];
+ }
+ };
+
+ /**
+ * 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 secrete id of the credential.
+ */
+ @NonNull
+ public byte[] getSecreteId() {
+ return mSecreteId;
+ }
+
+ /**
+ * 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;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeInt(mIdentityType);
+ dest.writeInt(mSecreteId.length);
+ dest.writeByteArray(mSecreteId);
+ dest.writeInt(mAuthenticityKey.length);
+ dest.writeByteArray(mAuthenticityKey);
+ dest.writeList(mCredentialElements);
+ }
+}
diff --git a/nearby/framework/java/android/nearby/PrivateCredential.java b/nearby/framework/java/android/nearby/PrivateCredential.java
new file mode 100644
index 0000000..e05efa0
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PrivateCredential.java
@@ -0,0 +1,180 @@
+/*
+ * 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;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a private credential.
+ *
+ * @hide
+ */
+public 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();
+ }
+
+ public PrivateCredential(int identityType, byte[] secreteId,
+ String deviceName, byte[] authenticityKey, List<CredentialElement> credentialElements,
+ byte[] metaDataEncryptionKey) {
+ super(CREDENTIAL_TYPE_PRIVATE, identityType, secreteId, 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);
+ }
+
+ public byte[] getMetaDataEncryptionKey() {
+ return mMetaDataEncryptionKey;
+ }
+
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+
+ /**
+ * Builder class for {@link PresenceCredential}.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private final List<CredentialElement> mCredentialElements;
+
+ private @IdentityType int mIdentityType;
+ private byte[] mSecreteId;
+ private byte[] mAuthenticityKey;
+ private byte[] mMetaDataEncryptionKey;
+ private String mDeviceName;
+
+ public Builder() {
+ mCredentialElements = new ArrayList<>();
+ }
+
+ /**
+ * Sets the identity type for the presence credential.
+ */
+ @NonNull
+ public Builder setIdentityType(@IdentityType int identityType) {
+ mIdentityType = identityType;
+ return this;
+ }
+
+ /**
+ * Sets the secrete id for the presence credential.
+ */
+ @NonNull
+ public Builder setSecretId(@NonNull byte[] secreteId) {
+ mSecreteId = secreteId;
+ return this;
+ }
+
+ /**
+ * Sets the authenticity key for the presence credential.
+ */
+ @NonNull
+ public Builder setAuthenticityKey(@NonNull byte[] authenticityKey) {
+ mAuthenticityKey = authenticityKey;
+ return this;
+ }
+
+ /**
+ * Sets the metadata encryption key to the credential.
+ */
+ @NonNull
+ public Builder setMetaDataEncryptionKey(byte[] metaDataEncryptionKey) {
+ mMetaDataEncryptionKey = metaDataEncryptionKey;
+ return this;
+ }
+
+ /**
+ * Sets the device name of the credential.
+ */
+ @NonNull
+ public Builder setDeviceName(String deviceName) {
+ mDeviceName = deviceName;
+ return this;
+ }
+
+ /**
+ * Adds an element to the credential.
+ */
+ @NonNull
+ public Builder addCredentialElement(CredentialElement credentialElement) {
+ mCredentialElements.add(credentialElement);
+ return this;
+ }
+
+ /**
+ * Builds the {@link PresenceCredential}.
+ */
+ @NonNull
+ public PrivateCredential build() {
+ Preconditions.checkState(mSecreteId != null && mSecreteId.length > 0,
+ "secrete id cannot be empty");
+ Preconditions.checkState(mAuthenticityKey != null && mAuthenticityKey.length > 0,
+ "authenticity key cannot be empty");
+ return new PrivateCredential(mIdentityType, mSecreteId, 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..560e7f0
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PublicCredential.java
@@ -0,0 +1,198 @@
+/*
+ * 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;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a public credential.
+ *
+ * @hide
+ */
+public 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[] mMetaDataEncryptionKeyTag;
+
+ private PublicCredential(int identityType, byte[] secreteId, byte[] authenticityKey,
+ List<CredentialElement> credentialElements, byte[] publicKey, byte[] encryptedMetadata,
+ byte[] metaDataEncryptionKeyTag) {
+ super(CREDENTIAL_TYPE_PUBLIC, identityType, secreteId, authenticityKey, credentialElements);
+ mPublicKey = publicKey;
+ mEncryptedMetadata = encryptedMetadata;
+ mMetaDataEncryptionKeyTag = metaDataEncryptionKeyTag;
+ }
+
+ public PublicCredential(Parcel in) {
+ super(CREDENTIAL_TYPE_PUBLIC, in);
+ mPublicKey = new byte[in.readInt()];
+ in.readByteArray(mPublicKey);
+ mEncryptedMetadata = new byte[in.readInt()];
+ in.readByteArray(mEncryptedMetadata);
+ mMetaDataEncryptionKeyTag = new byte[in.readInt()];
+ in.readByteArray(mMetaDataEncryptionKeyTag);
+ }
+
+ static PublicCredential createFromParcelBody(Parcel in) {
+ return new PublicCredential(in);
+ }
+
+ public byte[] getPublicKey() {
+ return mPublicKey;
+ }
+
+ public byte[] getEncryptedMetadata() {
+ return mEncryptedMetadata;
+ }
+
+ public byte[] getMetaDataEncryptionKeyTag() {
+ return mMetaDataEncryptionKeyTag;
+ }
+
+ @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(mMetaDataEncryptionKeyTag.length);
+ dest.writeByteArray(mMetaDataEncryptionKeyTag);
+ }
+
+ /**
+ * Builder class for {@link PresenceCredential}.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private final List<CredentialElement> mCredentialElements;
+
+ private @IdentityType int mIdentityType;
+ private byte[] mSecreteId;
+ private byte[] mAuthenticityKey;
+ private byte[] mPublicKey;
+ private byte[] mEncryptedMetadata;
+ private byte[] mMetaDataEncryptionKeyTag;
+
+ public Builder() {
+ mCredentialElements = new ArrayList<>();
+ }
+
+ /**
+ * Sets the identity type for the presence credential.
+ */
+ @NonNull
+ public Builder setIdentityType(@IdentityType int identityType) {
+ mIdentityType = identityType;
+ return this;
+ }
+
+ /**
+ * Sets the secrete id for the presence credential.
+ */
+ @NonNull
+ public Builder setSecretId(@NonNull byte[] secreteId) {
+ mSecreteId = secreteId;
+ return this;
+ }
+
+ /**
+ * Sets the authenticity key for the presence credential.
+ */
+ @NonNull
+ public Builder setAuthenticityKey(@NonNull byte[] authenticityKey) {
+ mAuthenticityKey = authenticityKey;
+ return this;
+ }
+
+ /**
+ * Adds an element to the credential.
+ */
+ @NonNull
+ public Builder addCredentialElement(CredentialElement credentialElement) {
+ mCredentialElements.add(credentialElement);
+ return this;
+ }
+
+ /**
+ * Sets the public key for the credential.
+ */
+ @NonNull
+ public Builder setPublicKey(byte[] publicKey) {
+ mPublicKey = publicKey;
+ return this;
+ }
+
+ /**
+ * Sets the encrypted metadata.
+ */
+ @NonNull
+ public Builder setEncryptedMetadata(byte[] encryptedMetadata) {
+ mEncryptedMetadata = encryptedMetadata;
+ return this;
+ }
+
+ /**
+ * Sets the metadata encryption key tag.
+ */
+ @NonNull
+ public Builder setMetaDataEncryptionKeyTag(byte[] metaDataEncryptionKeyTag) {
+ mMetaDataEncryptionKeyTag = metaDataEncryptionKeyTag;
+ return this;
+ }
+
+ /**
+ * Builds the {@link PresenceCredential}.
+ */
+ @NonNull
+ public PublicCredential build() {
+ Preconditions.checkState(mSecreteId.length > 0, "secrete id cannot be empty");
+ Preconditions.checkState(mAuthenticityKey.length > 0,
+ "authenticity key cannot be empty");
+ return new PublicCredential(mIdentityType, mSecreteId, mAuthenticityKey,
+ mCredentialElements, mPublicKey, mEncryptedMetadata, mMetaDataEncryptionKeyTag);
+ }
+
+ }
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/CredentialElementTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/CredentialElementTest.java
new file mode 100644
index 0000000..0cf81ee
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/CredentialElementTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.nearby.CredentialElement;
+import android.os.Build;
+import android.os.Parcel;
+
+import androidx.annotation.RequiresApi;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class CredentialElementTest {
+ private static final String KEY = "SECRETE_ID";
+ private static final byte[] VALUE = new byte[]{1, 2, 3, 4};
+
+ @Test
+ public void testBuilder() {
+ CredentialElement element = new CredentialElement.Builder().setElement(KEY,
+ VALUE).build();
+
+ assertThat(element.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(element.getValue(), VALUE)).isTrue();
+ }
+
+ @Test
+ public void testWriteParcel() {
+ CredentialElement element = new CredentialElement.Builder().setElement(KEY,
+ VALUE).build();
+
+ Parcel parcel = Parcel.obtain();
+ element.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CredentialElement elementFromParcel = element.CREATOR.createFromParcel(
+ parcel);
+ parcel.recycle();
+
+ assertThat(elementFromParcel.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(elementFromParcel.getValue(), VALUE)).isTrue();
+ }
+
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/DataElementTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/DataElementTest.java
new file mode 100644
index 0000000..95d64c3
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/DataElementTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.nearby.DataElement;
+import android.os.Build;
+import android.os.Parcel;
+
+import androidx.annotation.RequiresApi;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class DataElementTest {
+
+ private static final String KEY = "SUPPORT_MEDIA";
+ private static final byte[] VALUE = new byte[]{1, 1, 1, 1};
+
+ @Test
+ public void testBuilder() {
+ DataElement dataElement = new DataElement.Builder().setElement(KEY, VALUE).build();
+
+ assertThat(dataElement.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(dataElement.getValue(), VALUE)).isTrue();
+ }
+
+ @Test
+ public void testWriteParcel() {
+ DataElement dataElement = new DataElement.Builder().setElement(KEY, VALUE).build();
+
+ Parcel parcel = Parcel.obtain();
+ dataElement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ DataElement elementFromParcel = DataElement.CREATOR.createFromParcel(
+ parcel);
+ parcel.recycle();
+
+ assertThat(elementFromParcel.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(elementFromParcel.getValue(), VALUE)).isTrue();
+ }
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
index 07e8558..23ae47d 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
@@ -16,12 +16,18 @@
package android.nearby.cts;
+import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
+
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import android.content.Context;
+import android.nearby.BroadcastCallback;
+import android.nearby.BroadcastRequest;
import android.nearby.NearbyDevice;
import android.nearby.NearbyManager;
+import android.nearby.PresenceBroadcastRequest;
+import android.nearby.PrivateCredential;
import android.nearby.ScanCallback;
import android.nearby.ScanRequest;
import android.os.Build;
@@ -44,9 +50,13 @@
@RunWith(AndroidJUnit4.class)
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public class NearbyManagerTest {
+ private static final byte[] SALT = new byte[] {1, 2};
+ private static final byte[] SECRETE_ID = new byte[]{1, 2, 3, 4};
+ private static final byte[] AUTHENTICITY_KEY = new byte[]{0, 1, 1, 1};
+ private static final int BLE_MEDIUM = 1;
- @Mock Context mContext;
- @Mock NearbyManager mNearbyManager;
+ @Mock private Context mContext;
+ @Mock private NearbyManager mNearbyManager;
@Before
public void setUp() {
@@ -79,4 +89,24 @@
mNearbyManager.startScan(scanRequest, Executors.newSingleThreadExecutor(), scanCallback);
mNearbyManager.stopScan(scanCallback);
}
+
+ @Test
+ public void testStartStopBroadcast() {
+ PrivateCredential credential = new PrivateCredential.Builder()
+ .setIdentityType(IDENTITY_TYPE_PRIVATE)
+ .setSecretId(SECRETE_ID)
+ .setAuthenticityKey(AUTHENTICITY_KEY)
+ .build();
+ BroadcastRequest broadcastRequest =
+ new PresenceBroadcastRequest.Builder()
+ .setSalt(SALT)
+ .addMediums(BLE_MEDIUM).setCredential(credential)
+ .build();
+
+ BroadcastCallback callback = status -> {
+ };
+ mNearbyManager.startBroadcast(broadcastRequest, Executors.newSingleThreadExecutor(),
+ callback);
+ mNearbyManager.stopBroadcast(callback);
+ }
}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/PresenceBroadcastRequestTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/PresenceBroadcastRequestTest.java
new file mode 100644
index 0000000..a974008
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/PresenceBroadcastRequestTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.cts;
+
+import static android.nearby.BroadcastRequest.BROADCAST_TYPE_NEARBY_PRESENCE;
+import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.nearby.DataElement;
+import android.nearby.PresenceBroadcastRequest;
+import android.nearby.PrivateCredential;
+import android.os.Build;
+import android.os.Parcel;
+
+import androidx.annotation.RequiresApi;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link PresenceBroadcastRequest}.
+ */
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class PresenceBroadcastRequestTest {
+
+ private static final int TX_POWER = 1;
+ private static final byte[] SALT = new byte[]{1, 2};
+ private static final int ACTION_ID = 123;
+ private static final String SUPPORT_MEDIA_KEY = "SupportMedia";
+ private static final byte[] SUPPORT_MEDIA_VALUE = new byte[]{1, 2, 34};
+ private static final int BLE_MEDIUM = 1;
+ private static final byte[] SECRETE_ID = new byte[]{1, 2, 3, 4};
+ private static final byte[] AUTHENTICITY_KEY = new byte[]{0, 1, 1, 1};
+ private static final byte[] METADATA_ENCRYPTION_KEY = new byte[]{1, 1, 3, 4, 5};
+
+ private PresenceBroadcastRequest.Builder mBuilder;
+
+ @Before
+ public void setUp() {
+ PrivateCredential credential = new PrivateCredential.Builder()
+ .setIdentityType(IDENTITY_TYPE_PRIVATE)
+ .setSecretId(SECRETE_ID)
+ .setAuthenticityKey(AUTHENTICITY_KEY)
+ .setMetaDataEncryptionKey(METADATA_ENCRYPTION_KEY)
+ .build();
+ mBuilder = new PresenceBroadcastRequest.Builder()
+ .setSalt(SALT)
+ .setTxPower(TX_POWER)
+ .setCredential(credential)
+ .addAction(ACTION_ID)
+ .addMediums(BLE_MEDIUM)
+ .addExtendedProperty(new DataElement.Builder().setElement(SUPPORT_MEDIA_KEY,
+ SUPPORT_MEDIA_VALUE).build());
+ }
+
+ @Test
+ public void testBuilder() {
+ PresenceBroadcastRequest broadcastRequest = mBuilder.build();
+
+ assertThat(broadcastRequest.getTxPower()).isEqualTo(TX_POWER);
+ assertThat(broadcastRequest.getActions()).containsExactly(ACTION_ID);
+ assertThat(broadcastRequest.getExtendedProperties().get(0).getKey()).isEqualTo(
+ SUPPORT_MEDIA_KEY);
+ assertThat(broadcastRequest.getMediums()).containsExactly(BLE_MEDIUM);
+ assertThat(broadcastRequest.getCredential().getIdentityType()).isEqualTo(
+ IDENTITY_TYPE_PRIVATE);
+ assertThat(broadcastRequest.getType()).isEqualTo(BROADCAST_TYPE_NEARBY_PRESENCE);
+ }
+
+ @Test
+ public void testWriteParcel() {
+ PresenceBroadcastRequest broadcastRequest = mBuilder.build();
+
+ Parcel parcel = Parcel.obtain();
+ broadcastRequest.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ PresenceBroadcastRequest parcelRequest = PresenceBroadcastRequest.CREATOR.createFromParcel(
+ parcel);
+ parcel.recycle();
+
+ assertThat(parcelRequest.getTxPower()).isEqualTo(TX_POWER);
+ assertThat(parcelRequest.getActions()).containsExactly(ACTION_ID);
+ assertThat(parcelRequest.getExtendedProperties().get(0).getKey()).isEqualTo(
+ SUPPORT_MEDIA_KEY);
+ assertThat(parcelRequest.getMediums()).containsExactly(BLE_MEDIUM);
+ assertThat(parcelRequest.getCredential().getIdentityType()).isEqualTo(
+ IDENTITY_TYPE_PRIVATE);
+ assertThat(parcelRequest.getType()).isEqualTo(BROADCAST_TYPE_NEARBY_PRESENCE);
+
+ }
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/PrivateCredentialTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/PrivateCredentialTest.java
new file mode 100644
index 0000000..1174400
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/PrivateCredentialTest.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.cts;
+
+import static android.nearby.PresenceCredential.CREDENTIAL_TYPE_PRIVATE;
+import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.nearby.CredentialElement;
+import android.nearby.PrivateCredential;
+import android.os.Build;
+import android.os.Parcel;
+
+import androidx.annotation.RequiresApi;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link PrivateCredential}.
+ */
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class PrivateCredentialTest {
+ private static final byte[] SECRETE_ID = new byte[]{1, 2, 3, 4};
+ private static final byte[] AUTHENTICITY_KEY = new byte[]{0, 1, 1, 1};
+ private static final String KEY = "SecreteId";
+ private static final byte[] VALUE = new byte[]{1, 2, 3, 4, 5};
+ private static final byte[] METADATA_ENCRYPTION_KEY = new byte[]{1, 1, 3, 4, 5};
+
+ private PrivateCredential.Builder mBuilder;
+
+ @Before
+ public void setUp() {
+ mBuilder = new PrivateCredential.Builder()
+ .setIdentityType(IDENTITY_TYPE_PRIVATE)
+ .setSecretId(SECRETE_ID).setAuthenticityKey(AUTHENTICITY_KEY)
+ .setMetaDataEncryptionKey(METADATA_ENCRYPTION_KEY)
+ .addCredentialElement(
+ new CredentialElement.Builder().setElement(KEY, VALUE).build());
+ }
+
+ @Test
+ public void testBuilder() {
+ PrivateCredential credential = mBuilder.build();
+
+ assertThat(credential.getType()).isEqualTo(CREDENTIAL_TYPE_PRIVATE);
+ assertThat(credential.getIdentityType()).isEqualTo(IDENTITY_TYPE_PRIVATE);
+ assertThat(Arrays.equals(credential.getSecreteId(), SECRETE_ID)).isTrue();
+ assertThat(Arrays.equals(credential.getAuthenticityKey(), AUTHENTICITY_KEY)).isTrue();
+ assertThat(Arrays.equals(credential.getMetaDataEncryptionKey(),
+ METADATA_ENCRYPTION_KEY)).isTrue();
+ CredentialElement credentialElement = credential.getCredentialElements().get(0);
+ assertThat(credentialElement.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(credentialElement.getValue(), VALUE)).isTrue();
+ }
+
+ @Test
+ public void testWriteParcel() {
+ PrivateCredential credential = mBuilder.build();
+
+ Parcel parcel = Parcel.obtain();
+ credential.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ PrivateCredential credentialFromParcel = PrivateCredential.CREATOR.createFromParcel(
+ parcel);
+ parcel.recycle();
+
+ assertThat(credentialFromParcel.getType()).isEqualTo(CREDENTIAL_TYPE_PRIVATE);
+ assertThat(credentialFromParcel.getIdentityType()).isEqualTo(IDENTITY_TYPE_PRIVATE);
+ assertThat(Arrays.equals(credentialFromParcel.getSecreteId(), SECRETE_ID)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getAuthenticityKey(),
+ AUTHENTICITY_KEY)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getMetaDataEncryptionKey(),
+ METADATA_ENCRYPTION_KEY)).isTrue();
+ CredentialElement credentialElement = credentialFromParcel.getCredentialElements().get(0);
+ assertThat(credentialElement.getKey()).isEqualTo(KEY);
+ assertThat(Arrays.equals(credentialElement.getValue(), VALUE)).isTrue();
+ }
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/PublicCredentialTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/PublicCredentialTest.java
new file mode 100644
index 0000000..2c28768
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/PublicCredentialTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.cts;
+
+import static android.nearby.PresenceCredential.CREDENTIAL_TYPE_PUBLIC;
+import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.nearby.PresenceCredential;
+import android.nearby.PublicCredential;
+import android.os.Build;
+import android.os.Parcel;
+
+import androidx.annotation.RequiresApi;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link PresenceCredential}.
+ */
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class PublicCredentialTest {
+
+ private static final byte[] SECRETE_ID = new byte[]{1, 2, 3, 4};
+ private static final byte[] AUTHENTICITY_KEY = new byte[]{0, 1, 1, 1};
+ private static final byte[] PUBLIC_KEY = new byte[]{1, 1, 2, 2};
+ private static final byte[] ENCRYPTED_METADATA = new byte[]{1, 2, 3, 4, 5};
+ private static final byte[] METADATA_ENCRYPTION_KEY_TAG = new byte[]{1, 1, 3, 4, 5};
+
+ private PublicCredential.Builder mBuilder;
+
+ @Before
+ public void setUp() {
+ mBuilder = new PublicCredential.Builder()
+ .setIdentityType(IDENTITY_TYPE_PRIVATE)
+ .setSecretId(SECRETE_ID).setAuthenticityKey(AUTHENTICITY_KEY)
+ .setPublicKey(PUBLIC_KEY).setEncryptedMetadata(ENCRYPTED_METADATA)
+ .setMetaDataEncryptionKeyTag(METADATA_ENCRYPTION_KEY_TAG);
+ }
+
+ @Test
+ public void testBuilder() {
+ PublicCredential credential = mBuilder.build();
+
+ assertThat(credential.getType()).isEqualTo(CREDENTIAL_TYPE_PUBLIC);
+ assertThat(credential.getIdentityType()).isEqualTo(IDENTITY_TYPE_PRIVATE);
+ assertThat(Arrays.equals(credential.getSecreteId(), SECRETE_ID)).isTrue();
+ assertThat(Arrays.equals(credential.getAuthenticityKey(), AUTHENTICITY_KEY)).isTrue();
+ assertThat(Arrays.equals(credential.getPublicKey(), PUBLIC_KEY)).isTrue();
+ assertThat(Arrays.equals(credential.getEncryptedMetadata(), ENCRYPTED_METADATA)).isTrue();
+ assertThat(Arrays.equals(credential.getMetaDataEncryptionKeyTag(),
+ METADATA_ENCRYPTION_KEY_TAG)).isTrue();
+ }
+
+ @Test
+ public void testWriteParcel() {
+ PublicCredential credential = mBuilder.build();
+
+ Parcel parcel = Parcel.obtain();
+ credential.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ PublicCredential credentialFromParcel = PublicCredential.CREATOR.createFromParcel(
+ parcel);
+ parcel.recycle();
+
+ assertThat(credentialFromParcel.getType()).isEqualTo(CREDENTIAL_TYPE_PUBLIC);
+ assertThat(credentialFromParcel.getIdentityType()).isEqualTo(IDENTITY_TYPE_PRIVATE);
+ assertThat(Arrays.equals(credentialFromParcel.getSecreteId(), SECRETE_ID)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getAuthenticityKey(),
+ AUTHENTICITY_KEY)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getPublicKey(), PUBLIC_KEY)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getEncryptedMetadata(),
+ ENCRYPTED_METADATA)).isTrue();
+ assertThat(Arrays.equals(credentialFromParcel.getMetaDataEncryptionKeyTag(),
+ METADATA_ENCRYPTION_KEY_TAG)).isTrue();
+ }
+}