Merge "Apply theme to half sheet and clean up"
diff --git a/nearby/framework/java/android/nearby/PresenceDevice.java b/nearby/framework/java/android/nearby/PresenceDevice.java
new file mode 100644
index 0000000..61326c6
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceDevice.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nearby;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Represents a Presence device from nearby scans.
+ *
+ * @hide
+ */
+public final class PresenceDevice extends NearbyDevice implements Parcelable {
+
+    /** The type of presence device. */
+    /** @hide **/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DeviceType.UNKNOWN,
+            DeviceType.PHONE,
+            DeviceType.TABLET,
+            DeviceType.DISPLAY,
+            DeviceType.LAPTOP,
+            DeviceType.TV,
+            DeviceType.WATCH,
+    })
+    public @interface DeviceType {
+        /** The type of the device is unknown. */
+        int UNKNOWN = 0;
+        /** The device is a phone. */
+        int PHONE = 1;
+        /** The device is a tablet. */
+        int TABLET = 2;
+        /** The device is a display. */
+        int DISPLAY = 3;
+        /** The device is a laptop. */
+        int LAPTOP = 4;
+        /** The device is a TV. */
+        int TV = 5;
+        /** The device is a watch. */
+        int WATCH = 6;
+    }
+
+    private final String mDeviceId;
+    private final int mDeviceType;
+    private final String mDeviceImageUrl;
+    private final long mDiscoveryTimestampMillis;
+    private final Bundle mExtendedProperties;
+
+    /**
+     * Gets the name of the device, or {@code null} if not available.
+     *
+     * @hide
+     */
+    @Nullable
+    @Override
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * The id of the device.
+     *
+     * <p>This id is not a hardware id. It may rotate based on the remote device's broadcasts.
+     */
+    @NonNull
+    public String getDeviceId() {
+        return mDeviceId;
+    }
+
+    /** The type of the device. */
+    @DeviceType
+    public int getDeviceType() {
+        return mDeviceType;
+    }
+
+    /** An image URL representing the device. */
+    @Nullable
+    public String getDeviceImageUrl() {
+        return mDeviceImageUrl;
+    }
+
+    /** The timestamp (since boot) when the device is discovered. */
+    public long getDiscoveryTimestampMillis() {
+        return mDiscoveryTimestampMillis;
+    }
+
+    /**
+     * The extended properties of the device.
+     */
+    @NonNull
+    public Bundle getExtendedProperties() {
+        return mExtendedProperties;
+    }
+
+    private PresenceDevice(String deviceName, int mMedium, int rssi, String deviceId,
+            int deviceType,
+            String deviceImageUrl, long discoveryTimestampMillis,
+            Bundle extendedProperties) {
+        // TODO (b/217462253): change medium to a set in NearbyDevice.
+        super(deviceName, mMedium, rssi);
+        mDeviceId = deviceId;
+        mDeviceType = deviceType;
+        mDeviceImageUrl = deviceImageUrl;
+        mDiscoveryTimestampMillis = discoveryTimestampMillis;
+        mExtendedProperties = extendedProperties;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mName == null ? 0 : 1);
+        if (mName != null) {
+            dest.writeString(mName);
+        }
+        dest.writeInt(mMedium);
+        dest.writeInt(mRssi);
+        dest.writeString(mDeviceId);
+        dest.writeInt(mDeviceType);
+        dest.writeInt(mDeviceImageUrl == null ? 0 : 1);
+        if (mDeviceImageUrl != null) {
+            dest.writeString(mDeviceImageUrl);
+        }
+        dest.writeLong(mDiscoveryTimestampMillis);
+        dest.writeBundle(mExtendedProperties);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<PresenceDevice> CREATOR = new Creator<PresenceDevice>() {
+        @Override
+        public PresenceDevice createFromParcel(Parcel in) {
+            Builder builder = new Builder();
+            if (in.readInt() == 1) {
+                builder.setName(in.readString());
+            }
+            builder.setMedium(in.readInt());
+            builder.setRssi(in.readInt());
+            builder.setDeviceId(in.readString());
+            builder.setDeviceType(in.readInt());
+            if (in.readInt() == 1) {
+                builder.setDeviceImageUrl(in.readString());
+            }
+            builder.setDiscoveryTimestampMillis(in.readLong());
+            Bundle bundle = in.readBundle();
+            for (String key : bundle.keySet()) {
+                builder.addExtendedProperty(key, bundle.getCharSequence(key).toString());
+            }
+            return builder.build();
+        }
+
+        @Override
+        public PresenceDevice[] newArray(int size) {
+            return new PresenceDevice[size];
+        }
+    };
+
+    /**
+     * Builder class for {@link PresenceDevice}.
+     *
+     * @hide
+     */
+    public static final class Builder {
+
+        private final Bundle mExtendedProperties;
+
+        private String mName;
+        private int mRssi;
+        private int mMedium;
+        private String mDeviceId;
+        private int mDeviceType;
+        private String mDeviceImageUrl;
+        private long mDiscoveryTimestampMillis;
+
+        public Builder() {
+            mExtendedProperties = new Bundle();
+            mRssi = -100;
+        }
+
+        /**
+         * Sets the name of the Presence device.
+         *
+         * @param name Name of the Presence. Can be {@code null} if there is no name.
+         */
+        @NonNull
+        public Builder setName(@android.annotation.Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Sets the medium over which the Presence device is discovered.
+         *
+         * @param medium The {@link Medium} over which the device is discovered.
+         */
+        @NonNull
+        public Builder setMedium(@Medium int medium) {
+            mMedium = medium;
+            return this;
+        }
+
+        /**
+         * Sets the RSSI on the discovered Presence device.
+         *
+         * @param rssi The received signal strength in dBm.
+         */
+        @NonNull
+        public Builder setRssi(int rssi) {
+            mRssi = rssi;
+            return this;
+        }
+
+        /**
+         * Sets the identifier on the discovered Presence device.
+         *
+         * @param deviceId Identifier of the Presence device.
+         */
+        @NonNull
+        public Builder setDeviceId(@NonNull String deviceId) {
+            mDeviceId = deviceId;
+            return this;
+        }
+
+
+        /**
+         * Sets the type of discovered Presence device.
+         *
+         * @param deviceType Type of the Presence device.
+         */
+        @NonNull
+        public Builder setDeviceType(int deviceType) {
+            mDeviceType = deviceType;
+            return this;
+        }
+
+
+        /**
+         * Sets the image url of the discovered Presence device.
+         *
+         * @param deviceImageUrl Url of the image for the Presence device.
+         */
+        @NonNull
+        public Builder setDeviceImageUrl(@NonNull String deviceImageUrl) {
+            mDeviceImageUrl = deviceImageUrl;
+            return this;
+        }
+
+
+        /**
+         * Sets discovery timestamp, the clock is based on elapsed time.
+         *
+         * @param discoveryTimestampMillis Timestamp when the presence device is discovered.
+         */
+        @NonNull
+        public Builder setDiscoveryTimestampMillis(long discoveryTimestampMillis) {
+            mDiscoveryTimestampMillis = discoveryTimestampMillis;
+            return this;
+        }
+
+
+        /**
+         * Adds an extended property of the discovered presence device.
+         *
+         * @param key   Key of the extended property.
+         * @param value Value of the extended property,
+         */
+        @NonNull
+        public Builder addExtendedProperty(@NonNull String key, @NonNull String value) {
+            mExtendedProperties.putCharSequence(key, value);
+            return this;
+        }
+
+        /**
+         * Builds a Presence device.
+         */
+        @NonNull
+        public PresenceDevice build() {
+            return new PresenceDevice(mName, mMedium, mRssi, mDeviceId, mDeviceType,
+                    mDeviceImageUrl,
+                    mDiscoveryTimestampMillis, mExtendedProperties);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/PresenceScanFilter.java b/nearby/framework/java/android/nearby/PresenceScanFilter.java
new file mode 100644
index 0000000..61e5049
--- /dev/null
+++ b/nearby/framework/java/android/nearby/PresenceScanFilter.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Filter for scanning a nearby presence device.
+ *
+ * @hide
+ */
+public final class PresenceScanFilter extends ScanFilter implements Parcelable {
+
+    private final List<byte[]> mCertificates;
+    private final List<Integer> mPresenceIdentities;
+    private final List<Integer> mPresenceActions;
+    private final Bundle mExtendedProperties;
+
+    /**
+     * A list of certificates to filter on.
+     */
+    @NonNull
+    public List<byte[]> getCertificates() {
+        return mCertificates;
+    }
+
+    /**
+     * A list of presence identities for matching.
+     */
+    @NonNull
+    public List<Integer> getPresenceIdentities() {
+        return mPresenceIdentities;
+    }
+
+    /**
+     * A list of presence actions for matching.
+     */
+    @NonNull
+    public List<Integer> getPresenceActions() {
+        return mPresenceActions;
+    }
+
+    /**
+     * A bundle of extended properties for matching.
+     */
+    @NonNull
+    public Bundle getExtendedProperties() {
+        return mExtendedProperties;
+    }
+
+    private PresenceScanFilter(int rssiThreshold, List<byte[]> certificates,
+            List<Integer> presenceIdentities, List<Integer> presenceActions,
+            Bundle extendedProperties) {
+        super(ScanRequest.SCAN_TYPE_NEARBY_PRESENCE, rssiThreshold);
+        mCertificates = new ArrayList<>(certificates);
+        mPresenceIdentities = new ArrayList<>(presenceIdentities);
+        mPresenceActions = new ArrayList<>(presenceActions);
+        mExtendedProperties = extendedProperties;
+    }
+
+    private PresenceScanFilter(Parcel in) {
+        super(ScanRequest.SCAN_TYPE_NEARBY_PRESENCE, in);
+        mCertificates = new ArrayList<>();
+        int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            int len = in.readInt();
+            byte[] certificate = new byte[len];
+            in.readByteArray(certificate);
+            mCertificates.add(certificate);
+        }
+        mPresenceIdentities = new ArrayList<>();
+        if (in.readInt() != 0) {
+            in.readList(mPresenceIdentities, Integer.class.getClassLoader(), Integer.class);
+        }
+        mPresenceActions = new ArrayList<>();
+        if (in.readInt() != 0) {
+            in.readList(mPresenceActions, Integer.class.getClassLoader(), Integer.class);
+        }
+        mExtendedProperties = new Bundle();
+        Bundle bundle = in.readBundle(getClass().getClassLoader());
+        for (String key : bundle.keySet()) {
+            mExtendedProperties.putString(key, bundle.getString(key));
+        }
+    }
+
+    @NonNull
+    public static final Creator<PresenceScanFilter> CREATOR = new Creator<PresenceScanFilter>() {
+        @Override
+        public PresenceScanFilter createFromParcel(Parcel in) {
+            // Skip Scan Filter type as it's used for parent class.
+            in.readInt();
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public PresenceScanFilter[] newArray(int size) {
+            return new PresenceScanFilter[size];
+        }
+    };
+
+    /**
+     * Create a {@link PresenceScanFilter} from the parcel body. Scan Filter type is skipped.
+     */
+    static PresenceScanFilter createFromParcelBody(Parcel in) {
+        return new PresenceScanFilter(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mCertificates.size());
+        for (byte[] certificate : mCertificates) {
+            dest.writeInt(certificate.length);
+            dest.writeByteArray(certificate);
+        }
+        dest.writeInt(mPresenceIdentities.size());
+        if (!mPresenceIdentities.isEmpty()) {
+            dest.writeList(mPresenceIdentities);
+        }
+        dest.writeInt(mPresenceActions.size());
+        if (!mPresenceActions.isEmpty()) {
+            dest.writeList(mPresenceActions);
+        }
+        dest.writeBundle(mExtendedProperties);
+    }
+
+    /**
+     * Builder for {@link PresenceScanFilter}.
+     *
+     * @hide
+     */
+    public static final class Builder {
+        private int mRssiThreshold;
+        private final Set<byte[]> mCertificates;
+        private final Set<Integer> mPresenceIdentities;
+        private final Set<Integer> mPresenceActions;
+        private final Bundle mExtendedProperties;
+
+        public Builder() {
+            mRssiThreshold = -100;
+            mCertificates = new ArraySet<>();
+            mPresenceIdentities = new ArraySet<>();
+            mPresenceActions = new ArraySet<>();
+            mExtendedProperties = new Bundle();
+        }
+
+        /**
+         * Sets the rssi threshold for the scan request.
+         */
+        @NonNull
+        public Builder setRssiThreshold(int rssiThreshold) {
+            mRssiThreshold = rssiThreshold;
+            return this;
+        }
+
+        /**
+         * Adds a list of certificates the scan filter is expected to match.
+         */
+
+        @NonNull
+        public Builder addCertificate(@NonNull byte[] certificate) {
+            mCertificates.add(certificate);
+            return this;
+        }
+
+        /**
+         * Adds a presence identity for filtering.
+         */
+        @NonNull
+        public Builder addPresenceIdentity(int identity) {
+            mPresenceIdentities.add(identity);
+            return this;
+        }
+
+        /**
+         * Adds a presence action for filtering.
+         */
+        @NonNull
+        public Builder addPresenceAction(int action) {
+            mPresenceActions.add(action);
+            return this;
+        }
+
+        /**
+         * Add an extended property for scan filtering.
+         */
+        @NonNull
+        public Builder addExtendedProperty(@NonNull String key, @Nullable String value) {
+            mExtendedProperties.putCharSequence(key, value);
+            return this;
+        }
+
+        /**
+         * Builds the scan filter.
+         */
+        @NonNull
+        public PresenceScanFilter build() {
+            Preconditions.checkState(!mCertificates.isEmpty(), "certificates cannot be empty");
+            return new PresenceScanFilter(mRssiThreshold, new ArrayList<>(mCertificates),
+                    new ArrayList<>(mPresenceIdentities),
+                    new ArrayList<>(mPresenceActions),
+                    mExtendedProperties);
+        }
+    }
+}
diff --git a/nearby/framework/java/android/nearby/ScanFilter.java b/nearby/framework/java/android/nearby/ScanFilter.java
new file mode 100644
index 0000000..0b2a754
--- /dev/null
+++ b/nearby/framework/java/android/nearby/ScanFilter.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nearby;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Filter for scanning a nearby device.
+ *
+ * @hide
+ */
+@SuppressLint("ParcelNotFinal")  // ScanFilter constructor is not public
+public abstract class ScanFilter implements Parcelable {
+    public static final @NonNull Creator<ScanFilter> CREATOR = new Creator<ScanFilter>() {
+        @Override
+        public ScanFilter createFromParcel(Parcel in) {
+            int type = in.readInt();
+            switch (type) {
+                case ScanRequest.SCAN_TYPE_NEARBY_PRESENCE:
+                    return PresenceScanFilter.createFromParcelBody(in);
+                default:
+                    throw new IllegalStateException(
+                            "Unexpected scan type (value " + type + ") in parcel.");
+            }
+        }
+
+        @Override
+        public ScanFilter[] newArray(int size) {
+            return new ScanFilter[size];
+        }
+    };
+
+    private final @ScanRequest.ScanType int mType;
+    private final int mRssiThreshold;
+
+    /**
+     * Constructs a Scan Filter.
+     *
+     * @hide
+     */
+    ScanFilter(@ScanRequest.ScanType int type, int rssiThreshold) {
+        mType = type;
+        mRssiThreshold = rssiThreshold;
+    }
+
+    /**
+     * Constructs a Scan Filter.
+     *
+     * @hide
+     */
+    ScanFilter(@ScanRequest.ScanType int type, Parcel in) {
+        mType = type;
+        mRssiThreshold = in.readInt();
+    }
+
+    /**
+     * Returns the type of this scan filter.
+     */
+    public @ScanRequest.ScanType int getType() {
+        return mType;
+    }
+
+    /**
+     * Minimum RSSI of the received scan result.
+     */
+    public int getRssiThreshold() {
+        return mRssiThreshold;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mRssiThreshold);
+    }
+
+    /**
+     * No special parcel contents.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+}
diff --git a/nearby/framework/java/android/nearby/ScanRequest.java b/nearby/framework/java/android/nearby/ScanRequest.java
index 737f574..9180d5e 100644
--- a/nearby/framework/java/android/nearby/ScanRequest.java
+++ b/nearby/framework/java/android/nearby/ScanRequest.java
@@ -30,6 +30,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -48,6 +50,7 @@
     public static final int SCAN_TYPE_NEARBY_PRESENCE = 3;
     /** Scan type for scanning devices using exposure notification protocol. */
     public static final int SCAN_TYPE_EXPOSURE_NOTIFICATION = 4;
+
     /** Scan mode uses highest duty cycle. */
     public static final int SCAN_MODE_LOW_LATENCY = 2;
     /** Scan in balanced power mode.
@@ -73,7 +76,9 @@
                     /* scanType= */ in.readInt(),
                     /* scanMode= */ in.readInt(),
                     /* enableBle= */ in.readBoolean(),
-                    /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
+                    /* workSource= */ in.readTypedObject(WorkSource.CREATOR),
+                    /* scanFilters= */
+                    in.readArrayList(ScanFilter.class.getClassLoader(), ScanFilter.class));
         }
 
         @Override
@@ -81,17 +86,20 @@
             return new ScanRequest[size];
         }
     };
+
     private final @ScanType int mScanType;
     private final @ScanMode int mScanMode;
     private final boolean mEnableBle;
     private final @NonNull WorkSource mWorkSource;
+    private final List<ScanFilter> mScanFilters;
 
     private ScanRequest(@ScanType int scanType, @ScanMode int scanMode, boolean enableBle,
-            @NonNull WorkSource workSource) {
+            @NonNull WorkSource workSource, List<ScanFilter> scanFilters) {
         mScanType = scanType;
         mScanMode = scanMode;
         mEnableBle = enableBle;
         mWorkSource = workSource;
+        mScanFilters = scanFilters;
     }
 
     /**
@@ -157,6 +165,16 @@
     }
 
     /**
+     * Returns Scan Filters for this request.
+     *
+     * @hide
+     */
+    @NonNull
+    public List<ScanFilter> getScanFilters() {
+        return mScanFilters;
+    }
+
+    /**
      * Returns the work source used for power attribution of this request.
      *
      * @hide
@@ -186,6 +204,7 @@
         stringBuilder.append(", scanMode=").append(scanModeToString(mScanMode));
         stringBuilder.append(", enableBle=").append(mEnableBle);
         stringBuilder.append(", workSource=").append(mWorkSource);
+        stringBuilder.append(", scanFilters=").append(mScanFilters);
         stringBuilder.append("]");
         return stringBuilder.toString();
     }
@@ -196,6 +215,7 @@
         dest.writeInt(mScanMode);
         dest.writeBoolean(mEnableBle);
         dest.writeTypedObject(mWorkSource, /* parcelableFlags= */0);
+        dest.writeTypedList(mScanFilters);
     }
 
     @Override
@@ -237,12 +257,14 @@
 
         private boolean mEnableBle;
         private WorkSource mWorkSource;
