Merge "Add subsequent related db save info after pairing success" into tm-dev
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 08e98db..4ee16b7 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
@@ -27,17 +27,19 @@
 import android.nearby.NearbyDevice;
 import android.util.Log;
 
+import com.android.server.nearby.common.ble.decode.FastPairDecoder;
 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.cache.FastPairCacheManager;
 import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
 import com.android.server.nearby.provider.FastPairDataProvider;
 import com.android.server.nearby.util.DataUtils;
-import com.android.server.nearby.util.FastPairDecoder;
 import com.android.server.nearby.util.Hex;
 
 import java.util.List;
 
+import service.proto.Cache;
 import service.proto.Data;
 import service.proto.Rpcs;
 
@@ -47,6 +49,7 @@
 public class FastPairAdvHandler {
     Context mContext;
     String mBleAddress;
+
     /** The types about how the bloomfilter is processed. */
     public enum ProcessBloomFilterType {
         IGNORE, // The bloomfilter is not handled. e.g. distance is too far away.
@@ -69,16 +72,18 @@
     public void handleBroadcast(NearbyDevice device) {
         FastPairDevice fastPairDevice = (FastPairDevice) device;
         mBleAddress = fastPairDevice.getBluetoothAddress();
-        List<Account> accountList =
-                FastPairDataProvider.getInstance().loadFastPairEligibleAccounts();
+        FastPairDataProvider dataProvider = FastPairDataProvider.getInstance();
+        if (dataProvider == null) {
+            return;
+        }
+        List<Account> accountList = dataProvider.loadFastPairEligibleAccounts();
         if (FastPairDecoder.checkModelId(fastPairDevice.getData())) {
             byte[] model = FastPairDecoder.getModelId(fastPairDevice.getData());
             Log.d(TAG, "On discovery model id " + Hex.bytesToStringLowercase(model));
             // Use api to get anti spoofing key from model id.
             try {
                 Rpcs.GetObservedDeviceResponse response =
-                        FastPairDataProvider.getInstance()
-                                .loadFastPairAntispoofkeyDeviceMetadata(model);
+                        dataProvider.loadFastPairAntispoofkeyDeviceMetadata(model);
                 if (response == null) {
                     Log.e(TAG, "server does not have model id "
                             + Hex.bytesToStringLowercase(model));
@@ -94,26 +99,41 @@
         } else {
             // Start to process bloom filter
             try {
-                Log.d(TAG, "account list size " + accountList.size());
                 byte[] bloomFilterByteArray = FastPairDecoder
                         .getBloomFilter(fastPairDevice.getData());
                 byte[] bloomFilterSalt = FastPairDecoder
                         .getBloomFilterSalt(fastPairDevice.getData());
                 if (bloomFilterByteArray == null || bloomFilterByteArray.length == 0) {
-                    Log.d(TAG, "bloom filter byte size is 0");
                     return;
                 }
                 for (Account account : accountList) {
                     List<Data.FastPairDeviceWithAccountKey> listDevices =
-                            FastPairDataProvider.getInstance()
-                                    .loadFastPairDeviceWithAccountKey(account);
+                            dataProvider.loadFastPairDeviceWithAccountKey(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");
+                        // Check if the device is already paired
+                        List<Cache.StoredFastPairItem> storedFastPairItemList =
+                                Locator.get(mContext, FastPairCacheManager.class)
+                                        .getAllSavedStoredFastPairItem();
+                        Cache.StoredFastPairItem recognizedStoredFastPairItem =
+                                findRecognizedDeviceFromCachedItem(storedFastPairItemList,
+                                        new BloomFilter(bloomFilterByteArray,
+                                                new FastPairBloomFilterHasher()), bloomFilterSalt);
+                        if (recognizedStoredFastPairItem != null) {
+                            // The bloomfilter is recognized in the cache so the device is paired
+                            // before
+                            Log.d(TAG, "bloom filter is recognized in the cache");
+                            continue;
+                        } else {
+                            Log.d(TAG, "bloom filter is not recognized not paired before");
+                        }
+
                         return;
                     }
                 }
@@ -132,10 +152,27 @@
     @Nullable
     static Data.FastPairDeviceWithAccountKey findRecognizedDevice(
             List<Data.FastPairDeviceWithAccountKey> devices, BloomFilter bloomFilter, byte[] salt) {
+        Log.d(TAG, "saved devices size in the account is " + devices.size());
         for (Data.FastPairDeviceWithAccountKey device : devices) {
-            if (device.getAccountKey().toByteArray() == null) {
-                continue;
+            byte[] rotatedKey = concat(device.getAccountKey().toByteArray(), salt);
+            StringBuilder sb = new StringBuilder();
+            for (byte b : rotatedKey) {
+                sb.append(b);
             }
+            if (bloomFilter.possiblyContains(rotatedKey)) {
+                Log.d(TAG, "match " + sb.toString());
+                return device;
+            } else {
+                Log.d(TAG, "not match " + sb.toString());
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    static Cache.StoredFastPairItem findRecognizedDeviceFromCachedItem(
+            List<Cache.StoredFastPairItem> devices, BloomFilter bloomFilter, byte[] salt) {
+        for (Cache.StoredFastPairItem device : devices) {
             byte[] rotatedKey = concat(device.getAccountKey().toByteArray(), salt);
             if (bloomFilter.possiblyContains(rotatedKey)) {
                 return device;
@@ -143,4 +180,5 @@
         }
         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 1264ade..896056b 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -237,12 +237,14 @@
                             ByteString.copyFrom(hashValue));
             // account data place holder here
             try {
-                List<Account> accountList =
-                        FastPairDataProvider.getInstance().loadFastPairEligibleAccounts();
+                FastPairDataProvider fastPairDataProvider = FastPairDataProvider.getInstance();
+                if (fastPairDataProvider == null) {
+                    return;
+                }
+                List<Account> accountList = fastPairDataProvider.loadFastPairEligibleAccounts();
                 if (accountList.size() > 0) {
-                    FastPairDataProvider.getInstance().optIn(accountList.get(0));
-                    FastPairDataProvider.getInstance().upload(
-                            accountList.get(0), uploadInfo);
+                    fastPairDataProvider.optIn(accountList.get(0));
+                    fastPairDataProvider.upload(accountList.get(0), 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/fastpair/FastPairManager.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
index 04f72f0..cb4e6cb 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -41,6 +41,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.server.nearby.common.ble.decode.FastPairDecoder;
 import com.android.server.nearby.common.bluetooth.BluetoothException;
 import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
 import com.android.server.nearby.common.bluetooth.fastpair.FastPairDualConnection;
@@ -48,6 +49,7 @@
 import com.android.server.nearby.common.bluetooth.fastpair.Preferences;
 import com.android.server.nearby.common.bluetooth.fastpair.ReflectionException;
 import com.android.server.nearby.common.bluetooth.fastpair.SimpleBroadcastReceiver;
+import com.android.server.nearby.common.bluetooth.testability.android.bluetooth.BluetoothDevice;
 import com.android.server.nearby.common.eventloop.Annotations;
 import com.android.server.nearby.common.eventloop.EventLoop;
 import com.android.server.nearby.common.eventloop.NamedRunnable;
@@ -58,10 +60,12 @@
 import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
 import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
 import com.android.server.nearby.fastpair.pairinghandler.PairingProgressHandlerBase;
-import com.android.server.nearby.util.FastPairDecoder;
 import com.android.server.nearby.util.ForegroundThread;
 import com.android.server.nearby.util.Hex;
 
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.ByteString;
+
 import java.security.GeneralSecurityException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
@@ -71,6 +75,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import service.proto.Cache;
 import service.proto.Rpcs;
 
 /**
@@ -180,7 +185,6 @@
             @Nullable String companionApp,
             FootprintsDeviceManager footprints,
             PairingProgressHandlerBase pairingProgressHandlerBase) {
-
         return executor.submit(
                 () -> pairInternal(context, item, companionApp, accountKey, footprints,
                         pairingProgressHandlerBase), /* result= */ null);
@@ -197,7 +201,8 @@
             @Nullable byte[] accountKey,
             FootprintsDeviceManager footprints,
             PairingProgressHandlerBase pairingProgressHandlerBase) {
-        FastPairHalfSheetManager manager = Locator.get(context, FastPairHalfSheetManager.class);
+        FastPairHalfSheetManager fastPairHalfSheetManager =
+                Locator.get(context, FastPairHalfSheetManager.class);
         try {
             pairingProgressHandlerBase.onPairingStarted();
             if (pairingProgressHandlerBase.skipWaitingScreenUnlock()) {
@@ -268,24 +273,17 @@
                     if (sharedSecret != null) {
                         Locator.get(context, FastPairController.class).addDeviceToFootprint(
                                 connection.getPublicAddress(), sharedSecret.getKey(), item);
+                        cacheFastPairDevice(context, connection.getPublicAddress(),
+                                sharedSecret.getKey(), item);
                     }
                 }
-
-                byte[] key = pairingProgressHandlerBase.getKeyForLocalCache(accountKey,
-                        connection, sharedSecret);
-
-                // We don't cache initial pairing case here but cache it when upload to footprints.
-                if (key != null) {
-                    // CacheManager to save the content here
-                }
             } else {
                 // Fast Pair one
                 connection.pair();
             }
-
             // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
             // pairingProgressHandlerBase class.
-            manager.showPairingSuccessHalfSheet(connection.getPublicAddress());
+            fastPairHalfSheetManager.showPairingSuccessHalfSheet(connection.getPublicAddress());
             pairingProgressHandlerBase.onPairingSuccess(connection.getPublicAddress());
         } catch (BluetoothException
                 | InterruptedException
@@ -298,11 +296,38 @@
 
             // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
             // pairingProgressHandlerBase class.
-            manager.showPairingFailed();
+            fastPairHalfSheetManager.showPairingFailed();
             pairingProgressHandlerBase.onPairingFailed(e);
         }
     }
 
+    private static void cacheFastPairDevice(Context context, String publicAddress, byte[] key,
+            DiscoveryItem item) {
+        try {
+            Locator.get(context, EventLoop.class).postAndWait(
+                    new NamedRunnable("FastPairCacheDevice") {
+                        @Override
+                        public void run() {
+                            Cache.StoredFastPairItem storedFastPairItem =
+                                    Cache.StoredFastPairItem.newBuilder()
+                                            .setMacAddress(publicAddress)
+                                            .setAccountKey(ByteString.copyFrom(key))
+                                            .setModelId(item.getTriggerId())
+                                            .addAllFeatures(item.getFastPairInformation() == null
+                                                    ? ImmutableList.of() :
+                                                    item.getFastPairInformation().getFeaturesList())
+                                            .setDiscoveryItem(item.getCopyOfStoredItem())
+                                            .build();
+                            Locator.get(context, FastPairCacheManager.class)
+                                    .putStoredFastPairItem(storedFastPairItem);
+                        }
+                    }
+            );
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Fail to insert paired device into cache");
+        }
+    }
+
     /** Checks if the pairing is initial pairing with fast pair 2.0 design. */
     public static boolean isThroughFastPair2InitialPairing(
             DiscoveryItem item, @Nullable byte[] accountKey) {
@@ -319,7 +344,7 @@
         // regardless.
         if (keyguardManager.isKeyguardLocked()) {
             Log.v(TAG, "FastPair: Screen is locked, waiting until unlocked "
-                            + "to show status notifications.");
+                    + "to show status notifications.");
             try (SimpleBroadcastReceiver isUnlockedReceiver =
                          SimpleBroadcastReceiver.oneShotReceiver(
                                  context, FlagUtils.getPreferencesBuilder().build(),
@@ -346,7 +371,7 @@
                     Settings.Secure.getUriFor(Settings.Secure.FAST_PAIR_SCAN_ENABLED),
                     /* notifyForDescendants= */ false,
                     mFastPairScanChangeContentObserver);
-        }  catch (SecurityException e) {
+        } catch (SecurityException e) {
             Log.e(TAG, "Failed to register content observer for fast pair scan.", e);
         }
     }
@@ -395,7 +420,7 @@
     }
 
     /**
-     *  Starts or stops scanning according to mAllowScan value.
+     * Starts or stops scanning according to mAllowScan value.
      */
     private void invalidateScan() {
         NearbyManager nearbyManager = getNearbyManager();
@@ -415,6 +440,30 @@
     }
 
     /**
+     * When certain device is forgotten we need to remove the info from database because the info
+     * is no longer useful.
+     */
+    private void processBluetoothConnectionEvent(Intent intent) {
+        int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                BluetoothDevice.ERROR);
+        if (bondState == BluetoothDevice.BOND_NONE) {
+            BluetoothDevice device =
+                    intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            if (device != null) {
+                Log.d("FastPairService", "Forget device detect");
+                processBackgroundTask(new Runnable() {
+                    @Override
+                    public void run() {
+                        mLocatorContextWrapper.getLocator().get(FastPairCacheManager.class)
+                                .removeStoredFastPairItem(device.getAddress());
+                    }
+                });
+            }
+
+        }
+    }
+
+    /**
      * Helper function to get bluetooth adapter.
      */
     @Nullable
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java
deleted file mode 100644
index e171462..0000000
--- a/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.nearby.fastpair.cache;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-/**
- * Discovery db helper
- */
-public class DiscoveryItemDbHelper extends SQLiteOpenHelper {
-
-    public static final int DATABASE_VERSION = 1;
-    public static final String DATABASE_NAME = "ScanResult.db";
-    private static final String SQL_CREATE_DB =
-            "CREATE TABLE " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME
-                    + " (" + DiscoveryItemContract.DiscoveryItemEntry._ID
-                    + "INTEGER PRIMARY KEY,"
-                    + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID
-                    + " TEXT," + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
-                    + " BLOB)";
-    private static final String SQL_DELETE_DB =
-            "DROP TABLE IF EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME;
-
-    public DiscoveryItemDbHelper(Context context) {
-        super(context, DATABASE_NAME, null, DATABASE_VERSION);
-    }
-
-    @Override
-    public void onCreate(SQLiteDatabase db) {
-        db.execSQL(SQL_CREATE_DB);
-    }
-
-    @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        // Since the outdated data has no value so just remove the data.
-        db.execSQL(SQL_DELETE_DB);
-        onCreate(db);
-    }
-
-    @Override
-    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        super.onDowngrade(db, oldVersion, newVersion);
-    }
-}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
index fb2adb2..b840091 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
@@ -39,18 +39,18 @@
  */
 public class FastPairCacheManager {
     private final Context mContext;
-    private final DiscoveryItemDbHelper mDiscoveryItemDbHelper;
+    private final FastPairDbHelper mFastPairDbHelper;
 
     public FastPairCacheManager(Context context) {
         mContext = context;
-        mDiscoveryItemDbHelper = new DiscoveryItemDbHelper(context);
+        mFastPairDbHelper = new FastPairDbHelper(context);
     }
 
     /**
      * Clean up function to release db
      */
     public void cleanUp() {
-        mDiscoveryItemDbHelper.close();
+        mFastPairDbHelper.close();
     }
 
     /**
@@ -74,10 +74,12 @@
     }
 
     /**
-     * Save discovery item into database.
+     * Save discovery item into database. Discovery item is item that discovered through Ble before
+     * pairing success.
      */
     public boolean saveDiscoveryItem(DiscoveryItem item) {
-        SQLiteDatabase db = mDiscoveryItemDbHelper.getWritableDatabase();
+
+        SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
         ContentValues values = new ContentValues();
         values.put(DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID, item.getTriggerId());
         values.put(DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE,
@@ -103,8 +105,7 @@
      * Get discovery item from item id.
      */
     public Cache.StoredDiscoveryItem getStoredDiscoveryItem(String itemId) {
-
-        SQLiteDatabase db = mDiscoveryItemDbHelper.getReadableDatabase();
+        SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
         String[] projection = {
                 DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID,
                 DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
@@ -140,7 +141,7 @@
      */
     public List<Cache.StoredDiscoveryItem> getAllSavedStoreDiscoveryItem() {
         List<Cache.StoredDiscoveryItem> storedDiscoveryItemList = new ArrayList<>();
-        SQLiteDatabase db = mDiscoveryItemDbHelper.getReadableDatabase();
+        SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
         String[] projection = {
                 DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID,
                 DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
@@ -169,6 +170,7 @@
         cursor.close();
         return storedDiscoveryItemList;
     }
+
     /**
      * Get scan result from local database use model id
      */
@@ -176,4 +178,105 @@
         return Cache.StoredScanResult.getDefaultInstance();
     }
 
+    /**
+     * Gets the paired Fast Pair item that paired to the phone through mac address.
+     */
+    public Cache.StoredFastPairItem getStoredFastPairItemFromMacAddress(String macAddress) {
+        SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
+        String[] projection = {
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+        };
+        String selection =
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS + " =? ";
+        String[] selectionArgs = {macAddress};
+        Cursor cursor = db.query(
+                StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+                projection,
+                selection,
+                selectionArgs,
+                null,
+                null,
+                null
+        );
+
+        if (cursor.moveToNext()) {
+            byte[] res = cursor.getBlob(cursor.getColumnIndexOrThrow(
+                    StoredFastPairItemContract.StoredFastPairItemEntry
+                            .COLUMN_STORED_FAST_PAIR_BYTE));
+            try {
+                Cache.StoredFastPairItem item = Cache.StoredFastPairItem.parseFrom(res);
+                return item;
+            } catch (InvalidProtocolBufferException e) {
+                Log.e("FastPairCacheManager", "storediscovery has error");
+            }
+        }
+        cursor.close();
+        return Cache.StoredFastPairItem.getDefaultInstance();
+    }
+
+    /**
+     * Save paired fast pair item into the database.
+     */
+    public boolean putStoredFastPairItem(Cache.StoredFastPairItem storedFastPairItem) {
+        SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+                storedFastPairItem.getMacAddress());
+        values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+                storedFastPairItem.getAccountKey().toString());
+        values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE,
+                storedFastPairItem.toByteArray());
+        db.insert(StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME, null, values);
+        return true;
+
+    }
+
+    /**
+     * Removes certain storedFastPairItem so that it can update timely.
+     */
+    public void removeStoredFastPairItem(String macAddress) {
+        SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
+        int res = db.delete(StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS + "=?",
+                new String[]{macAddress});
+
+    }
+
+    /**
+     * Get all of the store fast pair item related info in the cache.
+     */
+    public List<Cache.StoredFastPairItem> getAllSavedStoredFastPairItem() {
+        List<Cache.StoredFastPairItem> storedFastPairItemList = new ArrayList<>();
+        SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
+        String[] projection = {
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+                StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+        };
+        Cursor cursor = db.query(
+                StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+                projection,
+                null,
+                null,
+                null,
+                null,
+                null
+        );
+
+        while (cursor.moveToNext()) {
+            byte[] res = cursor.getBlob(cursor.getColumnIndexOrThrow(StoredFastPairItemContract
+                    .StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE));
+            try {
+                Cache.StoredFastPairItem item = Cache.StoredFastPairItem.parseFrom(res);
+                storedFastPairItemList.add(item);
+            } catch (InvalidProtocolBufferException e) {
+                Log.e("FastPairCacheManager", "storediscovery has error");
+            }
+
+        }
+        cursor.close();
+        return storedFastPairItemList;
+    }
 }
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java
new file mode 100644
index 0000000..d950d8d
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.fastpair.cache;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Fast Pair db helper handle all of the db actions related Fast Pair.
+ */
+public class FastPairDbHelper extends SQLiteOpenHelper {
+
+    public static final int DATABASE_VERSION = 1;
+    public static final String DATABASE_NAME = "FastPair.db";
+    private static final String SQL_CREATE_DISCOVERY_ITEM_DB =
+            "CREATE TABLE IF NOT EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME
+                    + " (" + DiscoveryItemContract.DiscoveryItemEntry._ID
+                    + "INTEGER PRIMARY KEY,"
+                    + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID
+                    + " TEXT," + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
+                    + " BLOB)";
+    private static final String SQL_DELETE_DISCOVERY_ITEM_DB =
+            "DROP TABLE IF EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME;
+    private static final String SQL_CREATE_FAST_PAIR_ITEM_DB =
+            "CREATE TABLE IF NOT EXISTS "
+                    + StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME
+                    + " (" + StoredFastPairItemContract.StoredFastPairItemEntry._ID
+                    + "INTEGER PRIMARY KEY,"
+                    + StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS
+                    + " TEXT,"
+                    + StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY
+                    + " TEXT,"
+                    + StoredFastPairItemContract
+                    .StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+                    + " BLOB)";
+    private static final String SQL_DELETE_FAST_PAIR_ITEM_DB =
+            "DROP TABLE IF EXISTS " + StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME;
+
+    public FastPairDbHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL(SQL_CREATE_DISCOVERY_ITEM_DB);
+        db.execSQL(SQL_CREATE_FAST_PAIR_ITEM_DB);
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        // Since the outdated data has no value so just remove the data.
+        db.execSQL(SQL_DELETE_DISCOVERY_ITEM_DB);
+        db.execSQL(SQL_DELETE_FAST_PAIR_ITEM_DB);
+        onCreate(db);
+    }
+
+    @Override
+    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        super.onDowngrade(db, oldVersion, newVersion);
+    }
+}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java
new file mode 100644
index 0000000..9980565
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java
@@ -0,0 +1,37 @@
+/*
+ * 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.fastpair.cache;
+
+import android.provider.BaseColumns;
+
+/**
+ * Defines fast pair item database schema.
+ */
+public class StoredFastPairItemContract {
+    private StoredFastPairItemContract() {}
+
+    /**
+     * StoredFastPairItem entry related info.
+     */
+    public static class StoredFastPairItemEntry implements BaseColumns {
+        public static final String TABLE_NAME = "STORED_FAST_PAIR_ITEM";
+        public static final String COLUMN_MAC_ADDRESS = "MAC_ADDRESS";
+        public static final String COLUMN_ACCOUNT_KEY = "ACCOUNT_KEY";
+
+        public static final String COLUMN_STORED_FAST_PAIR_BYTE = "STORED_FAST_PAIR_BYTE";
+    }
+}
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 b8233ec..adae97d 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
@@ -25,6 +25,8 @@
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SdkSuppress;
 
+import com.google.protobuf.ByteString;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -37,9 +39,17 @@
     private static final String MODEL_ID = "001";
     private static final String MODEL_ID2 = "002";
     private static final String APP_NAME = "APP_NAME";
+    private static final String MAC_ADDRESS = "00:11:22:33";
+    private static final ByteString ACCOUNT_KEY = ByteString.copyFromUtf8("axgs");
+    private static final String MAC_ADDRESS_B = "00:11:22:44";
+    private static final ByteString ACCOUNT_KEY_B = ByteString.copyFromUtf8("axgb");
+
     @Mock
     DiscoveryItem mDiscoveryItem;
-    @Mock DiscoveryItem mDiscoveryItem2;
+    @Mock
+    DiscoveryItem mDiscoveryItem2;
+    @Mock
+    Cache.StoredFastPairItem mStoredFastPairItem;
     Cache.StoredDiscoveryItem mStoredDiscoveryItem = Cache.StoredDiscoveryItem.newBuilder()
             .setTriggerId(MODEL_ID)
             .setAppName(APP_NAME).build();
@@ -97,4 +107,47 @@
         assertThat(fastPairCacheManager.getAllSavedStoreDiscoveryItem()).hasSize(3);
     }
 
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void saveRetrieveInfoStoredFastPairItem() {
+        Context mContext = ApplicationProvider.getApplicationContext();
+        Cache.StoredFastPairItem storedFastPairItem = Cache.StoredFastPairItem.newBuilder()
+                .setMacAddress(MAC_ADDRESS)
+                .setAccountKey(ACCOUNT_KEY)
+                .build();
+
+
+        FastPairCacheManager fastPairCacheManager = new FastPairCacheManager(mContext);
+        fastPairCacheManager.putStoredFastPairItem(storedFastPairItem);
+
+        assertThat(fastPairCacheManager.getStoredFastPairItemFromMacAddress(
+                MAC_ADDRESS).getAccountKey())
+                .isEqualTo(ACCOUNT_KEY);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void checkGetAllFastPairItems() {
+        Context mContext = ApplicationProvider.getApplicationContext();
+        Cache.StoredFastPairItem storedFastPairItem = Cache.StoredFastPairItem.newBuilder()
+                .setMacAddress(MAC_ADDRESS)
+                .setAccountKey(ACCOUNT_KEY)
+                .build();
+        Cache.StoredFastPairItem storedFastPairItemB = Cache.StoredFastPairItem.newBuilder()
+                .setMacAddress(MAC_ADDRESS_B)
+                .setAccountKey(ACCOUNT_KEY_B)
+                .build();
+
+        FastPairCacheManager fastPairCacheManager = new FastPairCacheManager(mContext);
+        fastPairCacheManager.putStoredFastPairItem(storedFastPairItem);
+        fastPairCacheManager.putStoredFastPairItem(storedFastPairItemB);
+
+        assertThat(fastPairCacheManager.getAllSavedStoredFastPairItem().size())
+                .isEqualTo(2);
+
+        fastPairCacheManager.removeStoredFastPairItem(MAC_ADDRESS_B);
+
+        assertThat(fastPairCacheManager.getAllSavedStoredFastPairItem().size())
+                .isEqualTo(1);
+    }
 }