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