+        private List<ScanFilter> mScanFilters;
 
         /** Creates a new Builder with the given scan type. */
         public Builder() {
             mScanType = INVALID_SCAN_TYPE;
             mEnableBle = true;
             mWorkSource = new WorkSource();
+            mScanFilters = new ArrayList<>();
         }
 
         /**
@@ -304,6 +326,24 @@
         }
 
         /**
+         * Adds a scan filter to the request. Client can call this method multiple times to add
+         * more than one scan filter. Scan results that match any of these scan filters will
+         * be returned.
+         *
+         * <p>On devices with hardware support, scan filters can significantly improve the battery
+         * usage of Nearby scans.
+         *
+         * @param scanFilter Filter for scanning the request.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder addScanFilter(@NonNull ScanFilter scanFilter) {
+            mScanFilters.add(scanFilter);
+            return this;
+        }
+
+        /**
          * Builds a scan request from this builder.
          *
          * @return a new nearby scan request.
@@ -318,7 +358,7 @@
             Preconditions.checkState(isValidScanMode(mScanMode),
                     "invalid scan mode : " + mScanMode
                             + ", scan mode must be one of ScanMode#SCAN_MODE_");
-            return new ScanRequest(mScanType, mScanMode, mEnableBle, mWorkSource);
+            return new ScanRequest(mScanType, mScanMode, mEnableBle, mWorkSource, mScanFilters);
         }
     }
 }
diff --git a/nearby/service/java/com/android/server/nearby/common/bloomfilter/BloomFilter.java b/nearby/service/java/com/android/server/nearby/common/bloomfilter/BloomFilter.java
new file mode 100644
index 0000000..6d4275f
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/common/bloomfilter/BloomFilter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bloomfilter;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.primitives.UnsignedInts;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.BitSet;
+
+/**
+ * A bloom filter that gives access to the underlying BitSet.
+ */
+public class BloomFilter {
+    private static final Charset CHARSET = UTF_8;
+
+    /**
+     * Receives a value and converts it into an array of ints that will be converted to indexes for
+     * the filter.
+     */
+    public interface Hasher {
+        /**
+         * Generate hash value.
+         */
+        int[] getHashes(byte[] value);
+    }
+
+    // The backing data for this bloom filter. As additions are made, they're OR'd until it
+    // eventually reaches 0xFF.
+    private final BitSet mBits;
+    // The max length of bits.
+    private final int mBitLength;
+    // The hasher to use for converting a value into an array of hashes.
+    private final Hasher mHasher;
+
+    public BloomFilter(byte[] bytes, Hasher hasher) {
+        this.mBits = BitSet.valueOf(bytes);
+        this.mBitLength = bytes.length * 8;
+        this.mHasher = hasher;
+    }
+
+    /**
+     * Return the bloom filter check bit set as byte array.
+     */
+    public byte[] asBytes() {
+        // BitSet.toByteArray() truncates all the unset bits after the last set bit (eg. [0,0,1,0]
+        // becomes [0,0,1]) so we re-add those bytes if needed with Arrays.copy().
+        byte[] b = mBits.toByteArray();
+        if (b.length == mBitLength / 8) {
+            return b;
+        }
+        return Arrays.copyOf(b, mBitLength / 8);
+    }
+
+    /**
+     * Add string value to bloom filter hash.
+     */
+    public void add(String s) {
+        add(s.getBytes(CHARSET));
+    }
+
+    /**
+     * Adds value to bloom filter hash.
+     */
+    public void add(byte[] value) {
+        int[] hashes = mHasher.getHashes(value);
+        for (int hash : hashes) {
+            mBits.set(UnsignedInts.remainder(hash, mBitLength));
+        }
+    }
+
+    /**
+     * Check if the string format has collision.
+     */
+    public boolean possiblyContains(String s) {
+        return possiblyContains(s.getBytes(CHARSET));
+    }
+
+    /**
+     * Checks if value after hash will have collision.
+     */
+    public boolean possiblyContains(byte[] value) {
+        int[] hashes = mHasher.getHashes(value);
+        for (int hash : hashes) {
+            if (!mBits.get(UnsignedInts.remainder(hash, mBitLength))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
+
diff --git a/nearby/service/java/com/android/server/nearby/common/bloomfilter/FastPairBloomFilterHasher.java b/nearby/service/java/com/android/server/nearby/common/bloomfilter/FastPairBloomFilterHasher.java
new file mode 100644
index 0000000..0ccee97
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/common/bloomfilter/FastPairBloomFilterHasher.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bloomfilter;
+
+import com.google.common.hash.Hashing;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Hasher which hashes a value using SHA-256 and splits it into parts, each of which can be
+ * converted to an index.
+ */
+public class FastPairBloomFilterHasher implements BloomFilter.Hasher {
+
+    private static final int NUM_INDEXES = 8;
+
+    @Override
+    public int[] getHashes(byte[] value) {
+        byte[] hash = Hashing.sha256().hashBytes(value).asBytes();
+        ByteBuffer buffer = ByteBuffer.wrap(hash);
+        int[] hashes = new int[NUM_INDEXES];
+        for (int i = 0; i < NUM_INDEXES; i++) {
+            hashes[i] = buffer.getInt();
+        }
+        return hashes;
+    }
+}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
index 6166052..672d785 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
@@ -16,11 +16,17 @@
 
 package com.android.server.nearby.fastpair;
 
+import static com.google.common.primitives.Bytes.concat;
+
+import android.accounts.Account;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.nearby.FastPairDevice;
 import android.nearby.NearbyDevice;
 import android.util.Log;
 
+import com.android.server.nearby.common.bloomfilter.BloomFilter;
+import com.android.server.nearby.common.bloomfilter.FastPairBloomFilterHasher;
 import com.android.server.nearby.common.locator.Locator;
 import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
 import com.android.server.nearby.provider.FastPairDataProvider;
@@ -29,7 +35,10 @@
 
 import com.google.protobuf.ByteString;
 
+import java.util.List;
+
 import service.proto.Cache;
+import service.proto.Data;
 import service.proto.Rpcs;
 
 /**
@@ -38,6 +47,7 @@
 public class FastPairAdvHandler {
     Context mContext;
     String mBleAddress;
+    private static final String TAG = "FastPairAdvHandler";
 
     /** The types about how the bloomfilter is processed. */
     public enum ProcessBloomFilterType {
@@ -69,16 +79,60 @@
             Log.d("FastPairService",
                     "On discovery model id" + Hex.bytesToStringLowercase(model));
             // Use api to get anti spoofing key from model id.
-            Rpcs.GetObservedDeviceResponse response =
-                    FastPairDataProvider.getInstance().loadFastPairDeviceMetadata(model);
-            ByteString publicKey = response.getDevice().getAntiSpoofingKeyPair().getPublicKey();
-            Locator.get(mContext, FastPairHalfSheetManager.class).showHalfSheet(
-                    Cache.ScanFastPairStoreItem.newBuilder().setAddress(mBleAddress)
-                            .setAntiSpoofingPublicKey(publicKey)
-                            .build());
-        } else {
-            // Start to process bloomfilter
+            try {
+                Rpcs.GetObservedDeviceResponse response =
+                        FastPairDataProvider.getInstance()
+                                .loadFastPairAntispoofkeyDeviceMetadata(model);
+                ByteString publicKey = response.getDevice().getAntiSpoofingKeyPair().getPublicKey();
+                Locator.get(mContext, FastPairHalfSheetManager.class).showHalfSheet(
+                        Cache.ScanFastPairStoreItem.newBuilder().setAddress(mBleAddress)
+                                .setAntiSpoofingPublicKey(publicKey)
+                                .build());
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "OEM does not construct fast pair data proxy correctly");
+            }
 
+        } else {
+            // Start to process bloom filter
+            List<Account> accountList =
+                    FastPairDataProvider.getInstance().loadFastPairEligibleAccounts();
+            byte[] bloomFilterByteArray = FastPairDecoder.getBloomFilter(fastPairDevice.getData());
+            byte[] bloomFilterSalt = FastPairDecoder.getBloomFilterSalt(fastPairDevice.getData());
+            for (Account account : accountList) {
+                try {
+                    List<Data.FastPairDeviceWithAccountKey> listDevices =
+                            FastPairDataProvider.getInstance().loadFastPairDevicesWithAccountKey(
+                                    account);
+                    Data.FastPairDeviceWithAccountKey recognizedDevice =
+                            findRecognizedDevice(listDevices,
+                                    new BloomFilter(bloomFilterByteArray,
+                                            new FastPairBloomFilterHasher()), bloomFilterSalt);
+                    if (recognizedDevice != null) {
+                        Log.d(TAG, "find matched device show notification to remind user to pair");
+                        return;
+                    }
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "OEM does not construct fast pair data proxy correctly");
+                }
+
+            }
         }
     }
+
+    /**
+     * Checks the bloom filter to see if any of the devices are recognized and should have a
+     * notification displayed for them. A device is recognized if the account key + salt combination
+     * is inside the bloom filter.
+     */
+    @Nullable
+    static Data.FastPairDeviceWithAccountKey findRecognizedDevice(
+            List<Data.FastPairDeviceWithAccountKey> devices, BloomFilter bloomFilter, byte[] salt) {
+        for (Data.FastPairDeviceWithAccountKey device : devices) {
+            byte[] rotatedKey = concat(device.getAccountKey().toByteArray(), salt);
+            if (bloomFilter.possiblyContains(rotatedKey)) {
+                return device;
+            }
+        }
+        return null;
+    }
 }
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
index 6efaae7..cf8cd62 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -63,6 +63,7 @@
  * for pairing control.
  */
 public class FastPairController {
+    private static final String TAG = "FastPairController";
     private final Context mContext;
     private final EventLoop mEventLoop;
     private final FastPairCacheManager mFastPairCacheManager;
@@ -132,7 +133,7 @@
                                 item = new DiscoveryItem(mContext,
                                         Cache.StoredDiscoveryItem.parseFrom(discoveryItem));
                             } catch (InvalidProtocolBufferException e) {
-                                Log.w("FastPairController",
+                                Log.w(TAG,
                                         "Error parsing serialized discovery item with size "
                                                 + discoveryItem.length);
                             }
@@ -140,8 +141,7 @@
 
 
                         if (item == null || TextUtils.isEmpty(item.getMacAddress())) {
-                            Log.w("FastPairController",
-                                    "Invalid DiscoveryItem, ignore pairing");
+                            Log.w(TAG, "Invalid DiscoveryItem, ignore pairing");
                             return;
                         }
 
@@ -150,7 +150,7 @@
                         // bug - b/31459521).
                         if (item.getState() != Cache.StoredDiscoveryItem.State.STATE_ENABLED
                                 && !isRetroactivePair) {
-                            Log.d("FastPairController", "Incorrect state, ignore pairing");
+                            Log.d(TAG, "Incorrect state, ignore pairing");
                             return;
                         }
 
@@ -193,10 +193,10 @@
             @Nullable String companionApp,
             PairingProgressHandlerBase pairingProgressHandlerBase) {
         if (mIsFastPairing) {
-            Log.d("FastPairController", "FastPair: fastpairing, skip pair request");
+            Log.d(TAG, "FastPair: fastpairing, skip pair request");
             return;
         }
-        Log.d("FastPairController", "FastPair: start pair");
+        Log.d(TAG, "FastPair: start pair");
 
         // Hide all "tap to pair" notifications until after the flow completes.
         mEventLoop.removeRunnable(mReEnableAllDeviceItemsRunnable);
@@ -243,7 +243,7 @@
         if (!mShouldUpload) {
             return;
         }
-        Log.d("FastPairController", "upload device to footprint");
+        Log.d(TAG, "upload device to footprint");
         FastPairManager.processBackgroundTask(() -> {
             Cache.StoredDiscoveryItem storedDiscoveryItem =
                     prepareStoredDiscoveryItemForFootprints(discoveryItem);
@@ -257,9 +257,13 @@
                         new FastPairUploadInfo(storedDiscoveryItem, ByteString.copyFrom(accountKey),
                                 ByteString.copyFrom(hashValue));
                 // account data place holder here
-                FastPairDataProvider.getInstance().optIn(new Account("empty", "empty"));
-                FastPairDataProvider.getInstance().upload(
-                        new Account("empty", "empty"), uploadInfo);
+                try {
+                    FastPairDataProvider.getInstance().optIn(new Account("empty", "empty"));
+                    FastPairDataProvider.getInstance().upload(
+                            new Account("empty", "empty"), uploadInfo);
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "OEM does not construct fast pair data proxy correctly");
+                }
 
             }
 
diff --git a/nearby/service/java/com/android/server/nearby/provider/FastPairDataProvider.java b/nearby/service/java/com/android/server/nearby/provider/FastPairDataProvider.java
index 5c57ddf..f8c16a1 100644
--- a/nearby/service/java/com/android/server/nearby/provider/FastPairDataProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/FastPairDataProvider.java
@@ -20,15 +20,26 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.nearby.FastPairDataProviderBase;
+import android.nearby.aidl.FastPairAccountDevicesMetadataRequestParcel;
+import android.nearby.aidl.FastPairAntispoofkeyDeviceMetadataRequestParcel;
+import android.nearby.aidl.FastPairEligibleAccountsRequestParcel;
+import android.nearby.aidl.FastPairManageAccountDeviceRequestParcel;
+import android.nearby.aidl.FastPairManageAccountRequestParcel;
 import android.util.Log;
 
 import androidx.annotation.WorkerThread;
 
+import com.android.server.nearby.common.bloomfilter.BloomFilter;
 import com.android.server.nearby.fastpair.footprint.FastPairUploadInfo;
 
+import java.util.List;
+
+import service.proto.Data;
 import service.proto.Rpcs;
 
-/** FastPairDataProvider is a singleton that implements APIs to get FastPair data. */
+/**
+ * FastPairDataProvider is a singleton that implements APIs to get FastPair data.
+ */
 public class FastPairDataProvider {
 
     private static final String TAG = "FastPairDataProvider";
@@ -37,9 +48,10 @@
 
     private ProxyFastPairDataProvider mProxyFastPairDataProvider;
 
-    /** Initializes FastPairDataProvider singleton. */
+    /**
+     * Initializes FastPairDataProvider singleton.
+     */
     public static synchronized FastPairDataProvider init(Context context) {
-
         if (sInstance == null) {
             sInstance = new FastPairDataProvider(context);
         }
@@ -66,28 +78,97 @@
         }
     }
 
-    /** loadFastPairDeviceMetadata. */
+    /**
+     * Loads FastPairAntispoofkeyDeviceMetadata.
+     *
+     * @throws IllegalStateException If ProxyFastPairDataProvider is not available.
+     */
     @WorkerThread
     @Nullable
-    public Rpcs.GetObservedDeviceResponse loadFastPairDeviceMetadata(byte[] modelId) {
+    public Rpcs.GetObservedDeviceResponse loadFastPairAntispoofkeyDeviceMetadata(byte[] modelId) {
         if (mProxyFastPairDataProvider != null) {
-            return mProxyFastPairDataProvider.loadFastPairDeviceMetadata(modelId);
+            FastPairAntispoofkeyDeviceMetadataRequestParcel requestParcel =
+                    new FastPairAntispoofkeyDeviceMetadataRequestParcel();
+            requestParcel.modelId = modelId;
+            return Utils.convertFastPairAntispoofkeyDeviceMetadataToGetObservedDeviceResponse(
+                    mProxyFastPairDataProvider
+                            .loadFastPairAntispoofkeyDeviceMetadata(requestParcel));
         }
         throw new IllegalStateException("No ProxyFastPairDataProvider yet constructed");
     }
 
     /**
-     * opt in default account to fast pair
+     * Enrolls an account to Fast Pair.
+     *
+     * @throws IllegalStateException If ProxyFastPairDataProvider is not available.
      */
     public void optIn(Account account) {
-
+        if (mProxyFastPairDataProvider != null) {
+            FastPairManageAccountRequestParcel requestParcel =
+                    new FastPairManageAccountRequestParcel();
+            requestParcel.account = account;
+            requestParcel.requestType = FastPairDataProviderBase.MANAGE_REQUEST_ADD;
+            mProxyFastPairDataProvider.manageFastPairAccount(requestParcel);
+        }
+        throw new IllegalStateException("No ProxyFastPairDataProvider yet constructed");
     }
 
     /**
-     * Upload the device to the footprint
+     * Uploads the device info to Fast Pair account.
+     *
+     * @throws IllegalStateException If ProxyFastPairDataProvider is not available.
      */
     public void upload(Account account, FastPairUploadInfo uploadInfo) {
-
+        if (mProxyFastPairDataProvider != null) {
+            FastPairManageAccountDeviceRequestParcel requestParcel =
+                    new FastPairManageAccountDeviceRequestParcel();
+            requestParcel.account = account;
+            requestParcel.requestType = FastPairDataProviderBase.MANAGE_REQUEST_ADD;
+            requestParcel.accountKeyDeviceMetadata =
+                    Utils.convertFastPairUploadInfoToFastPairAccountKeyDeviceMetadata(
+                            uploadInfo);
+            mProxyFastPairDataProvider.manageFastPairAccountDevice(requestParcel);
+        }
+        throw new IllegalStateException("No ProxyFastPairDataProvider yet constructed");
     }
 
+    /**
+     * Get recognized device from bloom filter.
+     */
+    public Data.FastPairDeviceWithAccountKey getRecognizedDevice(BloomFilter bloomFilter,
+            byte[] salt) {
+        return Data.FastPairDeviceWithAccountKey.newBuilder().build();
+    }
+
+    /**
+     * Loads FastPair devices for a given account.
+     *
+     * @throws IllegalStateException If ProxyFastPairDataProvider is not available.
+     */
+    public List<Data.FastPairDeviceWithAccountKey> loadFastPairDevicesWithAccountKey(
+            Account account) {
+        if (mProxyFastPairDataProvider != null) {
+            FastPairAccountDevicesMetadataRequestParcel requestParcel =
+                    new FastPairAccountDevicesMetadataRequestParcel();
+            requestParcel.account = account;
+            return Utils.convertFastPairAccountKeyDevicesMetadataToFastPairDevicesWithAccountKey(
+                    mProxyFastPairDataProvider.loadFastPairAccountDevicesMetadata(requestParcel));
+        }
+        throw new IllegalStateException("No ProxyFastPairDataProvider yet constructed");
+    }
+
+    /**
+     * Loads FastPair Eligible Accounts.
+     *
+     * @throws IllegalStateException If ProxyFastPairDataProvider is not available.
+     */
+    public List<Account> loadFastPairEligibleAccounts() {
+        if (mProxyFastPairDataProvider != null) {
+            FastPairEligibleAccountsRequestParcel requestParcel =
+                    new FastPairEligibleAccountsRequestParcel();
+            return Utils.convertFastPairEligibleAccountsToAccountList(
+                    mProxyFastPairDataProvider.loadFastPairEligibleAccounts(requestParcel));
+        }
+        throw new IllegalStateException("No ProxyFastPairDataProvider yet constructed");
+    }
 }
diff --git a/nearby/service/java/com/android/server/nearby/provider/ProxyFastPairDataProvider.java b/nearby/service/java/com/android/server/nearby/provider/ProxyFastPairDataProvider.java
index 7bd53f4..36b4478 100644
--- a/nearby/service/java/com/android/server/nearby/provider/ProxyFastPairDataProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/ProxyFastPairDataProvider.java
@@ -18,10 +18,20 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.nearby.aidl.FastPairAccountDevicesMetadataRequestParcel;
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
 import android.nearby.aidl.FastPairAntispoofkeyDeviceMetadataParcel;
 import android.nearby.aidl.FastPairAntispoofkeyDeviceMetadataRequestParcel;
+import android.nearby.aidl.FastPairEligibleAccountParcel;
+import android.nearby.aidl.FastPairEligibleAccountsRequestParcel;
+import android.nearby.aidl.FastPairManageAccountDeviceRequestParcel;
+import android.nearby.aidl.FastPairManageAccountRequestParcel;
+import android.nearby.aidl.IFastPairAccountDevicesMetadataCallback;
 import android.nearby.aidl.IFastPairAntispoofkeyDeviceMetadataCallback;
 import android.nearby.aidl.IFastPairDataProvider;
+import android.nearby.aidl.IFastPairEligibleAccountsCallback;
+import android.nearby.aidl.IFastPairManageAccountCallback;
+import android.nearby.aidl.IFastPairManageAccountDeviceCallback;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -36,13 +46,13 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
-import service.proto.Rpcs;
-
 /**
  * Proxy for IFastPairDataProvider implementations.
  */
 public class ProxyFastPairDataProvider implements ServiceListener<BoundServiceInfo> {
 
+    private static final int TIME_OUT_MILLIS = 10000;
+
     /**
      * Creates and registers this proxy. If no suitable service is available for the proxy, returns
      * null.
@@ -71,7 +81,9 @@
         return mServiceMonitor.checkServiceResolves();
     }
 
-    /** User service watch to connect to actually services implemented by OEMs. */
+    /**
+     * User service watch to connect to actually services implemented by OEMs.
+     */
     public void register() {
         mServiceMonitor.register();
     }
@@ -88,29 +100,151 @@
     public void onUnbind() {
     }
 
-    /** Invoke loadFastPairDeviceMetadata. */
+    /**
+     * Invokes system api loadFastPairEligibleAccounts.
+     *
+     * @return an array of acccounts and their opt in status.
+     */
     @WorkerThread
     @Nullable
-    Rpcs.GetObservedDeviceResponse loadFastPairDeviceMetadata(byte[] modelId) {
+    public FastPairEligibleAccountParcel[] loadFastPairEligibleAccounts(
+            FastPairEligibleAccountsRequestParcel requestParcel) {
         final CountDownLatch waitForCompletionLatch = new CountDownLatch(1);
-        final AtomicReference<Rpcs.GetObservedDeviceResponse> response = new AtomicReference<>();
+        final AtomicReference<FastPairEligibleAccountParcel[]> response = new AtomicReference<>();
         mServiceMonitor.runOnBinder(new ServiceMonitor.BinderOperation() {
             @Override
             public void run(IBinder binder) throws RemoteException {
                 IFastPairDataProvider provider = IFastPairDataProvider.Stub.asInterface(binder);
-                FastPairAntispoofkeyDeviceMetadataRequestParcel requestParcel =
-                        new FastPairAntispoofkeyDeviceMetadataRequestParcel();
-                requestParcel.modelId = modelId;
+                IFastPairEligibleAccountsCallback callback =
+                        new IFastPairEligibleAccountsCallback.Stub() {
+                            public void onFastPairEligibleAccountsReceived(
+                                    FastPairEligibleAccountParcel[] accountParcels) {
+                                response.set(accountParcels);
+                                waitForCompletionLatch.countDown();
+                            }
+
+                            public void onError(int code, String message) {
+                                waitForCompletionLatch.countDown();
+                            }
+                        };
+                provider.loadFastPairEligibleAccounts(requestParcel, callback);
+            }
+
+            @Override
+            public void onError() {
+                waitForCompletionLatch.countDown();
+            }
+        });
+        try {
+            waitForCompletionLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // skip.
+        }
+        return response.get();
+    }
+
+    /**
+     * Invokes system api manageFastPairAccount to opt in account, or opt out account.
+     */
+    @WorkerThread
+    public void manageFastPairAccount(FastPairManageAccountRequestParcel requestParcel) {
+        final CountDownLatch waitForCompletionLatch = new CountDownLatch(1);
+        mServiceMonitor.runOnBinder(new ServiceMonitor.BinderOperation() {
+            @Override
+            public void run(IBinder binder) throws RemoteException {
+                IFastPairDataProvider provider = IFastPairDataProvider.Stub.asInterface(binder);
+                IFastPairManageAccountCallback callback =
+                        new IFastPairManageAccountCallback.Stub() {
+                            public void onSuccess() {
+                                waitForCompletionLatch.countDown();
+                            }
+
+                            public void onError(int code, String message) {
+                                waitForCompletionLatch.countDown();
+                            }
+                        };
+                provider.manageFastPairAccount(requestParcel, callback);
+            }
+
+            @Override
+            public void onError() {
+                waitForCompletionLatch.countDown();
+            }
+        });
+        try {
+            waitForCompletionLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // skip.
+        }
+        return;
+    }
+
+    /**
+     * Invokes system api manageFastPairAccountDevice to add or remove a device from a Fast Pair
+     * account.
+     */
+    @WorkerThread
+    public void manageFastPairAccountDevice(
+            FastPairManageAccountDeviceRequestParcel requestParcel) {
+        final CountDownLatch waitForCompletionLatch = new CountDownLatch(1);
+        mServiceMonitor.runOnBinder(new ServiceMonitor.BinderOperation() {
+            @Override
+            public void run(IBinder binder) throws RemoteException {
+                IFastPairDataProvider provider = IFastPairDataProvider.Stub.asInterface(binder);
+                IFastPairManageAccountDeviceCallback callback =
+                        new IFastPairManageAccountDeviceCallback.Stub() {
+                            public void onSuccess() {
+                                waitForCompletionLatch.countDown();
+                            }
+
+                            public void onError(int code, String message) {
+                                waitForCompletionLatch.countDown();
+                            }
+                        };
+                provider.manageFastPairAccountDevice(requestParcel, callback);
+            }
+
+            @Override
+            public void onError() {
+                waitForCompletionLatch.countDown();
+            }
+        });
+        try {
+            waitForCompletionLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // skip.
+        }
+        return;
+    }
+
+    /**
+     * Invokes system api loadFastPairAntispoofkeyDeviceMetadata.
+     *
+     * @return the Fast Pair AntispoofKeyDeviceMetadata of a given device.
+     */
+    @WorkerThread
+    @Nullable
+    FastPairAntispoofkeyDeviceMetadataParcel loadFastPairAntispoofkeyDeviceMetadata(
+            FastPairAntispoofkeyDeviceMetadataRequestParcel requestParcel) {
+        final CountDownLatch waitForCompletionLatch = new CountDownLatch(1);
+        final AtomicReference<FastPairAntispoofkeyDeviceMetadataParcel> response =
+                new AtomicReference<>();
+        mServiceMonitor.runOnBinder(new ServiceMonitor.BinderOperation() {
+            @Override
+            public void run(IBinder binder) throws RemoteException {
+                IFastPairDataProvider provider = IFastPairDataProvider.Stub.asInterface(binder);
                 IFastPairAntispoofkeyDeviceMetadataCallback callback =
                         new IFastPairAntispoofkeyDeviceMetadataCallback.Stub() {
-                    public void onFastPairAntispoofkeyDeviceMetadataReceived(
-                            FastPairAntispoofkeyDeviceMetadataParcel metadata) {
-                        response.set(Utils.convert(metadata));
-                        waitForCompletionLatch.countDown();
-                    }
-                    public void onError(int code, String message) {
-                    }
-                };
+                            public void onFastPairAntispoofkeyDeviceMetadataReceived(
+                                    FastPairAntispoofkeyDeviceMetadataParcel metadata) {
+                                response.set(metadata);
+                                waitForCompletionLatch.countDown();
+                            }
+
+                            public void onError(int code, String message) {
+                                waitForCompletionLatch.countDown();
+                            }
+                        };
                 provider.loadFastPairAntispoofkeyDeviceMetadata(requestParcel, callback);
             }
 
@@ -120,7 +254,51 @@
             }
         });
         try {
-            waitForCompletionLatch.await(10000, TimeUnit.MILLISECONDS);
+            waitForCompletionLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // skip.
+        }
+        return response.get();
+    }
+
+    /**
+     * Invokes loadFastPairAccountDevicesMetadata.
+     *
+     * @return the metadata of Fast Pair devices that are associated with a given account.
+     */
+    @WorkerThread
+    @Nullable
+    FastPairAccountKeyDeviceMetadataParcel[] loadFastPairAccountDevicesMetadata(
+            FastPairAccountDevicesMetadataRequestParcel requestParcel) {
+        final CountDownLatch waitForCompletionLatch = new CountDownLatch(1);
+        final AtomicReference<FastPairAccountKeyDeviceMetadataParcel[]> response =
+                new AtomicReference<>();
+        mServiceMonitor.runOnBinder(new ServiceMonitor.BinderOperation() {
+            @Override
+            public void run(IBinder binder) throws RemoteException {
+                IFastPairDataProvider provider = IFastPairDataProvider.Stub.asInterface(binder);
+                IFastPairAccountDevicesMetadataCallback callback =
+                        new IFastPairAccountDevicesMetadataCallback.Stub() {
+                            public void onFastPairAccountDevicesMetadataReceived(
+                                    FastPairAccountKeyDeviceMetadataParcel[] metadatas) {
+                                response.set(metadatas);
+                                waitForCompletionLatch.countDown();
+                            }
+
+                            public void onError(int code, String message) {
+                                waitForCompletionLatch.countDown();
+                            }
+                        };
+                provider.loadFastPairAccountDevicesMetadata(requestParcel, callback);
+            }
+
+            @Override
+            public void onError() {
+                waitForCompletionLatch.countDown();
+            }
+        });
+        try {
+            waitForCompletionLatch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
             // skip.
         }
diff --git a/nearby/service/java/com/android/server/nearby/provider/Utils.java b/nearby/service/java/com/android/server/nearby/provider/Utils.java
index ca0a390..a340b04 100644
--- a/nearby/service/java/com/android/server/nearby/provider/Utils.java
+++ b/nearby/service/java/com/android/server/nearby/provider/Utils.java
@@ -16,80 +16,480 @@
 
 package com.android.server.nearby.provider;
 
+import android.accounts.Account;
+import android.annotation.Nullable;
+import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
 import android.nearby.aidl.FastPairAntispoofkeyDeviceMetadataParcel;
+import android.nearby.aidl.FastPairDeviceMetadataParcel;
+import android.nearby.aidl.FastPairDiscoveryItemParcel;
+import android.nearby.aidl.FastPairEligibleAccountParcel;
+
+import com.android.server.nearby.fastpair.footprint.FastPairUploadInfo;
 
 import com.google.protobuf.ByteString;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import service.proto.Cache;
+import service.proto.Data;
+import service.proto.FastPairString.FastPairStrings;
 import service.proto.Rpcs;
 
+/**
+ * Utility functions to convert between different data classes.
+ */
 class Utils {
 
-    static Rpcs.GetObservedDeviceResponse convert(
-            FastPairAntispoofkeyDeviceMetadataParcel metadata) {
+    static List<Data.FastPairDeviceWithAccountKey>
+            convertFastPairAccountKeyDevicesMetadataToFastPairDevicesWithAccountKey(
+                    @Nullable FastPairAccountKeyDeviceMetadataParcel[] metadataParcels) {
+        if (metadataParcels == null) {
+            return new ArrayList<Data.FastPairDeviceWithAccountKey>(0);
+        }
+
+        List<Data.FastPairDeviceWithAccountKey> fpDeviceList =
+                new ArrayList<>(metadataParcels.length);
+        for (FastPairAccountKeyDeviceMetadataParcel metadataParcel : metadataParcels) {
+            Data.FastPairDeviceWithAccountKey.Builder fpDeviceBuilder =
+                    Data.FastPairDeviceWithAccountKey.newBuilder();
+            if (metadataParcel.accountKey != null) {
+                fpDeviceBuilder.setAccountKey(ByteString.copyFrom(metadataParcel.accountKey));
+            }
+            if (metadataParcel.sha256AccountKeyPublicAddress != null) {
+                fpDeviceBuilder.setSha256AccountKeyPublicAddress(
+                        ByteString.copyFrom(metadataParcel.sha256AccountKeyPublicAddress));
+            }
+
+            Cache.StoredDiscoveryItem.Builder storedDiscoveryItemBuilder =
+                    Cache.StoredDiscoveryItem.newBuilder();
+
+            if (metadataParcel.discoveryItem != null) {
+                if (metadataParcel.discoveryItem.actionUrl != null) {
+                    storedDiscoveryItemBuilder.setActionUrl(metadataParcel.discoveryItem.actionUrl);
+                }
+                storedDiscoveryItemBuilder.setActionUrlType(
+                        Cache.ResolvedUrlType.forNumber(
+                                metadataParcel.discoveryItem.actionUrlType));
+                if (metadataParcel.discoveryItem.appName != null) {
+                    storedDiscoveryItemBuilder.setAppName(metadataParcel.discoveryItem.appName);
+                }
+                storedDiscoveryItemBuilder.setAttachmentType(
+                        Cache.DiscoveryAttachmentType.forNumber(
+                                metadataParcel.discoveryItem.attachmentType));
+                if (metadataParcel.discoveryItem.authenticationPublicKeySecp256r1 != null) {
+                    storedDiscoveryItemBuilder.setAuthenticationPublicKeySecp256R1(
+                            ByteString.copyFrom(
+                                    metadataParcel.discoveryItem.authenticationPublicKeySecp256r1));
+                }
+                if (metadataParcel.discoveryItem.bleRecordBytes != null) {
+                    storedDiscoveryItemBuilder.setBleRecordBytes(
+                            ByteString.copyFrom(metadataParcel.discoveryItem.bleRecordBytes));
+                }
+                storedDiscoveryItemBuilder.setDebugCategory(
+                        Cache.StoredDiscoveryItem.DebugMessageCategory.forNumber(
+                                metadataParcel.discoveryItem.debugCategory));
+                if (metadataParcel.discoveryItem.debugMessage != null) {
+                    storedDiscoveryItemBuilder.setDebugMessage(
+                            metadataParcel.discoveryItem.debugMessage);
+                }
+                if (metadataParcel.discoveryItem.description != null) {
+                    storedDiscoveryItemBuilder.setDescription(
+                            metadataParcel.discoveryItem.description);
+                }
+                if (metadataParcel.discoveryItem.deviceName != null) {
+                    storedDiscoveryItemBuilder.setDeviceName(
+                            metadataParcel.discoveryItem.deviceName);
+                }
+                if (metadataParcel.discoveryItem.displayUrl != null) {
+                    storedDiscoveryItemBuilder.setDisplayUrl(
+                            metadataParcel.discoveryItem.displayUrl);
+                }
+                if (metadataParcel.discoveryItem.entityId != null) {
+                    storedDiscoveryItemBuilder.setEntityId(
+                            metadataParcel.discoveryItem.entityId);
+                }
+                if (metadataParcel.discoveryItem.featureGraphicUrl != null) {
+                    storedDiscoveryItemBuilder.setFeatureGraphicUrl(
+                            metadataParcel.discoveryItem.featureGraphicUrl);
+                }
+                storedDiscoveryItemBuilder.setFirstObservationTimestampMillis(
+                        metadataParcel.discoveryItem.firstObservationTimestampMillis);
+                if (metadataParcel.discoveryItem.groupId != null) {
+                    storedDiscoveryItemBuilder.setGroupId(metadataParcel.discoveryItem.groupId);
+                }
+                if (metadataParcel.discoveryItem.iconFifeUrl != null) {
+                    storedDiscoveryItemBuilder.setIconFifeUrl(
+                            metadataParcel.discoveryItem.iconFifeUrl);
+                }
+                if (metadataParcel.discoveryItem.iconPng != null) {
+                    storedDiscoveryItemBuilder.setIconPng(
+                            ByteString.copyFrom(metadataParcel.discoveryItem.iconPng));
+                }
+                if (metadataParcel.discoveryItem.id != null) {
+                    storedDiscoveryItemBuilder.setId(metadataParcel.discoveryItem.id);
+                }
+                storedDiscoveryItemBuilder.setLastObservationTimestampMillis(
+                        metadataParcel.discoveryItem.lastObservationTimestampMillis);
+                storedDiscoveryItemBuilder.setLastUserExperience(
+                        Cache.StoredDiscoveryItem.ExperienceType.forNumber(
+                                metadataParcel.discoveryItem.lastUserExperience));
+                storedDiscoveryItemBuilder.setLostMillis(metadataParcel.discoveryItem.lostMillis);
+                if (metadataParcel.discoveryItem.macAddress != null) {
+                    storedDiscoveryItemBuilder.setMacAddress(
+                            metadataParcel.discoveryItem.macAddress);
+                }
+                if (metadataParcel.discoveryItem.packageName != null) {
+                    storedDiscoveryItemBuilder.setPackageName(
+                            metadataParcel.discoveryItem.packageName);
+                }
+                storedDiscoveryItemBuilder.setPendingAppInstallTimestampMillis(
+                        metadataParcel.discoveryItem.pendingAppInstallTimestampMillis);
+                storedDiscoveryItemBuilder.setRssi(metadataParcel.discoveryItem.rssi);
+                storedDiscoveryItemBuilder.setState(
+                        Cache.StoredDiscoveryItem.State.forNumber(
+                                metadataParcel.discoveryItem.state));
+                if (metadataParcel.discoveryItem.title != null) {
+                    storedDiscoveryItemBuilder.setTitle(metadataParcel.discoveryItem.title);
+                }
+                if (metadataParcel.discoveryItem.triggerId != null) {
+                    storedDiscoveryItemBuilder.setTriggerId(metadataParcel.discoveryItem.triggerId);
+                }
+                storedDiscoveryItemBuilder.setTxPower(metadataParcel.discoveryItem.txPower);
+                storedDiscoveryItemBuilder.setType(
+                        Cache.NearbyType.forNumber(metadataParcel.discoveryItem.type));
+            }
+            if (metadataParcel.metadata != null) {
+                FastPairStrings.Builder stringsBuilder = FastPairStrings.newBuilder();
+                if (metadataParcel.metadata.assistantSetupHalfSheet != null) {
+                    stringsBuilder.setAssistantHalfSheetDescription(
+                            metadataParcel.metadata.assistantSetupHalfSheet);
+                }
+                if (metadataParcel.metadata.assistantSetupNotification != null) {
+                    stringsBuilder.setAssistantNotificationDescription(
+                            metadataParcel.metadata.assistantSetupNotification);
+                }
+                if (metadataParcel.metadata.confirmPinDescription != null) {
+                    stringsBuilder.setConfirmPinDescription(
+                            metadataParcel.metadata.confirmPinDescription);
+                }
+                if (metadataParcel.metadata.confirmPinTitle != null) {
+                    stringsBuilder.setConfirmPinTitle(
+                            metadataParcel.metadata.confirmPinTitle);
+                }
+                if (metadataParcel.metadata.connectSuccessCompanionAppInstalled != null) {
+                    stringsBuilder.setPairingFinishedCompanionAppInstalled(
+                            metadataParcel.metadata.connectSuccessCompanionAppInstalled);
+                }
+                if (metadataParcel.metadata.connectSuccessCompanionAppNotInstalled != null) {
+                    stringsBuilder.setPairingFinishedCompanionAppNotInstalled(
+                            metadataParcel.metadata.connectSuccessCompanionAppNotInstalled);
+                }
+                if (metadataParcel.metadata.failConnectGoToSettingsDescription != null) {
+                    stringsBuilder.setPairingFailDescription(
+                            metadataParcel.metadata.failConnectGoToSettingsDescription);
+                }
+                if (metadataParcel.metadata.fastPairTvConnectDeviceNoAccountDescription != null) {
+                    stringsBuilder.setFastPairTvConnectDeviceNoAccountDescription(
+                            metadataParcel.metadata.fastPairTvConnectDeviceNoAccountDescription);
+                }
+                if (metadataParcel.metadata.initialNotificationDescription != null) {
+                    stringsBuilder.setTapToPairWithAccount(
+                            metadataParcel.metadata.initialNotificationDescription);
+                }
+                if (metadataParcel.metadata.initialNotificationDescriptionNoAccount != null) {
+                    stringsBuilder.setTapToPairWithoutAccount(
+                            metadataParcel.metadata.initialNotificationDescriptionNoAccount);
+                }
+                if (metadataParcel.metadata.initialPairingDescription != null) {
+                    stringsBuilder.setInitialPairingDescription(
+                            metadataParcel.metadata.initialPairingDescription);
+                }
+                if (metadataParcel.metadata.retroactivePairingDescription != null) {
+                    stringsBuilder.setRetroactivePairingDescription(
+                            metadataParcel.metadata.retroactivePairingDescription);
+                }
+                if (metadataParcel.metadata.subsequentPairingDescription != null) {
+                    stringsBuilder.setSubsequentPairingDescription(
+                            metadataParcel.metadata.subsequentPairingDescription);
+                }
+                if (metadataParcel.metadata.syncContactsDescription != null) {
+                    stringsBuilder.setSyncContactsDescription(
+                            metadataParcel.metadata.syncContactsDescription);
+                }
+                if (metadataParcel.metadata.syncContactsTitle != null) {
+                    stringsBuilder.setSyncContactsTitle(
+                            metadataParcel.metadata.syncContactsTitle);
+                }
+                if (metadataParcel.metadata.syncSmsDescription != null) {
+                    stringsBuilder.setSyncSmsDescription(
+                            metadataParcel.metadata.syncSmsDescription);
+                }
+                if (metadataParcel.metadata.syncSmsTitle != null) {
+                    stringsBuilder.setSyncSmsTitle(metadataParcel.metadata.syncSmsTitle);
+                }
+                if (metadataParcel.metadata.waitLaunchCompanionAppDescription != null) {
+                    stringsBuilder.setWaitAppLaunchDescription(
+                            metadataParcel.metadata.waitLaunchCompanionAppDescription);
+                }
+                storedDiscoveryItemBuilder.setFastPairStrings(stringsBuilder.build());
+
+                Cache.FastPairInformation.Builder fpInformationBuilder =
+                        Cache.FastPairInformation.newBuilder();
+                Rpcs.TrueWirelessHeadsetImages.Builder imagesBuilder =
+                        Rpcs.TrueWirelessHeadsetImages.newBuilder();
+                if (metadataParcel.metadata.trueWirelessImageUrlCase != null) {
+                    imagesBuilder.setCaseUrl(metadataParcel.metadata.trueWirelessImageUrlCase);
+                }
+                if (metadataParcel.metadata.trueWirelessImageUrlLeftBud != null) {
+                    imagesBuilder.setLeftBudUrl(
+                            metadataParcel.metadata.trueWirelessImageUrlLeftBud);
+                }
+                if (metadataParcel.metadata.trueWirelessImageUrlRightBud != null) {
+                    imagesBuilder.setRightBudUrl(
+                            metadataParcel.metadata.trueWirelessImageUrlRightBud);
+                }
+                fpInformationBuilder.setTrueWirelessImages(imagesBuilder.build());
+                fpInformationBuilder.setDeviceType(
+                        Rpcs.DeviceType.forNumber(metadataParcel.metadata.deviceType));
+
+                storedDiscoveryItemBuilder.setFastPairInformation(fpInformationBuilder.build());
+                storedDiscoveryItemBuilder.setTxPower(metadataParcel.metadata.bleTxPower);
+
+                if (metadataParcel.metadata.image != null) {
+                    storedDiscoveryItemBuilder.setIconPng(
+                            ByteString.copyFrom(metadataParcel.metadata.image));
+                }
+                if (metadataParcel.metadata.imageUrl != null) {
+                    storedDiscoveryItemBuilder.setIconFifeUrl(metadataParcel.metadata.imageUrl);
+                }
+                if (metadataParcel.metadata.intentUri != null) {
+                    storedDiscoveryItemBuilder.setActionUrl(metadataParcel.metadata.intentUri);
+                }
+            }
+            fpDeviceBuilder.setDiscoveryItem(storedDiscoveryItemBuilder.build());
+            fpDeviceList.add(fpDeviceBuilder.build());
+        }
+        return fpDeviceList;
+    }
+
+    static List<Account> convertFastPairEligibleAccountsToAccountList(
+            @Nullable FastPairEligibleAccountParcel[] accountParcels) {
+        if (accountParcels == null) {
+            return new ArrayList<Account>(0);
+        }
+        List<Account> accounts = new ArrayList<Account>(accountParcels.length);
+        for (FastPairEligibleAccountParcel parcel : accountParcels) {
+            accounts.add(parcel.account);
+        }
+        return accounts;
+    }
+
+    static @Nullable Rpcs.GetObservedDeviceResponse
+            convertFastPairAntispoofkeyDeviceMetadataToGetObservedDeviceResponse(
+                    @Nullable FastPairAntispoofkeyDeviceMetadataParcel metadata) {
+        if (metadata == null) {
+            return null;
+        }
         return Rpcs.GetObservedDeviceResponse.newBuilder()
-          .setDevice(Rpcs.Device.newBuilder()
-                  .setAntiSpoofingKeyPair(Rpcs.AntiSpoofingKeyPair.newBuilder()
-                          .setPublicKey(ByteString.copyFrom(metadata.antiSpoofPublicKey))
-                          .build())
-                  .setTrueWirelessImages(
-                          Rpcs.TrueWirelessHeadsetImages.newBuilder()
-                                  .setLeftBudUrl(
-                                          metadata.deviceMetadata.trueWirelessImageUrlLeftBud)
-                                  .setRightBudUrl(
-                                          metadata.deviceMetadata.trueWirelessImageUrlRightBud)
-                                  .setCaseUrl(metadata.deviceMetadata.trueWirelessImageUrlCase)
-                                  .build())
-                  .setImageUrl(metadata.deviceMetadata.imageUrl)
-                  .setIntentUri(metadata.deviceMetadata.intentUri)
-                  .setBleTxPower(metadata.deviceMetadata.bleTxPower)
-                  .setTriggerDistance(metadata.deviceMetadata.triggerDistance)
-                  .setDeviceType(Rpcs.DeviceType.forNumber(metadata.deviceMetadata.deviceType))
-                  .build())
-          .setImage(ByteString.copyFrom(metadata.deviceMetadata.image))
-          .setStrings(Rpcs.ObservedDeviceStrings.newBuilder()
-                  .setAssistantSetupHalfSheet(metadata.deviceMetadata.assistantSetupHalfSheet)
-                  .setAssistantSetupNotification(metadata.deviceMetadata.assistantSetupNotification)
-                  .setConfirmPinDescription(metadata.deviceMetadata.confirmPinDescription)
-                  .setConfirmPinTitle(metadata.deviceMetadata.confirmPinTitle)
-                  .setConnectSuccessCompanionAppInstalled(
-                          metadata.deviceMetadata.connectSuccessCompanionAppInstalled)
-                  .setConnectSuccessCompanionAppNotInstalled(
-                          metadata.deviceMetadata.connectSuccessCompanionAppNotInstalled)
-                  .setDownloadCompanionAppDescription(
-                          metadata.deviceMetadata.downloadCompanionAppDescription)
-                  .setFailConnectGoToSettingsDescription(
-                          metadata.deviceMetadata.failConnectGoToSettingsDescription)
-                  .setFastPairTvConnectDeviceNoAccountDescription(
-                          metadata.deviceMetadata.fastPairTvConnectDeviceNoAccountDescription)
-                  .setInitialNotificationDescription(
-                          metadata.deviceMetadata.initialNotificationDescription)
-                  .setInitialNotificationDescriptionNoAccount(
-                          metadata.deviceMetadata.initialNotificationDescriptionNoAccount)
-                  .setInitialPairingDescription(metadata.deviceMetadata.initialPairingDescription)
-                  .setLocale(metadata.deviceMetadata.locale)
-                  .setOpenCompanionAppDescription(
-                          metadata.deviceMetadata.openCompanionAppDescription)
-                  .setRetroactivePairingDescription(
-                          metadata.deviceMetadata.retroactivePairingDescription)
-                  .setSubsequentPairingDescription(
-                          metadata.deviceMetadata.subsequentPairingDescription)
-                  .setSyncContactsDescription(
-                          metadata.deviceMetadata.syncContactsDescription)
-                  .setSyncContactsTitle(
-                          metadata.deviceMetadata.syncContactsTitle)
-                  .setSyncSmsDescription(
-                          metadata.deviceMetadata.syncSmsDescription)
-                  .setSyncSmsTitle(
-                          metadata.deviceMetadata.syncSmsTitle)
-                  .setUnableToConnectDescription(
-                          metadata.deviceMetadata.unableToConnectDescription)
-                  .setUnableToConnectTitle(
-                          metadata.deviceMetadata.unableToConnectTitle)
-                  .setUpdateCompanionAppDescription(
-                          metadata.deviceMetadata.updateCompanionAppDescription)
-                  .setWaitLaunchCompanionAppDescription(
-                          metadata.deviceMetadata.waitLaunchCompanionAppDescription)
-                  .build())
+                .setDevice(Rpcs.Device.newBuilder()
+                        .setAntiSpoofingKeyPair(Rpcs.AntiSpoofingKeyPair.newBuilder()
+                                .setPublicKey(ByteString.copyFrom(metadata.antiSpoofPublicKey))
+                                .build())
+                        .setTrueWirelessImages(Rpcs.TrueWirelessHeadsetImages.newBuilder()
+                                .setLeftBudUrl(
+                                        metadata.deviceMetadata.trueWirelessImageUrlLeftBud)
+                                .setRightBudUrl(
+                                        metadata.deviceMetadata
+                                                .trueWirelessImageUrlRightBud)
+                                .setCaseUrl(
+                                        metadata.deviceMetadata
+                                                .trueWirelessImageUrlCase
+                                )
+                                .build())
+                        .setImageUrl(metadata.deviceMetadata.imageUrl)
+                        .setIntentUri(metadata.deviceMetadata.intentUri)
+                        .setBleTxPower(metadata.deviceMetadata.bleTxPower)
+                        .setTriggerDistance(metadata.deviceMetadata.triggerDistance)
+                        .setDeviceType(
+                                Rpcs.DeviceType.forNumber(metadata.deviceMetadata.deviceType))
+                        .build())
+                .setImage(ByteString.copyFrom(metadata.deviceMetadata.image))
+                .setStrings(Rpcs.ObservedDeviceStrings.newBuilder()
+                        .setAssistantSetupHalfSheet(metadata.deviceMetadata.assistantSetupHalfSheet)
+                        .setAssistantSetupNotification(
+                                metadata.deviceMetadata.assistantSetupNotification)
+                        .setConfirmPinDescription(metadata.deviceMetadata.confirmPinDescription)
+                        .setConfirmPinTitle(metadata.deviceMetadata.confirmPinTitle)
+                        .setConnectSuccessCompanionAppInstalled(
+                                metadata.deviceMetadata.connectSuccessCompanionAppInstalled)
+                        .setConnectSuccessCompanionAppNotInstalled(
+                                metadata.deviceMetadata.connectSuccessCompanionAppNotInstalled)
+                        .setDownloadCompanionAppDescription(
+                                metadata.deviceMetadata.downloadCompanionAppDescription)
+                        .setFailConnectGoToSettingsDescription(
+                                metadata.deviceMetadata.failConnectGoToSettingsDescription)
+                        .setFastPairTvConnectDeviceNoAccountDescription(
+                                metadata.deviceMetadata.fastPairTvConnectDeviceNoAccountDescription)
+                        .setInitialNotificationDescription(
+                                metadata.deviceMetadata.initialNotificationDescription)
+                        .setInitialNotificationDescriptionNoAccount(
+                                metadata.deviceMetadata.initialNotificationDescriptionNoAccount)
+                        .setInitialPairingDescription(
+                                metadata.deviceMetadata.initialPairingDescription)
+                        .setLocale(metadata.deviceMetadata.locale)
+                        .setOpenCompanionAppDescription(
+                                metadata.deviceMetadata.openCompanionAppDescription)
+                        .setRetroactivePairingDescription(
+                                metadata.deviceMetadata.retroactivePairingDescription)
+                        .setSubsequentPairingDescription(
+                                metadata.deviceMetadata.subsequentPairingDescription)
+                        .setSyncContactsDescription(
+                                metadata.deviceMetadata.syncContactsDescription)
+                        .setSyncContactsTitle(
+                                metadata.deviceMetadata.syncContactsTitle)
+                        .setSyncSmsDescription(
+                                metadata.deviceMetadata.syncSmsDescription)
+                        .setSyncSmsTitle(
+                                metadata.deviceMetadata.syncSmsTitle)
+                        .setUnableToConnectDescription(
+                                metadata.deviceMetadata.unableToConnectDescription)
+                        .setUnableToConnectTitle(
+                                metadata.deviceMetadata.unableToConnectTitle)
+                        .setUpdateCompanionAppDescription(
+                                metadata.deviceMetadata.updateCompanionAppDescription)
+                        .setWaitLaunchCompanionAppDescription(
+                                metadata.deviceMetadata.waitLaunchCompanionAppDescription)
+                        .build())
                 .build();
     }
+
+    static @Nullable FastPairAccountKeyDeviceMetadataParcel
+            convertFastPairUploadInfoToFastPairAccountKeyDeviceMetadata(
+                    FastPairUploadInfo uploadInfo) {
+        if (uploadInfo == null) {
+            return null;
+        }
+
+        FastPairAccountKeyDeviceMetadataParcel accountKeyDeviceMetadataParcel =
+                new FastPairAccountKeyDeviceMetadataParcel();
+        accountKeyDeviceMetadataParcel.accountKey = uploadInfo.getAccountKey().toByteArray();
+        accountKeyDeviceMetadataParcel.sha256AccountKeyPublicAddress =
+                uploadInfo.getSha256AccountKeyPublicAddress().toByteArray();
+        accountKeyDeviceMetadataParcel.metadata =
+                convertStoredDiscoveryItemToFastPairDeviceMetadata(
+                        uploadInfo.getStoredDiscoveryItem());
+        accountKeyDeviceMetadataParcel.discoveryItem =
+                convertStoredDiscoveryItemToFastPairDiscoveryItem(
+                        uploadInfo.getStoredDiscoveryItem());
+
+        return accountKeyDeviceMetadataParcel;
+    }
+
+    private static @Nullable FastPairDiscoveryItemParcel
+            convertStoredDiscoveryItemToFastPairDiscoveryItem(
+                    @Nullable Cache.StoredDiscoveryItem storedDiscoveryItem) {
+        if (storedDiscoveryItem == null) {
+            return null;
+        }
+
+        FastPairDiscoveryItemParcel discoveryItemParcel = new FastPairDiscoveryItemParcel();
+        discoveryItemParcel.actionUrl = storedDiscoveryItem.getActionUrl();
+        discoveryItemParcel.actionUrlType = storedDiscoveryItem.getActionUrlType().getNumber();
+        discoveryItemParcel.appName = storedDiscoveryItem.getAppName();
+        discoveryItemParcel.attachmentType = storedDiscoveryItem.getAttachmentType().getNumber();
+        discoveryItemParcel.authenticationPublicKeySecp256r1 =
+                storedDiscoveryItem.getAuthenticationPublicKeySecp256R1().toByteArray();
+        discoveryItemParcel.bleRecordBytes = storedDiscoveryItem.getBleRecordBytes().toByteArray();
+        discoveryItemParcel.debugCategory = storedDiscoveryItem.getDebugCategory().getNumber();
+        discoveryItemParcel.debugMessage = storedDiscoveryItem.getDebugMessage();
+        discoveryItemParcel.description = storedDiscoveryItem.getDescription();
+        discoveryItemParcel.deviceName = storedDiscoveryItem.getDeviceName();
+        discoveryItemParcel.displayUrl = storedDiscoveryItem.getDisplayUrl();
+        discoveryItemParcel.entityId = storedDiscoveryItem.getEntityId();
+        discoveryItemParcel.featureGraphicUrl = storedDiscoveryItem.getFeatureGraphicUrl();
+        discoveryItemParcel.firstObservationTimestampMillis =
+                storedDiscoveryItem.getFirstObservationTimestampMillis();
+        discoveryItemParcel.groupId = storedDiscoveryItem.getGroupId();
+        discoveryItemParcel.iconFifeUrl = storedDiscoveryItem.getIconFifeUrl();
+        discoveryItemParcel.iconPng = storedDiscoveryItem.getIconPng().toByteArray();
+        discoveryItemParcel.id = storedDiscoveryItem.getId();
+        discoveryItemParcel.lastObservationTimestampMillis =
+                storedDiscoveryItem.getLastObservationTimestampMillis();
+        discoveryItemParcel.lastUserExperience =
+                storedDiscoveryItem.getLastUserExperience().getNumber();
+        discoveryItemParcel.lostMillis = storedDiscoveryItem.getLostMillis();
+        discoveryItemParcel.macAddress = storedDiscoveryItem.getMacAddress();
+        discoveryItemParcel.packageName = storedDiscoveryItem.getPackageName();
+        discoveryItemParcel.pendingAppInstallTimestampMillis =
+                storedDiscoveryItem.getPendingAppInstallTimestampMillis();
+        discoveryItemParcel.rssi = storedDiscoveryItem.getRssi();
+        discoveryItemParcel.state = storedDiscoveryItem.getState().getNumber();
+        discoveryItemParcel.title = storedDiscoveryItem.getTitle();
+        discoveryItemParcel.triggerId = storedDiscoveryItem.getTriggerId();
+        discoveryItemParcel.txPower = storedDiscoveryItem.getTxPower();
+        discoveryItemParcel.type = storedDiscoveryItem.getType().getNumber();
+
+        return discoveryItemParcel;
+    }
+
+    /*  Do we upload these?
+        String downloadCompanionAppDescription =
+             bundle.getString("downloadCompanionAppDescription");
+        String locale = bundle.getString("locale");
+        String openCompanionAppDescription = bundle.getString("openCompanionAppDescription");
+        float triggerDistance = bundle.getFloat("triggerDistance");
+        String unableToConnectDescription = bundle.getString("unableToConnectDescription");
+        String unableToConnectTitle = bundle.getString("unableToConnectTitle");
+        String updateCompanionAppDescription = bundle.getString("updateCompanionAppDescription");
+    */
+    private static @Nullable FastPairDeviceMetadataParcel
+            convertStoredDiscoveryItemToFastPairDeviceMetadata(
+                    @Nullable Cache.StoredDiscoveryItem storedDiscoveryItem) {
+        if (storedDiscoveryItem == null) {
+            return null;
+        }
+
+        FastPairStrings fpStrings = storedDiscoveryItem.getFastPairStrings();
+
+        FastPairDeviceMetadataParcel metadataParcel = new FastPairDeviceMetadataParcel();
+        metadataParcel.assistantSetupHalfSheet = fpStrings.getAssistantHalfSheetDescription();
+        metadataParcel.assistantSetupNotification = fpStrings.getAssistantNotificationDescription();
+        metadataParcel.confirmPinDescription = fpStrings.getConfirmPinDescription();
+        metadataParcel.confirmPinTitle = fpStrings.getConfirmPinTitle();
+        metadataParcel.connectSuccessCompanionAppInstalled =
+                fpStrings.getPairingFinishedCompanionAppInstalled();
+        metadataParcel.connectSuccessCompanionAppNotInstalled =
+                fpStrings.getPairingFinishedCompanionAppNotInstalled();
+        metadataParcel.failConnectGoToSettingsDescription = fpStrings.getPairingFailDescription();
+        metadataParcel.fastPairTvConnectDeviceNoAccountDescription =
+                fpStrings.getFastPairTvConnectDeviceNoAccountDescription();
+        metadataParcel.initialNotificationDescription = fpStrings.getTapToPairWithAccount();
+        metadataParcel.initialNotificationDescriptionNoAccount =
+                fpStrings.getTapToPairWithoutAccount();
+        metadataParcel.initialPairingDescription = fpStrings.getInitialPairingDescription();
+        metadataParcel.retroactivePairingDescription = fpStrings.getRetroactivePairingDescription();
+        metadataParcel.subsequentPairingDescription = fpStrings.getSubsequentPairingDescription();
+        metadataParcel.syncContactsDescription = fpStrings.getSyncContactsDescription();
+        metadataParcel.syncContactsTitle = fpStrings.getSyncContactsTitle();
+        metadataParcel.syncSmsDescription = fpStrings.getSyncSmsDescription();
+        metadataParcel.syncSmsTitle = fpStrings.getSyncSmsTitle();
+        metadataParcel.waitLaunchCompanionAppDescription = fpStrings.getWaitAppLaunchDescription();
+
+        Cache.FastPairInformation fpInformation = storedDiscoveryItem.getFastPairInformation();
+        metadataParcel.trueWirelessImageUrlCase =
+                fpInformation.getTrueWirelessImages().getCaseUrl();
+        metadataParcel.trueWirelessImageUrlLeftBud =
+                fpInformation.getTrueWirelessImages().getLeftBudUrl();
+        metadataParcel.trueWirelessImageUrlRightBud =
+                fpInformation.getTrueWirelessImages().getRightBudUrl();
+        metadataParcel.deviceType = fpInformation.getDeviceType().getNumber();
+
+        metadataParcel.bleTxPower = storedDiscoveryItem.getTxPower();
+        metadataParcel.image = storedDiscoveryItem.getIconPng().toByteArray();
+        metadataParcel.imageUrl = storedDiscoveryItem.getIconFifeUrl();
+        metadataParcel.intentUri = storedDiscoveryItem.getActionUrl();
+
+        return metadataParcel;
+    }
 }
diff --git a/nearby/service/proto/src/fastpair/data.proto b/nearby/service/proto/src/fastpair/data.proto
new file mode 100644
index 0000000..6f4fadd
--- /dev/null
+++ b/nearby/service/proto/src/fastpair/data.proto
@@ -0,0 +1,26 @@
+syntax = "proto3";
+
+package service.proto;
+import "src/fastpair/cache.proto";
+
+// A device that has been Fast Paired with.
+message FastPairDeviceWithAccountKey {
+  // The account key which was written to the device after pairing completed.
+  bytes account_key = 1;
+
+  // The stored discovery item which represents the notification that should be
+  // associated with the device. Note, this is stored as a raw byte array
+  // instead of StoredDiscoveryItem because icing only supports proto lite and
+  // StoredDiscoveryItem is handed around as a nano proto in implementation,
+  // which are not compatible with each other.
+  StoredDiscoveryItem discovery_item = 3;
+
+  // SHA256 of "account key + headset's public address", this is used to
+  // identify the paired headset. Because of adding account key to generate the
+  // hash value, it makes the information anonymous, even for the same headset,
+  // different accounts have different values.
+  bytes sha256_account_key_public_address = 4;
+
+  // Deprecated fields.
+  reserved 2;
+}
diff --git a/nearby/tests/cts/fastpair/AndroidTest.xml b/nearby/tests/cts/fastpair/AndroidTest.xml
index 0d55c71..59cc779 100644
--- a/nearby/tests/cts/fastpair/AndroidTest.xml
+++ b/nearby/tests/cts/fastpair/AndroidTest.xml
@@ -27,5 +27,9 @@
   <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
     <option name="package" value="android.nearby.cts" />
   </test>
-
+  <!-- Only run NearbyUnitTests in MTS if the Nearby Mainline module is installed. -->
+  <object type="module_controller"
+      class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+    <option name="mainline-module-package-name" value="com.google.android.tethering" />
+  </object>
 </configuration>
\ No newline at end of file
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
index bfe71cd..743a8e7 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderBaseTest.java
@@ -16,9 +16,8 @@
 
 package android.nearby.cts;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
@@ -50,6 +49,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 
 import com.google.common.collect.ImmutableList;
 
@@ -74,7 +74,7 @@
             "CONNECT_SUCCESS_COMPANION_APP_INSTALLED";
     private static final String CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED =
             "CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED";
-    private static final double DELTA = 0.000001;
+    private static final float DELTA = 0.001f;
     private static final int DEVICE_TYPE = 7;
     private static final String DOWNLOAD_COMPANION_APP_DESCRIPTION =
             "DOWNLOAD_COMPANION_APP_DESCRIPTION";
@@ -193,18 +193,18 @@
             HAPPY_PATH_FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA =
             genHappyPathFastPairAntispoofkeyDeviceMetadata();
 
-    private @Captor ArgumentCaptor<FastPairEligibleAccountParcel[]>
+    @Captor private ArgumentCaptor<FastPairEligibleAccountParcel[]>
             mFastPairEligibleAccountParcelsArgumentCaptor;
-    private @Captor ArgumentCaptor<FastPairAccountKeyDeviceMetadataParcel[]>
+    @Captor private ArgumentCaptor<FastPairAccountKeyDeviceMetadataParcel[]>
             mFastPairAccountKeyDeviceMetadataParcelsArgumentCaptor;
 
-    private @Mock FastPairDataProviderBase mMockFastPairDataProviderBase;
-    private @Mock IFastPairAntispoofkeyDeviceMetadataCallback.Stub
+    @Mock private FastPairDataProviderBase mMockFastPairDataProviderBase;
+    @Mock private IFastPairAntispoofkeyDeviceMetadataCallback.Stub
             mAntispoofkeyDeviceMetadataCallback;
-    private @Mock IFastPairAccountDevicesMetadataCallback.Stub mAccountDevicesMetadataCallback;
-    private @Mock IFastPairEligibleAccountsCallback.Stub mEligibleAccountsCallback;
-    private @Mock IFastPairManageAccountCallback.Stub mManageAccountCallback;
-    private @Mock IFastPairManageAccountDeviceCallback.Stub mManageAccountDeviceCallback;
+    @Mock private IFastPairAccountDevicesMetadataCallback.Stub mAccountDevicesMetadataCallback;
+    @Mock private IFastPairEligibleAccountsCallback.Stub mEligibleAccountsCallback;
+    @Mock private IFastPairManageAccountCallback.Stub mManageAccountCallback;
+    @Mock private IFastPairManageAccountDeviceCallback.Stub mManageAccountDeviceCallback;
 
     private MyHappyPathProvider mHappyPathFastPairDataProvider;
     private MyErrorPathProvider mErrorPathFastPairDataProvider;
@@ -220,6 +220,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testHappyPathLoadFastPairAntispoofkeyDeviceMetadata() throws Exception {
         // AOSP sends calls to OEM via Parcelable.
         mHappyPathFastPairDataProvider.asProvider().loadFastPairAntispoofkeyDeviceMetadata(
@@ -246,6 +247,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testHappyPathLoadFastPairAccountDevicesMetadata() throws Exception {
         // AOSP sends calls to OEM via Parcelable.
         mHappyPathFastPairDataProvider.asProvider().loadFastPairAccountDevicesMetadata(
@@ -270,6 +272,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testHappyPathLoadFastPairEligibleAccounts() throws Exception {
         // AOSP sends calls to OEM via Parcelable.
         mHappyPathFastPairDataProvider.asProvider().loadFastPairEligibleAccounts(
@@ -293,6 +296,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testHappyPathManageFastPairAccount() throws Exception {
         // AOSP sends calls to OEM via Parcelable.
         mHappyPathFastPairDataProvider.asProvider().manageFastPairAccount(
@@ -314,6 +318,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testHappyPathManageFastPairAccountDevice() throws Exception {
         // AOSP sends calls to OEM via Parcelable.
         mHappyPathFastPairDataProvider.asProvider().manageFastPairAccountDevice(
@@ -335,6 +340,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testErrorPathLoadFastPairAntispoofkeyDeviceMetadata() throws Exception {
         mErrorPathFastPairDataProvider.asProvider().loadFastPairAntispoofkeyDeviceMetadata(
                 FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA_REQUEST_PARCEL,
@@ -347,6 +353,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testErrorPathLoadFastPairAccountDevicesMetadata() throws Exception {
         mErrorPathFastPairDataProvider.asProvider().loadFastPairAccountDevicesMetadata(
                 FAST_PAIR_ACCOUNT_DEVICES_METADATA_REQUEST_PARCEL,
@@ -359,6 +366,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testErrorPathLoadFastPairEligibleAccounts() throws Exception {
         mErrorPathFastPairDataProvider.asProvider().loadFastPairEligibleAccounts(
                 FAST_PAIR_ELIGIBLE_ACCOUNTS_REQUEST_PARCEL,
@@ -371,6 +379,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testErrorPathManageFastPairAccount() throws Exception {
         mErrorPathFastPairDataProvider.asProvider().manageFastPairAccount(
                 FAST_PAIR_MANAGE_ACCOUNT_REQUEST_PARCEL,
@@ -382,6 +391,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testErrorPathManageFastPairAccountDevice() throws Exception {
         mErrorPathFastPairDataProvider.asProvider().manageFastPairAccountDevice(
                 FAST_PAIR_MANAGE_ACCOUNT_DEVICE_REQUEST_PARCEL,
@@ -773,13 +783,13 @@
     /* Verifies Happy Path AntispoofkeyDeviceMetadataRequest. */
     private static void ensureHappyPathAsExpected(
             FastPairDataProviderBase.FastPairAntispoofkeyDeviceMetadataRequest request) {
-        assertEquals(REQUEST_MODEL_ID, request.getModelId());
+        assertThat(request.getModelId()).isEqualTo(REQUEST_MODEL_ID);
     }
 
     /* Verifies Happy Path AccountDevicesMetadataRequest. */
     private static void ensureHappyPathAsExpected(
             FastPairDataProviderBase.FastPairAccountDevicesMetadataRequest request) {
-        assertEquals(ACCOUNTDEVICES_METADATA_ACCOUNT, request.getAccount());
+        assertThat(request.getAccount()).isEqualTo(ACCOUNTDEVICES_METADATA_ACCOUNT);
     }
 
     /* Verifies Happy Path FastPairEligibleAccountsRequest. */
@@ -792,32 +802,32 @@
     /* Verifies Happy Path FastPairManageAccountRequest. */
     private static void ensureHappyPathAsExpected(
             FastPairDataProviderBase.FastPairManageAccountRequest request) {
-        assertEquals(MANAGE_ACCOUNT, request.getAccount());
-        assertEquals(MANAGE_ACCOUNT_REQUEST_TYPE, request.getRequestType());
+        assertThat(request.getAccount()).isEqualTo(MANAGE_ACCOUNT);
+        assertThat(request.getRequestType()).isEqualTo(MANAGE_ACCOUNT_REQUEST_TYPE);
     }
 
     /* Verifies Happy Path FastPairManageAccountDeviceRequest. */
     private static void ensureHappyPathAsExpected(
             FastPairDataProviderBase.FastPairManageAccountDeviceRequest request) {
-        assertEquals(MANAGE_ACCOUNT, request.getAccount());
-        assertEquals(MANAGE_ACCOUNT_REQUEST_TYPE, request.getRequestType());
-        assertEquals(BLE_ADDRESS, request.getBleAddress());
+        assertThat(request.getAccount()).isEqualTo(MANAGE_ACCOUNT);
+        assertThat(request.getRequestType()).isEqualTo(MANAGE_ACCOUNT_REQUEST_TYPE);
+        assertThat(request.getBleAddress()).isEqualTo(BLE_ADDRESS);
         ensureHappyPathAsExpected(request.getAccountKeyDeviceMetadata());
     }
 
     /* Verifies Happy Path AntispoofkeyDeviceMetadataParcel. */
     private static void ensureHappyPathAsExpected(
             FastPairAntispoofkeyDeviceMetadataParcel metadataParcel) {
-        assertNotNull(metadataParcel);
-        assertEquals(ANTI_SPOOFING_KEY, metadataParcel.antiSpoofPublicKey);
+        assertThat(metadataParcel).isNotNull();
+        assertThat(metadataParcel.antiSpoofPublicKey).isEqualTo(ANTI_SPOOFING_KEY);
         ensureHappyPathAsExpected(metadataParcel.deviceMetadata);
     }
 
     /* Verifies Happy Path FastPairAccountKeyDeviceMetadataParcel[]. */
     private static void ensureHappyPathAsExpected(
             FastPairAccountKeyDeviceMetadataParcel[] metadataParcels) {
-        assertNotNull(metadataParcels);
-        assertEquals(ACCOUNTKEY_DEVICE_NUM, metadataParcels.length);
+        assertThat(metadataParcels).isNotNull();
+        assertThat(metadataParcels).hasLength(ACCOUNTKEY_DEVICE_NUM);
         for (FastPairAccountKeyDeviceMetadataParcel parcel: metadataParcels) {
             ensureHappyPathAsExpected(parcel);
         }
@@ -826,10 +836,10 @@
     /* Verifies Happy Path FastPairAccountKeyDeviceMetadataParcel. */
     private static void ensureHappyPathAsExpected(
             FastPairAccountKeyDeviceMetadataParcel metadataParcel) {
-        assertNotNull(metadataParcel);
-        assertEquals(ACCOUNT_KEY, metadataParcel.accountKey);
-        assertEquals(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS,
-                metadataParcel.sha256AccountKeyPublicAddress);
+        assertThat(metadataParcel).isNotNull();
+        assertThat(metadataParcel.accountKey).isEqualTo(ACCOUNT_KEY);
+        assertThat(metadataParcel.sha256AccountKeyPublicAddress)
+                .isEqualTo(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS);
         ensureHappyPathAsExpected(metadataParcel.metadata);
         ensureHappyPathAsExpected(metadataParcel.discoveryItem);
     }
@@ -837,191 +847,217 @@
     /* Verifies Happy Path FastPairAccountKeyDeviceMetadata. */
     private static void ensureHappyPathAsExpected(
             FastPairAccountKeyDeviceMetadata metadata) {
-        assertEquals(ACCOUNT_KEY, metadata.getAccountKey());
-        assertEquals(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS,
-                metadata.getSha256AccountKeyPublicAddress());
+        assertThat(metadata.getAccountKey()).isEqualTo(ACCOUNT_KEY);
+        assertThat(metadata.getSha256AccountKeyPublicAddress())
+                .isEqualTo(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS);
         ensureHappyPathAsExpected(metadata.getFastPairDeviceMetadata());
         ensureHappyPathAsExpected(metadata.getFastPairDiscoveryItem());
     }
 
     /* Verifies Happy Path DeviceMetadataParcel. */
     private static void ensureHappyPathAsExpected(FastPairDeviceMetadataParcel metadataParcel) {
-        assertNotNull(metadataParcel);
-        assertEquals(ASSISTANT_SETUP_HALFSHEET, metadataParcel.assistantSetupHalfSheet);
-        assertEquals(ASSISTANT_SETUP_NOTIFICATION, metadataParcel.assistantSetupNotification);
-        assertEquals(BLE_TX_POWER, metadataParcel.bleTxPower);
-        assertEquals(CONFIRM_PIN_DESCRIPTION, metadataParcel.confirmPinDescription);
-        assertEquals(CONFIRM_PIN_TITLE, metadataParcel.confirmPinTitle);
-        assertEquals(CONNECT_SUCCESS_COMPANION_APP_INSTALLED,
-                metadataParcel.connectSuccessCompanionAppInstalled);
-        assertEquals(CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED,
-                metadataParcel.connectSuccessCompanionAppNotInstalled);
-        assertEquals(DEVICE_TYPE, metadataParcel.deviceType);
-        assertEquals(DOWNLOAD_COMPANION_APP_DESCRIPTION,
-                metadataParcel.downloadCompanionAppDescription);
-        assertEquals(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION,
-                metadataParcel.failConnectGoToSettingsDescription);
-        assertEquals(FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION,
-                metadataParcel.fastPairTvConnectDeviceNoAccountDescription);
-        assertArrayEquals(IMAGE, metadataParcel.image);
-        assertEquals(IMAGE_URL, metadataParcel.imageUrl);
-        assertEquals(INITIAL_NOTIFICATION_DESCRIPTION,
-                metadataParcel.initialNotificationDescription);
-        assertEquals(INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT,
-                metadataParcel.initialNotificationDescriptionNoAccount);
-        assertEquals(INITIAL_PAIRING_DESCRIPTION, metadataParcel.initialPairingDescription);
-        assertEquals(INTENT_URI, metadataParcel.intentUri);
-        assertEquals(LOCALE, metadataParcel.locale);
-        assertEquals(OPEN_COMPANION_APP_DESCRIPTION, metadataParcel.openCompanionAppDescription);
-        assertEquals(RETRO_ACTIVE_PAIRING_DESCRIPTION,
-                metadataParcel.retroactivePairingDescription);
-        assertEquals(SUBSEQUENT_PAIRING_DESCRIPTION, metadataParcel.subsequentPairingDescription);
-        assertEquals(SYNC_CONTACT_DESCRPTION, metadataParcel.syncContactsDescription);
-        assertEquals(SYNC_CONTACTS_TITLE, metadataParcel.syncContactsTitle);
-        assertEquals(SYNC_SMS_DESCRIPTION, metadataParcel.syncSmsDescription);
-        assertEquals(SYNC_SMS_TITLE, metadataParcel.syncSmsTitle);
-        assertEquals(TRIGGER_DISTANCE, metadataParcel.triggerDistance, DELTA);
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_CASE, metadataParcel.trueWirelessImageUrlCase);
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD, metadataParcel.trueWirelessImageUrlLeftBud);
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD,
-                metadataParcel.trueWirelessImageUrlRightBud);
-        assertEquals(UNABLE_TO_CONNECT_DESCRIPTION, metadataParcel.unableToConnectDescription);
-        assertEquals(UNABLE_TO_CONNECT_TITLE, metadataParcel.unableToConnectTitle);
-        assertEquals(UPDATE_COMPANION_APP_DESCRIPTION,
-                metadataParcel.updateCompanionAppDescription);
-        assertEquals(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION,
-                metadataParcel.waitLaunchCompanionAppDescription);
+        assertThat(metadataParcel).isNotNull();
+
+        assertThat(metadataParcel.assistantSetupHalfSheet).isEqualTo(ASSISTANT_SETUP_HALFSHEET);
+        assertThat(metadataParcel.assistantSetupNotification).isEqualTo(
+                ASSISTANT_SETUP_NOTIFICATION);
+
+        assertThat(metadataParcel.bleTxPower).isEqualTo(BLE_TX_POWER);
+
+        assertThat(metadataParcel.confirmPinDescription).isEqualTo(CONFIRM_PIN_DESCRIPTION);
+        assertThat(metadataParcel.confirmPinTitle).isEqualTo(CONFIRM_PIN_TITLE);
+        assertThat(metadataParcel.connectSuccessCompanionAppInstalled).isEqualTo(
+                CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
+        assertThat(metadataParcel.connectSuccessCompanionAppNotInstalled).isEqualTo(
+                CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
+
+        assertThat(metadataParcel.deviceType).isEqualTo(DEVICE_TYPE);
+        assertThat(metadataParcel.downloadCompanionAppDescription).isEqualTo(
+                DOWNLOAD_COMPANION_APP_DESCRIPTION);
+
+        assertThat(metadataParcel.failConnectGoToSettingsDescription).isEqualTo(
+                FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
+        assertThat(metadataParcel.fastPairTvConnectDeviceNoAccountDescription).isEqualTo(
+                FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION);
+
+        assertThat(metadataParcel.image).isEqualTo(IMAGE);
+        assertThat(metadataParcel.imageUrl).isEqualTo(IMAGE_URL);
+        assertThat(metadataParcel.initialNotificationDescription).isEqualTo(
+                INITIAL_NOTIFICATION_DESCRIPTION);
+        assertThat(metadataParcel.initialNotificationDescriptionNoAccount).isEqualTo(
+                INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
+        assertThat(metadataParcel.initialPairingDescription).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
+        assertThat(metadataParcel.intentUri).isEqualTo(INTENT_URI);
+
+        assertThat(metadataParcel.locale).isEqualTo(LOCALE);
+
+        assertThat(metadataParcel.openCompanionAppDescription).isEqualTo(
+                OPEN_COMPANION_APP_DESCRIPTION);
+
+        assertThat(metadataParcel.retroactivePairingDescription).isEqualTo(
+                RETRO_ACTIVE_PAIRING_DESCRIPTION);
+
+        assertThat(metadataParcel.subsequentPairingDescription).isEqualTo(
+                SUBSEQUENT_PAIRING_DESCRIPTION);
+        assertThat(metadataParcel.syncContactsDescription).isEqualTo(SYNC_CONTACT_DESCRPTION);
+        assertThat(metadataParcel.syncContactsTitle).isEqualTo(SYNC_CONTACTS_TITLE);
+        assertThat(metadataParcel.syncSmsDescription).isEqualTo(SYNC_SMS_DESCRIPTION);
+        assertThat(metadataParcel.syncSmsTitle).isEqualTo(SYNC_SMS_TITLE);
+
+        assertThat(metadataParcel.triggerDistance).isWithin(DELTA).of(TRIGGER_DISTANCE);
+        assertThat(metadataParcel.trueWirelessImageUrlCase).isEqualTo(TRUE_WIRELESS_IMAGE_URL_CASE);
+        assertThat(metadataParcel.trueWirelessImageUrlLeftBud).isEqualTo(
+                TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
+        assertThat(metadataParcel.trueWirelessImageUrlRightBud).isEqualTo(
+                TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
+
+        assertThat(metadataParcel.unableToConnectDescription).isEqualTo(
+                UNABLE_TO_CONNECT_DESCRIPTION);
+        assertThat(metadataParcel.unableToConnectTitle).isEqualTo(UNABLE_TO_CONNECT_TITLE);
+        assertThat(metadataParcel.updateCompanionAppDescription).isEqualTo(
+                UPDATE_COMPANION_APP_DESCRIPTION);
+
+        assertThat(metadataParcel.waitLaunchCompanionAppDescription).isEqualTo(
+                WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
     }
 
     /* Verifies Happy Path DeviceMetadata. */
     private static void ensureHappyPathAsExpected(FastPairDeviceMetadata metadata) {
-        assertEquals(ASSISTANT_SETUP_HALFSHEET, metadata.getAssistantSetupHalfSheet());
-        assertEquals(ASSISTANT_SETUP_NOTIFICATION, metadata.getAssistantSetupNotification());
-        assertEquals(BLE_TX_POWER, metadata.getBleTxPower());
-        assertEquals(CONFIRM_PIN_DESCRIPTION, metadata.getConfirmPinDescription());
-        assertEquals(CONFIRM_PIN_TITLE, metadata.getConfirmPinTitle());
-        assertEquals(CONNECT_SUCCESS_COMPANION_APP_INSTALLED,
-                metadata.getConnectSuccessCompanionAppInstalled());
-        assertEquals(CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED,
-                metadata.getConnectSuccessCompanionAppNotInstalled());
-        assertEquals(DEVICE_TYPE, metadata.getDeviceType());
-        assertEquals(DOWNLOAD_COMPANION_APP_DESCRIPTION,
-                metadata.getDownloadCompanionAppDescription());
-        assertEquals(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION,
-                metadata.getFailConnectGoToSettingsDescription());
-        assertEquals(FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION,
-                metadata.getFastPairTvConnectDeviceNoAccountDescription());
-        assertArrayEquals(IMAGE, metadata.getImage());
-        assertEquals(IMAGE_URL, metadata.getImageUrl());
-        assertEquals(INITIAL_NOTIFICATION_DESCRIPTION,
-                metadata.getInitialNotificationDescription());
-        assertEquals(INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT,
-                metadata.getInitialNotificationDescriptionNoAccount());
-        assertEquals(INITIAL_PAIRING_DESCRIPTION, metadata.getInitialPairingDescription());
-        assertEquals(INTENT_URI, metadata.getIntentUri());
-        assertEquals(LOCALE, metadata.getLocale());
-        assertEquals(OPEN_COMPANION_APP_DESCRIPTION, metadata.getOpenCompanionAppDescription());
-        assertEquals(RETRO_ACTIVE_PAIRING_DESCRIPTION,
-                metadata.getRetroactivePairingDescription());
-        assertEquals(SUBSEQUENT_PAIRING_DESCRIPTION, metadata.getSubsequentPairingDescription());
-        assertEquals(SYNC_CONTACT_DESCRPTION, metadata.getSyncContactsDescription());
-        assertEquals(SYNC_CONTACTS_TITLE, metadata.getSyncContactsTitle());
-        assertEquals(SYNC_SMS_DESCRIPTION, metadata.getSyncSmsDescription());
-        assertEquals(SYNC_SMS_TITLE, metadata.getSyncSmsTitle());
-        assertEquals(TRIGGER_DISTANCE, metadata.getTriggerDistance(), DELTA);
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_CASE, metadata.getTrueWirelessImageUrlCase());
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD, metadata.getTrueWirelessImageUrlLeftBud());
-        assertEquals(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD,
-                metadata.getTrueWirelessImageUrlRightBud());
-        assertEquals(UNABLE_TO_CONNECT_DESCRIPTION, metadata.getUnableToConnectDescription());
-        assertEquals(UNABLE_TO_CONNECT_TITLE, metadata.getUnableToConnectTitle());
-        assertEquals(UPDATE_COMPANION_APP_DESCRIPTION,
-                metadata.getUpdateCompanionAppDescription());
-        assertEquals(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION,
-                metadata.getWaitLaunchCompanionAppDescription());
+        assertThat(metadata.getAssistantSetupHalfSheet()).isEqualTo(ASSISTANT_SETUP_HALFSHEET);
+        assertThat(metadata.getAssistantSetupNotification())
+                .isEqualTo(ASSISTANT_SETUP_NOTIFICATION);
+        assertThat(metadata.getBleTxPower()).isEqualTo(BLE_TX_POWER);
+        assertThat(metadata.getConfirmPinDescription()).isEqualTo(CONFIRM_PIN_DESCRIPTION);
+        assertThat(metadata.getConfirmPinTitle()).isEqualTo(CONFIRM_PIN_TITLE);
+        assertThat(metadata.getConnectSuccessCompanionAppInstalled())
+                .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
+        assertThat(metadata.getConnectSuccessCompanionAppNotInstalled())
+                .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
+        assertThat(metadata.getDeviceType()).isEqualTo(DEVICE_TYPE);
+        assertThat(metadata.getDownloadCompanionAppDescription())
+                .isEqualTo(DOWNLOAD_COMPANION_APP_DESCRIPTION);
+        assertThat(metadata.getFailConnectGoToSettingsDescription())
+                .isEqualTo(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
+        assertThat(metadata.getFastPairTvConnectDeviceNoAccountDescription())
+                .isEqualTo(FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION);
+        assertThat(metadata.getImage()).isEqualTo(IMAGE);
+        assertThat(metadata.getImageUrl()).isEqualTo(IMAGE_URL);
+        assertThat(metadata.getInitialNotificationDescription())
+                .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION);
+        assertThat(metadata.getInitialNotificationDescriptionNoAccount())
+                .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
+        assertThat(metadata.getInitialPairingDescription()).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
+        assertThat(metadata.getIntentUri()).isEqualTo(INTENT_URI);
+        assertThat(metadata.getLocale()).isEqualTo(LOCALE);
+        assertThat(metadata.getOpenCompanionAppDescription())
+                .isEqualTo(OPEN_COMPANION_APP_DESCRIPTION);
+        assertThat(metadata.getRetroactivePairingDescription())
+                .isEqualTo(RETRO_ACTIVE_PAIRING_DESCRIPTION);
+        assertThat(metadata.getSubsequentPairingDescription())
+                .isEqualTo(SUBSEQUENT_PAIRING_DESCRIPTION);
+        assertThat(metadata.getSyncContactsDescription()).isEqualTo(SYNC_CONTACT_DESCRPTION);
+        assertThat(metadata.getSyncContactsTitle()).isEqualTo(SYNC_CONTACTS_TITLE);
+        assertThat(metadata.getSyncSmsDescription()).isEqualTo(SYNC_SMS_DESCRIPTION);
+        assertThat(metadata.getSyncSmsTitle()).isEqualTo(SYNC_SMS_TITLE);
+        assertThat(metadata.getTriggerDistance()).isWithin(DELTA).of(TRIGGER_DISTANCE);
+        assertThat(metadata.getTrueWirelessImageUrlCase()).isEqualTo(TRUE_WIRELESS_IMAGE_URL_CASE);
+        assertThat(metadata.getTrueWirelessImageUrlLeftBud())
+                .isEqualTo(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
+        assertThat(metadata.getTrueWirelessImageUrlRightBud())
+                .isEqualTo(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
+        assertThat(metadata.getUnableToConnectDescription())
+                .isEqualTo(UNABLE_TO_CONNECT_DESCRIPTION);
+        assertThat(metadata.getUnableToConnectTitle()).isEqualTo(UNABLE_TO_CONNECT_TITLE);
+        assertThat(metadata.getUpdateCompanionAppDescription())
+                .isEqualTo(UPDATE_COMPANION_APP_DESCRIPTION);
+        assertThat(metadata.getWaitLaunchCompanionAppDescription())
+                .isEqualTo(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
     }
 
     /* Verifies Happy Path FastPairDiscoveryItemParcel. */
     private static void ensureHappyPathAsExpected(FastPairDiscoveryItemParcel itemParcel) {
-        assertEquals(ACTION_URL, itemParcel.actionUrl);
-        assertEquals(ACTION_URL_TYPE, itemParcel.actionUrlType);
-        assertEquals(APP_NAME, itemParcel.appName);
-        assertEquals(ATTACHMENT_TYPE, itemParcel.attachmentType);
-        assertArrayEquals(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1,
-                itemParcel.authenticationPublicKeySecp256r1);
-        assertArrayEquals(BLE_RECORD_BYTES, itemParcel.bleRecordBytes);
-        assertEquals(DEBUG_CATEGORY, itemParcel.debugCategory);
-        assertEquals(DEBUG_MESSAGE, itemParcel.debugMessage);
-        assertEquals(DESCRIPTION, itemParcel.description);
-        assertEquals(DEVICE_NAME, itemParcel.deviceName);
-        assertEquals(DISPLAY_URL, itemParcel.displayUrl);
-        assertEquals(ENTITY_ID, itemParcel.entityId);
-        assertEquals(FEATURE_GRAPHIC_URL, itemParcel.featureGraphicUrl);
-        assertEquals(FIRST_OBSERVATION_TIMESTAMP_MILLIS,
-                itemParcel.firstObservationTimestampMillis);
-        assertEquals(GROUP_ID, itemParcel.groupId);
-        assertEquals(ICON_FIFE_URL, itemParcel.iconFifeUrl);
-        assertEquals(ICON_PNG, itemParcel.iconPng);
-        assertEquals(ID, itemParcel.id);
-        assertEquals(LAST_OBSERVATION_TIMESTAMP_MILLIS, itemParcel.lastObservationTimestampMillis);
-        assertEquals(LAST_USER_EXPERIENCE, itemParcel.lastUserExperience);
-        assertEquals(LOST_MILLIS, itemParcel.lostMillis);
-        assertEquals(MAC_ADDRESS, itemParcel.macAddress);
-        assertEquals(PACKAGE_NAME, itemParcel.packageName);
-        assertEquals(PENDING_APP_INSTALL_TIMESTAMP_MILLIS,
-                itemParcel.pendingAppInstallTimestampMillis);
-        assertEquals(RSSI, itemParcel.rssi);
-        assertEquals(STATE, itemParcel.state);
-        assertEquals(TITLE, itemParcel.title);
-        assertEquals(TRIGGER_ID, itemParcel.triggerId);
-        assertEquals(TX_POWER, itemParcel.txPower);
-        assertEquals(TYPE, itemParcel.type);
+        assertThat(itemParcel.actionUrl).isEqualTo(ACTION_URL);
+        assertThat(itemParcel.actionUrlType).isEqualTo(ACTION_URL_TYPE);
+        assertThat(itemParcel.appName).isEqualTo(APP_NAME);
+        assertThat(itemParcel.attachmentType).isEqualTo(ATTACHMENT_TYPE);
+        assertThat(itemParcel.authenticationPublicKeySecp256r1)
+                .isEqualTo(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1);
+        assertThat(itemParcel.bleRecordBytes).isEqualTo(BLE_RECORD_BYTES);
+        assertThat(itemParcel.debugCategory).isEqualTo(DEBUG_CATEGORY);
+        assertThat(itemParcel.debugMessage).isEqualTo(DEBUG_MESSAGE);
+        assertThat(itemParcel.description).isEqualTo(DESCRIPTION);
+        assertThat(itemParcel.deviceName).isEqualTo(DEVICE_NAME);
+        assertThat(itemParcel.displayUrl).isEqualTo(DISPLAY_URL);
+        assertThat(itemParcel.entityId).isEqualTo(ENTITY_ID);
+        assertThat(itemParcel.featureGraphicUrl).isEqualTo(FEATURE_GRAPHIC_URL);
+        assertThat(itemParcel.firstObservationTimestampMillis)
+                .isEqualTo(FIRST_OBSERVATION_TIMESTAMP_MILLIS);
+        assertThat(itemParcel.groupId).isEqualTo(GROUP_ID);
+        assertThat(itemParcel.iconFifeUrl).isEqualTo(ICON_FIFE_URL);
+        assertThat(itemParcel.iconPng).isEqualTo(ICON_PNG);
+        assertThat(itemParcel.id).isEqualTo(ID);
+        assertThat(itemParcel.lastObservationTimestampMillis)
+                .isEqualTo(LAST_OBSERVATION_TIMESTAMP_MILLIS);
+        assertThat(itemParcel.lastUserExperience).isEqualTo(LAST_USER_EXPERIENCE);
+        assertThat(itemParcel.lostMillis).isEqualTo(LOST_MILLIS);
+        assertThat(itemParcel.macAddress).isEqualTo(MAC_ADDRESS);
+        assertThat(itemParcel.packageName).isEqualTo(PACKAGE_NAME);
+        assertThat(itemParcel.pendingAppInstallTimestampMillis)
+                .isEqualTo(PENDING_APP_INSTALL_TIMESTAMP_MILLIS);
+        assertThat(itemParcel.rssi).isEqualTo(RSSI);
+        assertThat(itemParcel.state).isEqualTo(STATE);
+        assertThat(itemParcel.title).isEqualTo(TITLE);
+        assertThat(itemParcel.triggerId).isEqualTo(TRIGGER_ID);
+        assertThat(itemParcel.txPower).isEqualTo(TX_POWER);
+        assertThat(itemParcel.type).isEqualTo(TYPE);
     }
 
     /* Verifies Happy Path FastPairDiscoveryItem. */
     private static void ensureHappyPathAsExpected(FastPairDiscoveryItem item) {
-        assertEquals(ACTION_URL, item.getActionUrl());
-        assertEquals(ACTION_URL_TYPE, item.getActionUrlType());
-        assertEquals(APP_NAME, item.getAppName());
-        assertEquals(ATTACHMENT_TYPE, item.getAttachmentType());
-        assertArrayEquals(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1,
-                item.getAuthenticationPublicKeySecp256r1());
-        assertArrayEquals(BLE_RECORD_BYTES, item.getBleRecordBytes());
-        assertEquals(DEBUG_CATEGORY, item.getDebugCategory());
-        assertEquals(DEBUG_MESSAGE, item.getDebugMessage());
-        assertEquals(DESCRIPTION, item.getDescription());
-        assertEquals(DEVICE_NAME, item.getDeviceName());
-        assertEquals(DISPLAY_URL, item.getDisplayUrl());
-        assertEquals(ENTITY_ID, item.getEntityId());
-        assertEquals(FEATURE_GRAPHIC_URL, item.getFeatureGraphicUrl());
-        assertEquals(FIRST_OBSERVATION_TIMESTAMP_MILLIS,
-                item.getFirstObservationTimestampMillis());
-        assertEquals(GROUP_ID, item.getGroupId());
-        assertEquals(ICON_FIFE_URL, item.getIconFfeUrl());
-        assertEquals(ICON_PNG, item.getIconPng());
-        assertEquals(ID, item.getId());
-        assertEquals(LAST_OBSERVATION_TIMESTAMP_MILLIS, item.getLastObservationTimestampMillis());
-        assertEquals(LAST_USER_EXPERIENCE, item.getLastUserExperience());
-        assertEquals(LOST_MILLIS, item.getLostMillis());
-        assertEquals(MAC_ADDRESS, item.getMacAddress());
-        assertEquals(PACKAGE_NAME, item.getPackageName());
-        assertEquals(PENDING_APP_INSTALL_TIMESTAMP_MILLIS,
-                item.getPendingAppInstallTimestampMillis());
-        assertEquals(RSSI, item.getRssi());
-        assertEquals(STATE, item.getState());
-        assertEquals(TITLE, item.getTitle());
-        assertEquals(TRIGGER_ID, item.getTriggerId());
-        assertEquals(TX_POWER, item.getTxPower());
-        assertEquals(TYPE, item.getType());
+        assertThat(item.getActionUrl()).isEqualTo(ACTION_URL);
+        assertThat(item.getActionUrlType()).isEqualTo(ACTION_URL_TYPE);
+        assertThat(item.getAppName()).isEqualTo(APP_NAME);
+        assertThat(item.getAttachmentType()).isEqualTo(ATTACHMENT_TYPE);
+        assertThat(item.getAuthenticationPublicKeySecp256r1())
+                .isEqualTo(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1);
+        assertThat(item.getBleRecordBytes()).isEqualTo(BLE_RECORD_BYTES);
+        assertThat(item.getDebugCategory()).isEqualTo(DEBUG_CATEGORY);
+        assertThat(item.getDebugMessage()).isEqualTo(DEBUG_MESSAGE);
+        assertThat(item.getDescription()).isEqualTo(DESCRIPTION);
+        assertThat(item.getDeviceName()).isEqualTo(DEVICE_NAME);
+        assertThat(item.getDisplayUrl()).isEqualTo(DISPLAY_URL);
+        assertThat(item.getEntityId()).isEqualTo(ENTITY_ID);
+        assertThat(item.getFeatureGraphicUrl()).isEqualTo(FEATURE_GRAPHIC_URL);
+        assertThat(item.getFirstObservationTimestampMillis())
+                .isEqualTo(FIRST_OBSERVATION_TIMESTAMP_MILLIS);
+        assertThat(item.getGroupId()).isEqualTo(GROUP_ID);
+        assertThat(item.getIconFfeUrl()).isEqualTo(ICON_FIFE_URL);
+        assertThat(item.getIconPng()).isEqualTo(ICON_PNG);
+        assertThat(item.getId()).isEqualTo(ID);
+        assertThat(item.getLastObservationTimestampMillis())
+                .isEqualTo(LAST_OBSERVATION_TIMESTAMP_MILLIS);
+        assertThat(item.getLastUserExperience()).isEqualTo(LAST_USER_EXPERIENCE);
+        assertThat(item.getLostMillis()).isEqualTo(LOST_MILLIS);
+        assertThat(item.getMacAddress()).isEqualTo(MAC_ADDRESS);
+        assertThat(item.getPackageName()).isEqualTo(PACKAGE_NAME);
+        assertThat(item.getPendingAppInstallTimestampMillis())
+                .isEqualTo(PENDING_APP_INSTALL_TIMESTAMP_MILLIS);
+        assertThat(item.getRssi()).isEqualTo(RSSI);
+        assertThat(item.getState()).isEqualTo(STATE);
+        assertThat(item.getTitle()).isEqualTo(TITLE);
+        assertThat(item.getTriggerId()).isEqualTo(TRIGGER_ID);
+        assertThat(item.getTxPower()).isEqualTo(TX_POWER);
+        assertThat(item.getType()).isEqualTo(TYPE);
     }
 
     /* Verifies Happy Path EligibleAccountParcel[]. */
     private static void ensureHappyPathAsExpected(FastPairEligibleAccountParcel[] accountsParcel) {
-        assertEquals(ELIGIBLE_ACCOUNTS_NUM, accountsParcel.length);
-        assertEquals(ELIGIBLE_ACCOUNT_1, accountsParcel[0].account);
-        assertEquals(ELIGIBLE_ACCOUNT_1_OPT_IN, accountsParcel[0].optIn);
+        assertThat(accountsParcel).hasLength(ELIGIBLE_ACCOUNTS_NUM);
 
-        assertEquals(ELIGIBLE_ACCOUNT_2, accountsParcel[1].account);
-        assertEquals(ELIGIBLE_ACCOUNT_2_OPT_IN, accountsParcel[1].optIn);
+        assertThat(accountsParcel[0].account).isEqualTo(ELIGIBLE_ACCOUNT_1);
+        assertThat(accountsParcel[0].optIn).isEqualTo(ELIGIBLE_ACCOUNT_1_OPT_IN);
+
+        assertThat(accountsParcel[1].account).isEqualTo(ELIGIBLE_ACCOUNT_2);
+        assertThat(accountsParcel[1].optIn).isEqualTo(ELIGIBLE_ACCOUNT_2_OPT_IN);
     }
 }
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceParcelableTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceParcelableTest.java
index 16cab99..081626b 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceParcelableTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceParcelableTest.java
@@ -23,7 +23,8 @@
 import android.os.Build;
 
 import androidx.annotation.RequiresApi;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,6 +37,7 @@
 
     /** Verify toString returns expected string. */
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testToString() {
         NearbyDeviceParcelable nearbyDeviceParcelable =  new NearbyDeviceParcelable.Builder()
                 .setName("testDevice")
@@ -53,6 +55,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_defaultNullFields() {
         NearbyDeviceParcelable nearbyDeviceParcelable =  new NearbyDeviceParcelable.Builder()
                 .setMedium(NearbyDevice.Medium.BLE)
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceTest.java
index b7a4690..aad3fca 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyDeviceTest.java
@@ -24,7 +24,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import androidx.annotation.RequiresApi;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,6 +36,7 @@
 public class NearbyDeviceTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isValidMedium() {
         assertThat(NearbyDevice.isValidMedium(1)).isTrue();
         assertThat(NearbyDevice.isValidMedium(2)).isTrue();
@@ -44,6 +46,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getMedium_fromChild() {
         FastPairDevice fastPairDevice = new FastPairDevice.Builder()
                 .setMedium(NearbyDevice.Medium.BLE)
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
index c062e84..370bfe1 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
@@ -16,12 +16,12 @@
 
 package android.nearby.cts;
 
-import android.annotation.TargetApi;
 import android.nearby.NearbyFrameworkInitializer;
 import android.os.Build;
 
 import androidx.annotation.RequiresApi;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,7 +29,6 @@
 // NearbyFrameworkInitializer was added in T
 @RunWith(AndroidJUnit4.class)
 @RequiresApi(Build.VERSION_CODES.TIRAMISU)
-@TargetApi(Build.VERSION_CODES.TIRAMISU)
 public class NearbyFrameworkInitializerTest {
 
 //    // TODO(b/215435710) This test cannot pass now because our test cannot access system API.
@@ -44,6 +43,7 @@
 
     // registerServiceWrappers can only be called during initialization and should throw otherwise
     @Test(expected = IllegalStateException.class)
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testThrowsException() {
         NearbyFrameworkInitializer.registerServiceWrappers();
     }
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
new file mode 100644
index 0000000..07e8558
--- /dev/null
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.content.Context;
+import android.nearby.NearbyDevice;
+import android.nearby.NearbyManager;
+import android.nearby.ScanCallback;
+import android.nearby.ScanRequest;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+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 org.mockito.Mock;
+
+import java.util.concurrent.Executors;
+
+/**
+ * TODO(b/215435939) This class doesn't include any logic yet. Because SELinux denies access to
+ * NearbyManager.
+ */
+@RunWith(AndroidJUnit4.class)
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class NearbyManagerTest {
+
+    @Mock Context mContext;
+    @Mock NearbyManager mNearbyManager;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+        when(mContext.getSystemService(Context.NEARBY_SERVICE)).thenReturn(mNearbyManager);
+    }
+
+    @Test
+    public void test_startAndStopScan() {
+        ScanRequest scanRequest = new ScanRequest.Builder()
+                .setScanType(ScanRequest.SCAN_TYPE_FAST_PAIR)
+                .setScanMode(ScanRequest.SCAN_MODE_LOW_LATENCY)
+                .setEnableBle(true)
+                .build();
+        ScanCallback scanCallback = new ScanCallback() {
+            @Override
+            public void onDiscovered(@NonNull NearbyDevice device) {
+            }
+
+            @Override
+            public void onUpdated(@NonNull NearbyDevice device) {
+
+            }
+
+            @Override
+            public void onLost(@NonNull NearbyDevice device) {
+
+            }
+        };
+        mNearbyManager.startScan(scanRequest, Executors.newSingleThreadExecutor(), scanCallback);
+        mNearbyManager.stopScan(scanCallback);
+    }
+}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/ScanRequestTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/ScanRequestTest.java
index a49444f..3bb348b 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/ScanRequestTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/ScanRequestTest.java
@@ -27,21 +27,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.annotation.TargetApi;
 import android.nearby.ScanRequest;
 import android.os.Build;
 import android.os.WorkSource;
 
 import androidx.annotation.RequiresApi;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-// NearbyFrameworkInitializer was added in T
 @RunWith(AndroidJUnit4.class)
 @RequiresApi(Build.VERSION_CODES.TIRAMISU)
-@TargetApi(Build.VERSION_CODES.TIRAMISU)
 public class ScanRequestTest {
 
     private static final int UID = 1001;
@@ -49,11 +47,13 @@
 
     // Valid scan type must be set to one of ScanRequest#SCAN_TYPE_
     @Test(expected = IllegalStateException.class)
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testScanType_notSet_throwsException() {
         new ScanRequest.Builder().setScanMode(SCAN_MODE_BALANCED).build();
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testScanMode_defaultLowPower() {
         ScanRequest request = new ScanRequest.Builder()
                 .setScanType(SCAN_TYPE_FAST_PAIR)
@@ -64,6 +64,7 @@
 
     /** Verify setting work source with null value in the scan request is allowed*/
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testSetWorkSource_nullValue() {
         ScanRequest request = new ScanRequest.Builder()
                 .setScanType(SCAN_TYPE_EXPOSURE_NOTIFICATION)
@@ -76,6 +77,7 @@
 
     /** Verify toString returns expected string. */
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testToString() {
         WorkSource workSource = getWorkSource();
         ScanRequest request = new ScanRequest.Builder()
@@ -87,20 +89,24 @@
 
         assertThat(request.toString()).isEqualTo(
                 "Request[scanType=2, scanMode=SCAN_MODE_BALANCED, "
-                        + "enableBle=true, workSource=WorkSource{" + UID + " " + APP_NAME + "}]");
+                        + "enableBle=true, workSource=WorkSource{" + UID + " " + APP_NAME
+                        + "}, scanFilters=[]]");
     }
 
     /** Verify toString works correctly with null WorkSource. */
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testToString_nullWorkSource() {
         ScanRequest request = new ScanRequest.Builder().setScanType(
                 SCAN_TYPE_FAST_PAIR).setWorkSource(null).build();
 
         assertThat(request.toString()).isEqualTo("Request[scanType=1, "
-                + "scanMode=SCAN_MODE_LOW_POWER, enableBle=true, workSource=WorkSource{}]");
+                + "scanMode=SCAN_MODE_LOW_POWER, enableBle=true, workSource=WorkSource{}, "
+                + "scanFilters=[]]");
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testisEnableBle_defaultTrue() {
         ScanRequest request = new ScanRequest.Builder()
                 .setScanType(SCAN_TYPE_FAST_PAIR)
@@ -110,6 +116,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isValidScanType() {
         assertThat(ScanRequest.isValidScanType(SCAN_TYPE_FAST_PAIR)).isTrue();
         assertThat(ScanRequest.isValidScanType(SCAN_TYPE_NEARBY_SHARE)).isTrue();
@@ -121,6 +128,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isValidScanMode() {
         assertThat(ScanRequest.isValidScanMode(SCAN_MODE_LOW_LATENCY)).isTrue();
         assertThat(ScanRequest.isValidScanMode(SCAN_MODE_BALANCED)).isTrue();
@@ -132,6 +140,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_scanModeToString() {
         assertThat(ScanRequest.scanModeToString(2)).isEqualTo("SCAN_MODE_LOW_LATENCY");
         assertThat(ScanRequest.scanModeToString(1)).isEqualTo("SCAN_MODE_BALANCED");
diff --git a/nearby/tests/unit/AndroidTest.xml b/nearby/tests/unit/AndroidTest.xml
index 8b08abb..9124a07 100644
--- a/nearby/tests/unit/AndroidTest.xml
+++ b/nearby/tests/unit/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="NearbyUnitTests" />
     <option name="config-descriptor:metadata" key="mainline-param"
-            value="com.google.android.nearby.apex" />
+            value="com.google.android.tethering.apex" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.nearby.test" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
@@ -32,6 +32,6 @@
     <!-- Only run NearbyUnitTests in MTS if the Nearby Mainline module is installed. -->
     <object type="module_controller"
             class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.nearby" />
+        <option name="mainline-module-package-name" value="com.google.android.tethering" />
     </object>
 </configuration>
diff --git a/nearby/tests/unit/src/android/nearby/ScanRequestTest.java b/nearby/tests/unit/src/android/nearby/ScanRequestTest.java
index fdb6db1..509fa1e 100644
--- a/nearby/tests/unit/src/android/nearby/ScanRequestTest.java
+++ b/nearby/tests/unit/src/android/nearby/ScanRequestTest.java
@@ -114,7 +114,8 @@
 
         assertThat(request.toString()).isEqualTo(
                 "Request[scanType=2, scanMode=SCAN_MODE_BALANCED, "
-                        + "enableBle=true, workSource=WorkSource{1001 android.nearby.tests}]");
+                        + "enableBle=true, workSource=WorkSource{1001 android.nearby.tests}, "
+                        + "scanFilters=[]]");
     }
 
     /** Verify toString works correctly with null WorkSource. */
@@ -124,7 +125,8 @@
                 SCAN_TYPE_FAST_PAIR).setWorkSource(null).build();
 
         assertThat(request.toString()).isEqualTo("Request[scanType=1, "
-                + "scanMode=SCAN_MODE_LOW_POWER, enableBle=true, workSource=WorkSource{}]");
+                + "scanMode=SCAN_MODE_LOW_POWER, enableBle=true, workSource=WorkSource{}, "
+                + "scanFilters=[]]");
     }
 
     /** Verify writing and reading from parcel for scan request. */
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/ble/BleRecordTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/ble/BleRecordTest.java
index 56ac1b8..f4aff1d 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/ble/BleRecordTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/ble/BleRecordTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import androidx.test.filters.SdkSuppress;
+
 import org.junit.Test;
 
 /** Test for Bluetooth LE {@link BleRecord}. */
@@ -215,6 +217,7 @@
     };
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testEquals() {
         BleRecord record = BleRecord.parseFromBytes(BEACON);
         BleRecord record2 = BleRecord.parseFromBytes(SAME_BEACON);
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AccountKeyGeneratorTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AccountKeyGeneratorTest.java
index 6b3ed2e..35a45c0 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AccountKeyGeneratorTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AccountKeyGeneratorTest.java
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -38,6 +39,7 @@
 @RunWith(AndroidJUnit4.class)
 public class AccountKeyGeneratorTest {
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void createAccountKey() throws NoSuchAlgorithmException {
         byte[] accountKey = AccountKeyGenerator.createAccountKey();
 
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AdditionalDataEncoderTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AdditionalDataEncoderTest.java
index 0273af9..28d2fca 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AdditionalDataEncoderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AdditionalDataEncoderTest.java
@@ -29,6 +29,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -45,6 +46,7 @@
 public class AdditionalDataEncoderTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decodeEncodedAdditionalDataPacket_mustGetSameRawData()
             throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
@@ -60,6 +62,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToEncode_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         byte[] rawData = base16().decode("00112233445566778899AABBCCDDEEFF");
@@ -75,6 +78,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToDecode_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         byte[] packet = base16().decode("01234567890123456789");
@@ -90,6 +94,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTooSmallPacketSize_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH];
         byte[] packet = new byte[EXTRACT_HMAC_SIZE - 1];
@@ -103,6 +108,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTooLargePacketSize_mustThrowException() throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] packet = new byte[MAX_LENGTH_OF_DATA + EXTRACT_HMAC_SIZE + NONCE_SIZE + 1];
@@ -116,6 +122,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectHmacToDecode_mustThrowException() throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] rawData = base16().decode("00112233445566778899AABBCCDDEEFF");
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesCtrMultipleBlockEncryptionTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesCtrMultipleBlockEncryptionTest.java
index 50f826d..7d86037 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesCtrMultipleBlockEncryptionTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesCtrMultipleBlockEncryptionTest.java
@@ -29,6 +29,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -45,6 +46,7 @@
 public class AesCtrMultipleBlockEncryptionTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decryptEncryptedData_nonBlockSizeAligned_mustEqualToPlaintext() throws Exception {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] plaintext = "Someone's Google Headphone 2019".getBytes(UTF_8); // The length is 31.
@@ -56,6 +58,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decryptEncryptedData_blockSizeAligned_mustEqualToPlaintext() throws Exception {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] plaintext =
@@ -69,6 +72,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void generateNonceTwice_mustBeDifferent() {
         byte[] nonce1 = AesCtrMultipleBlockEncryption.generateNonce();
         byte[] nonce2 = AesCtrMultipleBlockEncryption.generateNonce();
@@ -77,6 +81,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void encryptedSamePlaintext_mustBeDifferentEncryptedResult() throws Exception {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] plaintext = "Someone's Google Headphone 2019".getBytes(UTF_8);
@@ -88,6 +93,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void encryptData_mustBeDifferentToUnencrypted() throws Exception {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] plaintext = "Someone's Google Headphone 2019".getBytes(UTF_8);
@@ -98,6 +104,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToEncrypt_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH + 1];
         byte[] plaintext = "Someone's Google Headphone 2019".getBytes(UTF_8);
@@ -113,6 +120,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToDecrypt_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         byte[] plaintext = "Someone's Google Headphone 2019".getBytes(UTF_8);
@@ -128,6 +136,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectDataSizeToDecrypt_mustThrowException()
             throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
@@ -147,6 +156,7 @@
     // Add some random tests that for a certain amount of random plaintext of random length to prove
     // our encryption/decryption is correct. This is suggested by security team.
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decryptEncryptedRandomDataForCertainAmount_mustEqualToOriginalData()
             throws Exception {
         SecureRandom random = new SecureRandom();
@@ -166,6 +176,7 @@
     // Add some random tests that for a certain amount of random plaintext of random length to prove
     // our encryption is correct. This is suggested by security team.
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void twoDistinctEncryptionOnSameRandomData_mustBeDifferentResult() throws Exception {
         SecureRandom random = new SecureRandom();
         for (int i = 0; i < 1000; i++) {
@@ -184,6 +195,7 @@
     // Adds this test example on spec. Also we can easily change the parameters(e.g. secret, data,
     // nonce) to clarify test results with partners.
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTestExampleToEncrypt_getCorrectResult() throws GeneralSecurityException {
         byte[] secret = base16().decode("0123456789ABCDEF0123456789ABCDEF");
         byte[] nonce = base16().decode("0001020304050607");
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesEcbSingleBlockEncryptionTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesEcbSingleBlockEncryptionTest.java
index b1f5148..eccbd01 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesEcbSingleBlockEncryptionTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/AesEcbSingleBlockEncryptionTest.java
@@ -22,6 +22,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.google.common.primitives.Bytes;
@@ -38,6 +39,7 @@
     private static final byte[] PLAINTEXT = base16().decode("F30F4E786C59A7BBF3873B5A49BA97EA");
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void encryptDecryptSuccessful() throws Exception {
         byte[] secret = AesEcbSingleBlockEncryption.generateKey();
         byte[] encrypted = AesEcbSingleBlockEncryption.encrypt(secret, PLAINTEXT);
@@ -47,6 +49,7 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void encryptionSizeLimitationEnforced() throws Exception {
         byte[] secret = AesEcbSingleBlockEncryption.generateKey();
         byte[] largePacket = Bytes.concat(PLAINTEXT, PLAINTEXT);
@@ -54,6 +57,7 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decryptionSizeLimitationEnforced() throws Exception {
         byte[] secret = AesEcbSingleBlockEncryption.generateKey();
         byte[] largePacket = Bytes.concat(PLAINTEXT, PLAINTEXT);
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothAddressTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothAddressTest.java
index fa0a890..6c95558 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothAddressTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothAddressTest.java
@@ -22,6 +22,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -34,28 +35,33 @@
 public class BluetoothAddressTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void maskBluetoothAddress_whenInputIsNull() {
         assertThat(BluetoothAddress.maskBluetoothAddress(null)).isEqualTo("");
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void maskBluetoothAddress_whenInputStringNotMatchFormat() {
         assertThat(BluetoothAddress.maskBluetoothAddress("AA:BB:CC")).isEqualTo("AA:BB:CC");
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void maskBluetoothAddress_whenInputStringMatchFormat() {
         assertThat(BluetoothAddress.maskBluetoothAddress("AA:BB:CC:DD:EE:FF"))
                 .isEqualTo("XX:XX:XX:XX:EE:FF");
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void maskBluetoothAddress_whenInputStringContainLowerCaseMatchFormat() {
         assertThat(BluetoothAddress.maskBluetoothAddress("Aa:Bb:cC:dD:eE:Ff"))
                 .isEqualTo("XX:XX:XX:XX:EE:FF");
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void maskBluetoothAddress_whenInputBluetoothDevice() {
         assertThat(
                 BluetoothAddress.maskBluetoothAddress(
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothUuidsTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothUuidsTest.java
index dbb01f2..fa977ed 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothUuidsTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/BluetoothUuidsTest.java
@@ -21,6 +21,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -47,23 +48,27 @@
             UUID.fromString("FE2C9487-8366-4814-8EB0-01DE32100BEA");
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void get16BitUuid() {
         assertThat(BluetoothUuids.get16BitUuid(A2DP_SINK_CHARACTERISTICS))
                 .isEqualTo(A2DP_SINK_SHORT_UUID);
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void is16BitUuid() {
         assertThat(BluetoothUuids.is16BitUuid(A2DP_SINK_CHARACTERISTICS)).isTrue();
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void to128BitUuid() {
         assertThat(BluetoothUuids.to128BitUuid(A2DP_SINK_SHORT_UUID))
                 .isEqualTo(A2DP_SINK_CHARACTERISTICS);
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void toFastPair128BitUuid() {
         assertThat(BluetoothUuids.toFastPair128BitUuid(CUSTOM_SHORT_UUID))
                 .isEqualTo(CUSTOM_CHARACTERISTICS);
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/ConstantsTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/ConstantsTest.java
index a0933a9..f7ffa24 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/ConstantsTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/ConstantsTest.java
@@ -27,6 +27,8 @@
 
 import android.bluetooth.BluetoothGattCharacteristic;
 
+import androidx.test.filters.SdkSuppress;
+
 import com.android.server.nearby.common.bluetooth.BluetoothException;
 import com.android.server.nearby.common.bluetooth.fastpair.Constants.FastPairService.KeyBasedPairingCharacteristic;
 import com.android.server.nearby.common.bluetooth.gatt.BluetoothGattConnection;
@@ -56,6 +58,7 @@
         initMocks(this);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getId_whenSupportNewCharacteristics() throws BluetoothException {
         when(mMockGattConnection.getCharacteristic(any(UUID.class), any(UUID.class)))
                 .thenReturn(new BluetoothGattCharacteristic(NEW_KEY_BASE_PAIRING_CHARACTERISTICS, 0,
@@ -65,6 +68,7 @@
                 .isEqualTo(NEW_KEY_BASE_PAIRING_CHARACTERISTICS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getId_whenNotSupportNewCharacteristics() throws BluetoothException {
         // {@link BluetoothGattConnection#getCharacteristic(UUID, UUID)} throws {@link
         // BluetoothException} if the characteristic not found .
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EllipticCurveDiffieHellmanExchangeTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EllipticCurveDiffieHellmanExchangeTest.java
index 94eba0e..3719783 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EllipticCurveDiffieHellmanExchangeTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EllipticCurveDiffieHellmanExchangeTest.java
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -44,6 +45,7 @@
 
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void generateCommonKey() throws Exception {
         EllipticCurveDiffieHellmanExchange bob = EllipticCurveDiffieHellmanExchange.create();
         EllipticCurveDiffieHellmanExchange alice = EllipticCurveDiffieHellmanExchange.create();
@@ -56,6 +58,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void generateCommonKey_withExistingPrivateKey() throws Exception {
         EllipticCurveDiffieHellmanExchange bob = EllipticCurveDiffieHellmanExchange.create();
         EllipticCurveDiffieHellmanExchange alice =
@@ -66,6 +69,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void generateCommonKey_soundcoreAntiSpoofingKey_generatedTooShort() throws Exception {
         // This soundcore device has a public key that was generated which starts with 0x0. This was
         // stripped out in our database, but this test confirms that adding that byte back fixes the
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EventTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EventTest.java
index d3867f0..28e925f 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EventTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/EventTest.java
@@ -24,6 +24,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.nearby.intdefs.NearbyEventIntDefs.EventCode;
@@ -47,6 +48,7 @@
     private static final Short PROFILE = (short) 1;
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void createAndReadFromParcel() {
         Event event =
                 Event.builder()
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/FastPairHistoryItemTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/FastPairHistoryItemTest.java
index 072fe00..b47fd89 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/FastPairHistoryItemTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/FastPairHistoryItemTest.java
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.google.common.hash.Hashing;
@@ -40,6 +41,7 @@
 public class FastPairHistoryItemTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputMatchedPublicAddress_isMatchedReturnTrue() {
         final byte[] accountKey = base16().decode("0123456789ABCDEF");
         final byte[] publicAddress = BluetoothAddress.decode("11:22:33:44:55:66");
@@ -54,6 +56,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputNotMatchedPublicAddress_isMatchedReturnFalse() {
         final byte[] accountKey = base16().decode("0123456789ABCDEF");
         final byte[] publicAddress1 = BluetoothAddress.decode("11:22:33:44:55:66");
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HeadsetPieceTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HeadsetPieceTest.java
index ff69a57..670b2ca 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HeadsetPieceTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HeadsetPieceTest.java
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -37,6 +38,7 @@
 public class HeadsetPieceTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void parcelAndUnparcel() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
         Parcel expectedParcel = Parcel.obtain();
@@ -49,6 +51,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void parcelAndUnparcel_nullImageContentUri() {
         HeadsetPiece headsetPiece = createDefaultHeadset().setImageContentUri(null).build();
         Parcel expectedParcel = Parcel.obtain();
@@ -61,6 +64,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void equals() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -70,6 +74,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void equals_nullImageContentUri() {
         HeadsetPiece headsetPiece = createDefaultHeadset().setImageContentUri(null).build();
 
@@ -79,6 +84,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_differentLowLevelThreshold() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -88,6 +94,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_differentBatteryLevel() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -97,6 +104,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_differentImageUrl() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -107,6 +115,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_differentChargingState() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -116,6 +125,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_differentImageContentUri() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -127,6 +137,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notEquals_nullImageContentUri() {
         HeadsetPiece headsetPiece = createDefaultHeadset().build();
 
@@ -145,6 +156,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void isLowBattery() {
         HeadsetPiece headsetPiece =
                 HeadsetPiece.builder()
@@ -158,6 +170,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void isNotLowBattery() {
         HeadsetPiece headsetPiece =
                 HeadsetPiece.builder()
@@ -171,6 +184,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void isNotLowBattery_whileCharging() {
         HeadsetPiece headsetPiece =
                 HeadsetPiece.builder()
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HmacSha256Test.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HmacSha256Test.java
index f5f2988..8db3b97 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HmacSha256Test.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/HmacSha256Test.java
@@ -28,6 +28,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.google.common.base.Preconditions;
@@ -53,6 +54,7 @@
     private static final byte INNER_PADDING_BYTE = 0x36;
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void compareResultWithOurImplementation_mustBeIdentical()
             throws GeneralSecurityException {
         Random random = new Random(0xFE2C);
@@ -69,6 +71,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToDecrypt_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         byte[] data = base16().decode("1234567890ABCDEF1234567890ABCDEF1234567890ABCD");
@@ -82,6 +85,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTwoIdenticalArrays_compareTwoHmacMustReturnTrue() {
         Random random = new Random(0x1237);
         byte[] array1 = new byte[EXTRACT_HMAC_SIZE];
@@ -92,6 +96,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTwoRandomArrays_compareTwoHmacMustReturnFalse() {
         Random random = new Random(0xff);
         byte[] array1 = new byte[EXTRACT_HMAC_SIZE];
@@ -132,6 +137,7 @@
     // Adds this test example on spec. Also we can easily change the parameters(e.g. secret, data)
     // to clarify test results with partners.
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTestExampleToHmacSha256_getCorrectResult() {
         byte[] secret = base16().decode("0123456789ABCDEF0123456789ABCDEF");
         byte[] data =
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/MessageStreamHmacEncoderTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/MessageStreamHmacEncoderTest.java
index 9a7c430..d4c3342 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/MessageStreamHmacEncoderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/MessageStreamHmacEncoderTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.nearby.common.bluetooth.fastpair;
 
-
 import static com.android.server.nearby.common.bluetooth.fastpair.MessageStreamHmacEncoder.EXTRACT_HMAC_SIZE;
 import static com.android.server.nearby.common.bluetooth.fastpair.MessageStreamHmacEncoder.SECTION_NONCE_LENGTH;
 
@@ -26,6 +25,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -46,6 +46,7 @@
     private static final int ACCOUNT_KEY_LENGTH = 16;
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void encodeMessagePacket() throws GeneralSecurityException {
         int messageLength = 2;
         SecureRandom secureRandom = new SecureRandom();
@@ -76,6 +77,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void verifyHmac() throws GeneralSecurityException {
         int messageLength = 2;
         SecureRandom secureRandom = new SecureRandom();
@@ -92,6 +94,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void verifyHmac_failedByAccountKey() throws GeneralSecurityException {
         int messageLength = 2;
         SecureRandom secureRandom = new SecureRandom();
@@ -109,6 +112,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void verifyHmac_failedBySectionNonce() throws GeneralSecurityException {
         int messageLength = 2;
         SecureRandom secureRandom = new SecureRandom();
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/NamingEncoderTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/NamingEncoderTest.java
index 9e3f3da..d66d209 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/NamingEncoderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/NamingEncoderTest.java
@@ -29,6 +29,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -45,6 +46,7 @@
 public class NamingEncoderTest {
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decodeEncodedNamingPacket_mustGetSameName() throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         String name = "Someone's Google Headphone";
@@ -55,6 +57,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToEncode_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         String data = "Someone's Google Headphone";
@@ -69,6 +72,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectKeySizeToDecode_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH - 1];
         byte[] data = new byte[50];
@@ -83,6 +87,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTooSmallPacketSize_mustThrowException() {
         byte[] secret = new byte[KEY_LENGTH];
         byte[] data = new byte[EXTRACT_HMAC_SIZE - 1];
@@ -96,6 +101,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputTooLargePacketSize_mustThrowException() throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         byte[] namingPacket = new byte[MAX_LENGTH_OF_NAME + EXTRACT_HMAC_SIZE + NONCE_SIZE + 1];
@@ -109,6 +115,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void inputIncorrectHmacToDecode_mustThrowException() throws GeneralSecurityException {
         byte[] secret = AesCtrMultipleBlockEncryption.generateKey();
         String name = "Someone's Google Headphone";
@@ -129,6 +136,7 @@
     // Adds this test example on spec. Also we can easily change the parameters(e.g. secret, naming
     // packet) to clarify test results with partners.
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void decodeTestNamingPacket_mustGetSameName() throws GeneralSecurityException {
         byte[] secret = base16().decode("0123456789ABCDEF0123456789ABCDEF");
         byte[] namingPacket = base16().decode(
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/TimingLoggerTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/TimingLoggerTest.java
index ded1fb7..4672905 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/TimingLoggerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/fastpair/TimingLoggerTest.java
@@ -22,6 +22,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.nearby.common.bluetooth.fastpair.TimingLogger.ScopedTiming;
@@ -30,7 +31,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 /**
  * Unit tests for {@link TimingLogger}.
  */
@@ -42,6 +42,7 @@
     private final Preferences mPrefs = Preferences.builder().setEvaluatePerformance(true).build();
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void logPairedTiming() {
         String label = "start";
         TimingLogger timingLogger = new TimingLogger("paired", mPrefs);
@@ -65,6 +66,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void logScopedTiming() {
         String label = "scopedTiming";
         TimingLogger timingLogger = new TimingLogger("scoped", mPrefs);
@@ -88,6 +90,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void logOrderedTiming() {
         String label1 = "t1";
         String label2 = "t2";
@@ -128,6 +131,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void logNestedTiming() {
         String labelOuter = "outer";
         String labelInner1 = "inner1";
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattConnectionTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattConnectionTest.java
index 13802ee..80bde63 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattConnectionTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattConnectionTest.java
@@ -39,6 +39,8 @@
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 
+import androidx.test.filters.SdkSuppress;
+
 import com.android.server.nearby.common.bluetooth.BluetoothConsts;
 import com.android.server.nearby.common.bluetooth.BluetoothException;
 import com.android.server.nearby.common.bluetooth.BluetoothGattException;
@@ -164,12 +166,14 @@
         when(mMockBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getDevice() {
         BluetoothDevice result = mBluetoothGattConnection.getDevice();
 
         assertThat(result).isEqualTo(mMockBluetoothDevice);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getConnectionOptions() {
         BluetoothGattHelper.ConnectionOptions result = mBluetoothGattConnection
                 .getConnectionOptions();
@@ -177,6 +181,7 @@
         assertThat(result).isSameInstanceAs(CONNECTION_OPTIONS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isConnected_false_beforeConnection() {
         mBluetoothGattConnection = new BluetoothGattConnection(
                 mMockBluetoothGattWrapper,
@@ -188,12 +193,14 @@
         assertThat(result).isFalse();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isConnected_true_afterConnection() {
         boolean result = mBluetoothGattConnection.isConnected();
 
         assertThat(result).isTrue();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_isConnected_false_afterDisconnection() {
         mBluetoothGattConnection.onClosed();
 
@@ -202,6 +209,7 @@
         assertThat(result).isFalse();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getService_notDiscovered() throws Exception {
         BluetoothGattService result = mBluetoothGattConnection.getService(SERVICE_UUID);
         verify(mMockBluetoothOperationExecutor).execute(mSynchronousOperationCaptor.capture());
@@ -216,6 +224,7 @@
         verify(mMockBluetoothGattWrapper).discoverServices();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getService_alreadyDiscovered() throws Exception {
         mBluetoothGattConnection.getService(SERVICE_UUID);
         verify(mMockBluetoothOperationExecutor).execute(mSynchronousOperationCaptor.capture());
@@ -229,6 +238,7 @@
         verifyNoMoreInteractions(mMockBluetoothOperationExecutor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getService_notFound() throws Exception {
         when(mMockBluetoothGattWrapper.getServices()).thenReturn(
                 Arrays.<BluetoothGattService>asList());
@@ -240,6 +250,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getService_moreThanOne() throws Exception {
         when(mMockBluetoothGattWrapper.getServices())
                 .thenReturn(Arrays.asList(mMockBluetoothGattService, mMockBluetoothGattService));
@@ -251,6 +262,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getCharacteristic() throws Exception {
         BluetoothGattCharacteristic result =
                 mBluetoothGattConnection.getCharacteristic(SERVICE_UUID, CHARACTERISTIC_UUID);
@@ -258,6 +270,7 @@
         assertThat(result).isEqualTo(mMockBluetoothGattCharacteristic);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getCharacteristic_notFound() throws Exception {
         when(mMockBluetoothGattService.getCharacteristics())
                 .thenReturn(Arrays.<BluetoothGattCharacteristic>asList());
@@ -269,6 +282,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getCharacteristic_moreThanOne() throws Exception {
         when(mMockBluetoothGattService.getCharacteristics())
                 .thenReturn(
@@ -282,6 +296,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getCharacteristic_moreThanOneService() throws Exception {
         // Add a new service with the same service UUID as our existing one, but add a different
         // characteristic inside of it.
@@ -303,6 +318,7 @@
         mBluetoothGattConnection.getCharacteristic(SERVICE_UUID, CHARACTERISTIC_UUID);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getDescriptor() throws Exception {
         when(mMockBluetoothGattCharacteristic.getDescriptors())
                 .thenReturn(Arrays.asList(mMockBluetoothGattDescriptor));
@@ -314,6 +330,7 @@
         assertThat(result).isEqualTo(mMockBluetoothGattDescriptor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getDescriptor_notFound() throws Exception {
         when(mMockBluetoothGattCharacteristic.getDescriptors())
                 .thenReturn(Arrays.<BluetoothGattDescriptor>asList());
@@ -326,6 +343,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getDescriptor_moreThanOne() throws Exception {
         when(mMockBluetoothGattCharacteristic.getDescriptors())
                 .thenReturn(
@@ -339,6 +357,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<>(
@@ -358,6 +377,7 @@
         verify(mMockBluetoothGattWrapper, never()).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices_serviceChange() throws Exception {
         when(mMockBluetoothGattWrapper.getService(ReservedUuids.Services.GENERIC_ATTRIBUTE))
                 .thenReturn(mMockBluetoothGattService);
@@ -376,6 +396,7 @@
         verify(mMockBluetoothGattWrapper).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices_SelfDefinedServiceDynamic() throws Exception {
         when(mMockBluetoothGattWrapper.getService(BluetoothConsts.SERVICE_DYNAMIC_SERVICE))
                 .thenReturn(mMockBluetoothGattService);
@@ -394,6 +415,7 @@
         verify(mMockBluetoothGattWrapper).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices_refreshWithGattErrorOnMncAbove() throws Exception {
         if (VERSION.SDK_INT <= VERSION_CODES.LOLLIPOP_MR1) {
             return;
@@ -414,6 +436,7 @@
         verify(mMockBluetoothGattWrapper).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices_refreshWithGattInternalErrorOnMncAbove() throws Exception {
         if (VERSION.SDK_INT <= VERSION_CODES.LOLLIPOP_MR1) {
             return;
@@ -434,6 +457,7 @@
         verify(mMockBluetoothGattWrapper).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_discoverServices_dynamicServices_notBonded() throws Exception {
         when(mMockBluetoothGattWrapper.getService(ReservedUuids.Services.GENERIC_ATTRIBUTE))
                 .thenReturn(mMockBluetoothGattService);
@@ -447,6 +471,7 @@
         verify(mMockBluetoothGattWrapper, never()).refresh();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_readCharacteristic() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<byte[]>(
@@ -466,6 +491,7 @@
         verify(mMockBluetoothGattWrapper).readCharacteristic(mMockBluetoothGattCharacteristic);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_readCharacteristic_by_uuid() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<byte[]>(
@@ -485,6 +511,7 @@
         verify(mMockBluetoothGattWrapper).readCharacteristic(mMockBluetoothGattCharacteristic);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_writeCharacteristic() throws Exception {
         BluetoothGattCharacteristic characteristic =
                 new BluetoothGattCharacteristic(
@@ -502,6 +529,7 @@
         assertThat(writtenCharacteristic).isEqualTo(characteristic);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_writeCharacteristic_by_uuid() throws Exception {
         mBluetoothGattConnection.writeCharacteristic(SERVICE_UUID, CHARACTERISTIC_UUID, DATA);
 
@@ -515,6 +543,7 @@
         assertThat(writtenCharacteristic.getUuid()).isEqualTo(CHARACTERISTIC_UUID);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_readDescriptor() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<byte[]>(
@@ -532,6 +561,7 @@
         verify(mMockBluetoothGattWrapper).readDescriptor(mMockBluetoothGattDescriptor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_readDescriptor_by_uuid() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<byte[]>(
@@ -551,6 +581,7 @@
         verify(mMockBluetoothGattWrapper).readDescriptor(mMockBluetoothGattDescriptor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_writeDescriptor() throws Exception {
         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0);
         mBluetoothGattConnection.writeDescriptor(descriptor, DATA);
@@ -565,6 +596,7 @@
         assertThat(writtenDescriptor).isEqualTo(descriptor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_writeDescriptor_by_uuid() throws Exception {
         mBluetoothGattConnection.writeDescriptor(
                 SERVICE_UUID, CHARACTERISTIC_UUID, DESCRIPTOR_UUID, DATA);
@@ -578,6 +610,7 @@
         assertThat(writtenDescriptor.getUuid()).isEqualTo(DESCRIPTOR_UUID);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_readRemoteRssi() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<Integer>(OperationType.READ_RSSI, mMockBluetoothGattWrapper),
@@ -595,12 +628,14 @@
         verify(mMockBluetoothGattWrapper).readRemoteRssi();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getMaxDataPacketSize() throws Exception {
         int result = mBluetoothGattConnection.getMaxDataPacketSize();
 
         assertThat(result).isEqualTo(mBluetoothGattConnection.getMtu() - 3);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testSetNotificationEnabled_indication_enable() throws Exception {
         when(mMockBluetoothGattCharacteristic.getProperties())
                 .thenReturn(BluetoothGattCharacteristic.PROPERTY_INDICATE);
@@ -618,6 +653,7 @@
                 .isEqualTo(ReservedUuids.Descriptors.CLIENT_CHARACTERISTIC_CONFIGURATION);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_getNotificationEnabled_notification_enable() throws Exception {
         mBluetoothGattConnection.setNotificationEnabled(mMockBluetoothGattCharacteristic, true);
 
@@ -632,6 +668,7 @@
                 .isEqualTo(ReservedUuids.Descriptors.CLIENT_CHARACTERISTIC_CONFIGURATION);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_setNotificationEnabled_indication_disable() throws Exception {
         when(mMockBluetoothGattCharacteristic.getProperties())
                 .thenReturn(BluetoothGattCharacteristic.PROPERTY_INDICATE);
@@ -649,6 +686,7 @@
                 .isEqualTo(ReservedUuids.Descriptors.CLIENT_CHARACTERISTIC_CONFIGURATION);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_setNotificationEnabled_notification_disable() throws Exception {
         mBluetoothGattConnection.setNotificationEnabled(mMockBluetoothGattCharacteristic, false);
 
@@ -663,6 +701,7 @@
                 .isEqualTo(ReservedUuids.Descriptors.CLIENT_CHARACTERISTIC_CONFIGURATION);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_setNotificationEnabled_failure() throws Exception {
         when(mMockBluetoothGattCharacteristic.getProperties())
                 .thenReturn(BluetoothGattCharacteristic.PROPERTY_READ);
@@ -675,6 +714,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_enableNotification_Uuid() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<>(
@@ -692,6 +732,7 @@
         verify(mMockCharChangeListener).onValueChange(DATA);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_enableNotification() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<>(
@@ -711,6 +752,7 @@
         verify(mMockCharChangeListener).onValueChange(DATA);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_enableNotification_observe() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<>(
@@ -728,6 +770,7 @@
         assertThat(changeObserver.waitForUpdate(TimeUnit.SECONDS.toMillis(1))).isEqualTo(DATA);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_disableNotification_Uuid() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<>(
@@ -743,6 +786,7 @@
         verify(mMockCharChangeListener, never()).onValueChange(DATA);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_disableNotification() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new SynchronousOperation<ChangeObserver>(
@@ -763,6 +807,7 @@
         verify(mMockCharChangeListener, never()).onValueChange(DATA);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_addCloseListener() throws Exception {
         mBluetoothGattConnection.addCloseListener(mMockConnectionCloseListener);
 
@@ -770,6 +815,7 @@
         verify(mMockConnectionCloseListener).onClose();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_removeCloseListener() throws Exception {
         mBluetoothGattConnection.addCloseListener(mMockConnectionCloseListener);
 
@@ -779,6 +825,7 @@
         verify(mMockConnectionCloseListener, never()).onClose();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_close() throws Exception {
         mBluetoothGattConnection.close();
 
@@ -790,6 +837,7 @@
         verify(mMockBluetoothGattWrapper).close();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_onClosed() throws Exception {
         mBluetoothGattConnection.onClosed();
 
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattHelperTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattHelperTest.java
index 60cac57..7c20be1 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattHelperTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/gatt/BluetoothGattHelperTest.java
@@ -42,6 +42,8 @@
 import android.os.ParcelUuid;
 import android.test.mock.MockContext;
 
+import androidx.test.filters.SdkSuppress;
+
 import com.android.server.nearby.common.bluetooth.BluetoothException;
 import com.android.server.nearby.common.bluetooth.gatt.BluetoothGattHelper.ConnectionOptions;
 import com.android.server.nearby.common.bluetooth.gatt.BluetoothGattHelper.OperationType;
@@ -144,6 +146,7 @@
                 .thenReturn(ConnectionOptions.builder().build());
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_success_lowLatency() throws Exception {
         BluetoothGattConnection result = mBluetoothGattHelper.autoConnect(SERVICE_UUID);
 
@@ -163,6 +166,7 @@
         verifyNoMoreInteractions(mMockBluetoothLeScanner);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_success_lowPower() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(SCANNING_OPERATION,
                 BluetoothGattHelper.LOW_LATENCY_SCAN_MILLIS)).thenThrow(
@@ -182,6 +186,7 @@
         verifyNoMoreInteractions(mMockBluetoothLeScanner);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_success_afterRetry() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<BluetoothGattConnection>(OperationType.CONNECT, mMockBluetoothDevice),
@@ -194,6 +199,7 @@
         assertThat(result).isEqualTo(mMockBluetoothGattConnection);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_failure_scanning() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(SCANNING_OPERATION,
                 BluetoothGattHelper.LOW_LATENCY_SCAN_MILLIS)).thenThrow(
@@ -207,6 +213,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_failure_connecting() throws Exception {
         when(mMockBluetoothOperationExecutor.executeNonnull(
                 new Operation<BluetoothGattConnection>(OperationType.CONNECT, mMockBluetoothDevice),
@@ -226,6 +233,7 @@
                         CONNECT_TIMEOUT_MILLIS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_autoConnect_uuid_failure_noBle() throws Exception {
         when(mMockBluetoothAdapter.getBluetoothLeScanner()).thenReturn(null);
 
@@ -237,6 +245,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_connect() throws Exception {
         BluetoothGattConnection result = mBluetoothGattHelper.connect(mMockBluetoothDevice);
 
@@ -251,6 +260,7 @@
                 .isEqualTo(mMockBluetoothDevice);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_connect_withOptionAutoConnect_success() throws Exception {
         BluetoothGattConnection result = mBluetoothGattHelper
                 .connect(
@@ -272,6 +282,7 @@
                         .build());
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_connect_withOptionAutoConnect_failure_nullResult() throws Exception {
         when(mMockBluetoothDevice.connectGatt(eq(mMockApplicationContext), anyBoolean(),
                 eq(mBluetoothGattHelper.mBluetoothGattCallback),
@@ -291,6 +302,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_connect_withOptionRequestConnectionPriority_success() throws Exception {
         // Operation succeeds on the 3rd try.
         when(mMockBluetoothGattWrapper
@@ -322,6 +334,7 @@
                 .requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_connect_cancel() throws Exception {
         mBluetoothGattHelper.connect(mMockBluetoothDevice);
 
@@ -336,6 +349,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_connected_success()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -352,6 +366,7 @@
         verify(mMockBluetoothGattConnection).onConnected();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_connected_success_withMtuOption()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -371,6 +386,7 @@
         verify(mMockBluetoothGattWrapper).requestMtu(MTU);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_connected_success_failMtuOption()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -394,6 +410,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_connected_unexpectedSuccess()
             throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onConnectionStateChange(
@@ -403,6 +420,7 @@
         verifyZeroInteractions(mMockBluetoothOperationExecutor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_connected_failure()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -424,6 +442,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_disconnected_unexpectedSuccess()
             throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback
@@ -435,6 +454,7 @@
         verifyZeroInteractions(mMockBluetoothOperationExecutor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_disconnected_notConnected()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -457,6 +477,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_disconnected_success()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -474,6 +495,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onConnectionStateChange_disconnected_failure()
             throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
@@ -491,6 +513,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onServicesDiscovered() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onServicesDiscovered(mMockBluetoothGattWrapper,
                 GATT_STATUS);
@@ -501,6 +524,7 @@
                 GATT_STATUS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onCharacteristicRead() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onCharacteristicRead(mMockBluetoothGattWrapper,
                 mMockBluetoothGattCharacteristic, GATT_STATUS);
@@ -511,6 +535,7 @@
                 GATT_STATUS, CHARACTERISTIC_VALUE);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onCharacteristicWrite() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onCharacteristicWrite(mMockBluetoothGattWrapper,
                 mMockBluetoothGattCharacteristic, GATT_STATUS);
@@ -521,6 +546,7 @@
                 GATT_STATUS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onDescriptorRead() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onDescriptorRead(mMockBluetoothGattWrapper,
                 mMockBluetoothGattDescriptor, GATT_STATUS);
@@ -532,6 +558,7 @@
                 DESCRIPTOR_VALUE);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onDescriptorWrite() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onDescriptorWrite(mMockBluetoothGattWrapper,
                 mMockBluetoothGattDescriptor, GATT_STATUS);
@@ -542,6 +569,7 @@
                 GATT_STATUS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onReadRemoteRssi() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onReadRemoteRssi(mMockBluetoothGattWrapper,
                 RSSI, GATT_STATUS);
@@ -551,6 +579,7 @@
                 GATT_STATUS, RSSI);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onReliableWriteCompleted() throws Exception {
         mBluetoothGattHelper.mBluetoothGattCallback.onReliableWriteCompleted(
                 mMockBluetoothGattWrapper,
@@ -561,6 +590,7 @@
                 GATT_STATUS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onMtuChanged() throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
                 mMockBluetoothGattConnection);
@@ -574,6 +604,7 @@
                 MTU);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testBluetoothGattCallback_onMtuChangedDuringConnection_success() throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
                 mMockBluetoothGattConnection);
@@ -590,6 +621,7 @@
                         mMockBluetoothGattConnection);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testBluetoothGattCallback_onMtuChangedDuringConnection_fail() throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
                 mMockBluetoothGattConnection);
@@ -609,6 +641,7 @@
         assertThat(mBluetoothGattHelper.mConnections.get(mMockBluetoothGattWrapper)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_BluetoothGattCallback_onCharacteristicChanged() throws Exception {
         mBluetoothGattHelper.mConnections.put(mMockBluetoothGattWrapper,
                 mMockBluetoothGattConnection);
@@ -622,6 +655,7 @@
                 CHARACTERISTIC_VALUE);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_ScanCallback_onScanFailed() throws Exception {
         mBluetoothGattHelper.mScanCallback.onScanFailed(ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
 
@@ -630,6 +664,7 @@
                 isA(BluetoothException.class));
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_ScanCallback_onScanResult() throws Exception {
         mBluetoothGattHelper.mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES,
                 mMockScanResult);
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothGattUtilsTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothGattUtilsTest.java
index 4f206c4..47182c3 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothGattUtilsTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothGattUtilsTest.java
@@ -24,6 +24,7 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import com.google.common.collect.ImmutableSet;
@@ -45,6 +46,7 @@
             "GATT_WRITE_REQUEST_BUSY", "GATT_WRITE_REQUEST_FAIL", "GATT_WRITE_REQUEST_SUCCESS");
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testGetMessageForStatusCode() throws Exception {
         Field[] publicFields = BluetoothGatt.class.getFields();
         for (Field field : publicFields) {
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothOperationExecutorTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothOperationExecutorTest.java
index 6d1450f..7b3ebab 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothOperationExecutorTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/util/BluetoothOperationExecutorTest.java
@@ -25,6 +25,8 @@
 
 import android.bluetooth.BluetoothGatt;
 
+import androidx.test.filters.SdkSuppress;
+
 import com.android.server.nearby.common.bluetooth.BluetoothException;
 import com.android.server.nearby.common.bluetooth.testability.NonnullProvider;
 import com.android.server.nearby.common.bluetooth.testability.TimeProvider;
@@ -89,6 +91,7 @@
                         mMockBlockingQueueProvider);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testExecute() throws Exception {
         when(mMockBlockingQueue.take()).thenReturn(OPERATION_RESULT);
 
@@ -98,6 +101,7 @@
         assertThat(result).isEqualTo(OPERATION_RESULT);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testExecuteWithTimeout() throws Exception {
         when(mMockBlockingQueue.poll(TIMEOUT, TimeUnit.MILLISECONDS)).thenReturn(OPERATION_RESULT);
 
@@ -107,6 +111,7 @@
         assertThat(result).isEqualTo(OPERATION_RESULT);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testSchedule() throws Exception {
         when(mMockBlockingQueue.poll(TIMEOUT, TimeUnit.MILLISECONDS)).thenReturn(OPERATION_RESULT);
 
@@ -116,6 +121,7 @@
         assertThat(result.get(TIMEOUT, TimeUnit.MILLISECONDS)).isEqualTo(OPERATION_RESULT);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testScheduleOtherOperationInProgress() throws Exception {
         when(mMockSemaphore.tryAcquire()).thenReturn(false);
         when(mMockBlockingQueue.poll(TIMEOUT, TimeUnit.MILLISECONDS)).thenReturn(OPERATION_RESULT);
@@ -130,6 +136,7 @@
         verify(mMockStringOperation).execute(mBluetoothOperationExecutor);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifySuccessWithResult() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<String> future = mBluetoothOperationExecutor.schedule(mMockStringOperation);
@@ -139,6 +146,7 @@
         assertThat(future.get(1, TimeUnit.MILLISECONDS)).isEqualTo(OPERATION_RESULT);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifySuccessTwice() throws Exception {
         BlockingQueue<Object> resultQueue = new LinkedBlockingDeque<Object>();
         when(mMockBlockingQueueProvider.get()).thenReturn(resultQueue);
@@ -153,6 +161,7 @@
         assertThat(resultQueue).isEmpty();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifySuccessWithNullResult() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<String> future = mBluetoothOperationExecutor.schedule(mMockStringOperation);
@@ -162,6 +171,7 @@
         assertThat(future.get(1, TimeUnit.MILLISECONDS)).isNull();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifySuccess() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<Void> future = mBluetoothOperationExecutor.schedule(mMockVoidOperation);
@@ -171,6 +181,7 @@
         future.get(1, TimeUnit.MILLISECONDS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifyCompletionSuccess() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<Void> future = mBluetoothOperationExecutor.schedule(mMockVoidOperation);
@@ -181,6 +192,7 @@
         future.get(1, TimeUnit.MILLISECONDS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifyCompletionFailure() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<Void> future = mBluetoothOperationExecutor.schedule(mMockVoidOperation);
@@ -196,6 +208,7 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testNotifyFailure() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(new LinkedBlockingDeque<Object>());
         Future<Void> future = mBluetoothOperationExecutor.schedule(mMockVoidOperation);
@@ -212,6 +225,7 @@
     }
 
     @SuppressWarnings("unchecked")
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testWaitFor() throws Exception {
         mBluetoothOperationExecutor.waitFor(Arrays.asList(mMockFuture, mMockFuture2));
 
@@ -220,6 +234,7 @@
     }
 
     @SuppressWarnings("unchecked")
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testWaitForWithTimeout() throws Exception {
         mBluetoothOperationExecutor.waitFor(
                 Arrays.asList(mMockFuture, mMockFuture2),
@@ -229,6 +244,7 @@
         verify(mMockFuture2).get(TIMEOUT, TimeUnit.MILLISECONDS);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testGetResult() throws Exception {
         when(mMockFuture.get()).thenReturn(OPERATION_RESULT);
 
@@ -237,6 +253,7 @@
         assertThat(result).isEqualTo(OPERATION_RESULT);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testGetResultWithTimeout() throws Exception {
         when(mMockFuture.get(TIMEOUT, TimeUnit.MILLISECONDS)).thenThrow(new TimeoutException());
 
@@ -249,6 +266,7 @@
         verify(mMockFuture).cancel(true);
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_SynchronousOperation_execute() throws Exception {
         when(mMockBlockingQueueProvider.get()).thenReturn(mMockBlockingQueue);
         SynchronousOperation<String> synchronousOperation = new SynchronousOperation<String>() {
@@ -265,6 +283,7 @@
         verify(mMockSemaphore).release();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_SynchronousOperation_exception() throws Exception {
         final BluetoothException exception = new BluetoothException(EXCEPTION_REASON);
         when(mMockBlockingQueueProvider.get()).thenReturn(mMockBlockingQueue);
@@ -282,6 +301,7 @@
         verify(mMockSemaphore).release();
     }
 
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void test_AsynchronousOperation_exception() throws Exception {
         final BluetoothException exception = new BluetoothException(EXCEPTION_REASON);
         when(mMockBlockingQueueProvider.get()).thenReturn(mMockBlockingQueue);
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/eventloop/EventLoopTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/eventloop/EventLoopTest.java
index 1af55b5..70dcec8 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/common/eventloop/EventLoopTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/eventloop/EventLoopTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import androidx.test.filters.SdkSuppress;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -48,6 +50,7 @@
     */
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void isPosted() {
         NumberedRunnable runnable = new NumberedRunnable(0);
         mEventLoop.postRunnableDelayed(runnable, 10 * 1000L);
@@ -61,6 +64,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void postAndWaitAfterDestroy() throws InterruptedException {
         mEventLoop.destroy();
         mEventLoop.postAndWait(new NumberedRunnable(0));
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairManagerTest.java
index bbf8cdf..f061115 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairManagerTest.java
@@ -22,6 +22,8 @@
 
 import android.content.Context;
 
+import androidx.test.filters.SdkSuppress;
+
 import com.android.server.nearby.common.locator.LocatorContextWrapper;
 
 import org.junit.Before;
@@ -43,6 +45,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testFastPairInit() {
         mFastPairManager.initiate();
 
@@ -50,6 +53,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testFastPairCleanUp() {
         mFastPairManager.cleanUp();
 
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/ModuleTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/ModuleTest.java
index fafd3b4..bb4e3d0 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/ModuleTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/ModuleTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
 
 import com.android.server.nearby.common.eventloop.EventLoop;
 import com.android.server.nearby.common.locator.Locator;
@@ -48,6 +49,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void genericConstructor() {
         assertThat(mLocator.get(FastPairCacheManager.class)).isNotNull();
         assertThat(mLocator.get(FootprintsDeviceManager.class)).isNotNull();
@@ -58,6 +60,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void genericDestroy() {
         mLocator.destroy();
     }
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
index ff98ecf..b8233ec 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 
 import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,6 +53,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void notSaveRetrieveInfo() {
         Context mContext = ApplicationProvider.getApplicationContext();
         when(mDiscoveryItem.getCopyOfStoredItem()).thenReturn(mStoredDiscoveryItem);
@@ -64,6 +66,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void saveRetrieveInfo() {
         Context mContext = ApplicationProvider.getApplicationContext();
         when(mDiscoveryItem.getCopyOfStoredItem()).thenReturn(mStoredDiscoveryItem);
@@ -76,6 +79,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void getAllInfo() {
         Context mContext = ApplicationProvider.getApplicationContext();
         when(mDiscoveryItem.getCopyOfStoredItem()).thenReturn(mStoredDiscoveryItem);