Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab6b060e authored by Ugo Yu's avatar Ugo Yu Committed by android-build-merger
Browse files

Merge "Support metadata APIs for Bluetooth storage"

am: 55083170

Change-Id: Ia6a9e9b3f6989ac3dd81bb378cea5eef0684cb90
parents a28baf30 55083170
Loading
Loading
Loading
Loading
+98 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothMetadataListener;
import android.bluetooth.IBluetoothSocketManager;
import android.bluetooth.IBluetoothSocketManager;
import android.bluetooth.OobData;
import android.bluetooth.OobData;
import android.bluetooth.UidTraffic;
import android.bluetooth.UidTraffic;
@@ -168,6 +169,8 @@ public class AdapterService extends Service {


    private boolean mNativeAvailable;
    private boolean mNativeAvailable;
    private boolean mCleaningUp;
    private boolean mCleaningUp;
    private final HashMap<BluetoothDevice, ArrayList<IBluetoothMetadataListener>>
            mMetadataListeners = new HashMap<>();
    private final HashMap<String, Integer> mProfileServicesState = new HashMap<String, Integer>();
    private final HashMap<String, Integer> mProfileServicesState = new HashMap<String, Integer>();
    //Only BluetoothManagerService should be registered
    //Only BluetoothManagerService should be registered
    private RemoteCallbackList<IBluetoothCallback> mCallbacks;
    private RemoteCallbackList<IBluetoothCallback> mCallbacks;
@@ -1618,6 +1621,43 @@ public class AdapterService extends Service {
            return service.reportActivityInfo();
            return service.reportActivityInfo();
        }
        }


        @Override
        public boolean registerMetadataListener(IBluetoothMetadataListener listener,
                BluetoothDevice device) {
            AdapterService service = getService();
            if (service == null) {
                return false;
            }
            return service.registerMetadataListener(listener, device);
        }

        @Override
        public boolean unregisterMetadataListener(BluetoothDevice device) {
            AdapterService service = getService();
            if (service == null) {
                return false;
            }
            return service.unregisterMetadataListener(device);
        }

        @Override
        public boolean setMetadata(BluetoothDevice device, int key, String value) {
            AdapterService service = getService();
            if (service == null) {
                return false;
            }
            return service.setMetadata(device, key, value);
        }

        @Override
        public String getMetadata(BluetoothDevice device, int key) {
            AdapterService service = getService();
            if (service == null) {
                return null;
            }
            return service.getMetadata(device, key);
        }

        @Override
        @Override
        public void requestActivityInfo(ResultReceiver result) {
        public void requestActivityInfo(ResultReceiver result) {
            Bundle bundle = new Bundle();
            Bundle bundle = new Bundle();
@@ -2531,6 +2571,64 @@ public class AdapterService extends Service {
                + ctrlState + "traffic = " + Arrays.toString(data));
                + ctrlState + "traffic = " + Arrays.toString(data));
    }
    }


    boolean registerMetadataListener(IBluetoothMetadataListener listener,
            BluetoothDevice device) {
        if (mMetadataListeners == null) {
            return false;
        }

        ArrayList<IBluetoothMetadataListener> list = mMetadataListeners.get(device);
        if (list == null) {
            list = new ArrayList<>();
        } else if (list.contains(listener)) {
            // The device is already registered with this listener
            return true;
        }
        list.add(listener);
        mMetadataListeners.put(device, list);
        return true;
    }

    boolean unregisterMetadataListener(BluetoothDevice device) {
        if (mMetadataListeners == null) {
            return false;
        }
        if (mMetadataListeners.containsKey(device)) {
            mMetadataListeners.remove(device);
        }
        return true;
    }

    boolean setMetadata(BluetoothDevice device, int key, String value) {
        if (value.length() > BluetoothDevice.METADATA_MAX_LENGTH) {
            Log.e(TAG, "setMetadata: value length too long " + value.length());
            return false;
        }
        return mDatabaseManager.setCustomMeta(device, key, value);
    }

    String getMetadata(BluetoothDevice device, int key) {
        return mDatabaseManager.getCustomMeta(device, key);
    }

    /**
     * Update metadata change to registered listeners
     */
    @VisibleForTesting
    public void metadataChanged(String address, int key, String value) {
        BluetoothDevice device = mRemoteDevices.getDevice(address.getBytes());
        if (mMetadataListeners.containsKey(device)) {
            ArrayList<IBluetoothMetadataListener> list = mMetadataListeners.get(device);
            for (IBluetoothMetadataListener listener : list) {
                try {
                    listener.onMetadataChanged(device, key, value);
                } catch (RemoteException e) {
                    Log.w(TAG, "RemoteException when onMetadataChanged");
                }
            }
        }
    }

    private int getIdleCurrentMa() {
    private int getIdleCurrentMa() {
        return getResources().getInteger(R.integer.config_bluetooth_idle_cur_ma);
        return getResources().getInteger(R.integer.config_bluetooth_idle_cur_ma);
    }
    }
+96 −1
Original line number Original line Diff line number Diff line
@@ -159,6 +159,97 @@ public class DatabaseManager {
        }
        }
    }
    }


    boolean isValidMetaKey(int key) {
        switch (key) {
            case BluetoothDevice.METADATA_MANUFACTURER_NAME:
            case BluetoothDevice.METADATA_MODEL_NAME:
            case BluetoothDevice.METADATA_SOFTWARE_VERSION:
            case BluetoothDevice.METADATA_HARDWARE_VERSION:
            case BluetoothDevice.METADATA_COMPANION_APP:
            case BluetoothDevice.METADATA_MAIN_ICON:
            case BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET:
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON:
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON:
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON:
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY:
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY:
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY:
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING:
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING:
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING:
            case BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI:
                return true;
        }
        Log.w(TAG, "Invalid metadata key " + key);
        return false;
    }

    /**
     * Set customized metadata to database with requested key
     */
    @VisibleForTesting
    public boolean setCustomMeta(BluetoothDevice device, int key, String newValue) {
        synchronized (mMetadataCache) {
            if (device == null) {
                Log.e(TAG, "setCustomMeta: device is null");
                return false;
            }
            if (!isValidMetaKey(key)) {
                Log.e(TAG, "setCustomMeta: meta key invalid " + key);
                return false;
            }

            String address = device.getAddress();
            if (VERBOSE) {
                Log.d(TAG, "setCustomMeta: " + address + ", key=" + key);
            }
            if (!mMetadataCache.containsKey(address)) {
                createMetadata(address);
            }
            Metadata data = mMetadataCache.get(address);
            String oldValue = data.getCustomizedMeta(key);
            if (oldValue != null && oldValue.equals(newValue)) {
                if (VERBOSE) {
                    Log.d(TAG, "setCustomMeta: metadata not changed.");
                }
                return true;
            }
            data.setCustomizedMeta(key, newValue);

            updateDatabase(data);
            mAdapterService.metadataChanged(address, key, newValue);
            return true;
        }
    }

    /**
     * Get customized metadata from database with requested key
     */
    @VisibleForTesting
    public String getCustomMeta(BluetoothDevice device, int key) {
        synchronized (mMetadataCache) {
            if (device == null) {
                Log.e(TAG, "getCustomMeta: device is null");
                return null;
            }
            if (!isValidMetaKey(key)) {
                Log.e(TAG, "getCustomMeta: meta key invalid " + key);
                return null;
            }

            String address = device.getAddress();

            if (!mMetadataCache.containsKey(address)) {
                Log.e(TAG, "getCustomMeta: device " + address + " is not in cache");
                return null;
            }

            Metadata data = mMetadataCache.get(address);
            String value = data.getCustomizedMeta(key);
            return value;
        }
    }

    /**
    /**
     * Set the device profile prioirty
     * Set the device profile prioirty
     *
     *
@@ -476,8 +567,12 @@ public class DatabaseManager {
                for (BluetoothDevice device : bondedDevices) {
                for (BluetoothDevice device : bondedDevices) {
                    if (!device.getAddress().equals(address)
                    if (!device.getAddress().equals(address)
                            && !address.equals(LOCAL_STORAGE)) {
                            && !address.equals(LOCAL_STORAGE)) {
                        // Report metadata change to null
                        List<Integer> list = metadata.getChangedCustomizedMeta();
                        for (int key : list) {
                            mAdapterService.metadataChanged(address, key, null);
                        }
                        Log.i(TAG, "remove unpaired device from database " + address);
                        Log.i(TAG, "remove unpaired device from database " + address);
                        //TODO Callback metadata change
                        deleteDatabase(mMetadataCache.get(address));
                        deleteDatabase(mMetadataCache.get(address));
                    }
                    }
                }
                }
+174 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.bluetooth.btservice;
package com.android.bluetooth.btservice;


import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
@@ -24,6 +25,9 @@ import androidx.room.Embedded;
import androidx.room.Entity;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import androidx.room.PrimaryKey;


import java.util.ArrayList;
import java.util.List;

@Entity(tableName = "metadata")
@Entity(tableName = "metadata")
class Metadata {
class Metadata {
    @PrimaryKey
    @PrimaryKey
@@ -121,4 +125,174 @@ class Metadata {
        }
        }
        return BluetoothProfile.PRIORITY_UNDEFINED;
        return BluetoothProfile.PRIORITY_UNDEFINED;
    }
    }

    void setCustomizedMeta(int key, String value) {
        switch (key) {
            case BluetoothDevice.METADATA_MANUFACTURER_NAME:
                publicMeta.manufacturer_name = value;
                break;
            case BluetoothDevice.METADATA_MODEL_NAME:
                publicMeta.model_name = value;
                break;
            case BluetoothDevice.METADATA_SOFTWARE_VERSION:
                publicMeta.software_version = value;
                break;
            case BluetoothDevice.METADATA_HARDWARE_VERSION:
                publicMeta.hardware_version = value;
                break;
            case BluetoothDevice.METADATA_COMPANION_APP:
                publicMeta.companion_app = value;
                break;
            case BluetoothDevice.METADATA_MAIN_ICON:
                publicMeta.main_icon = value;
                break;
            case BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET:
                publicMeta.is_unthethered_headset = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON:
                publicMeta.unthethered_left_icon = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON:
                publicMeta.unthethered_right_icon = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON:
                publicMeta.unthethered_case_icon = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY:
                publicMeta.unthethered_left_battery = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY:
                publicMeta.unthethered_right_battery = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY:
                publicMeta.unthethered_case_battery = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING:
                publicMeta.unthethered_left_charging = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING:
                publicMeta.unthethered_right_charging = value;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING:
                publicMeta.unthethered_case_charging = value;
                break;
            case BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI:
                publicMeta.enhanced_settings_ui_uri = value;
                break;
        }
    }

    String getCustomizedMeta(int key) {
        String value = null;
        switch (key) {
            case BluetoothDevice.METADATA_MANUFACTURER_NAME:
                value = publicMeta.manufacturer_name;
                break;
            case BluetoothDevice.METADATA_MODEL_NAME:
                value = publicMeta.model_name;
                break;
            case BluetoothDevice.METADATA_SOFTWARE_VERSION:
                value = publicMeta.software_version;
                break;
            case BluetoothDevice.METADATA_HARDWARE_VERSION:
                value = publicMeta.hardware_version;
                break;
            case BluetoothDevice.METADATA_COMPANION_APP:
                value = publicMeta.companion_app;
                break;
            case BluetoothDevice.METADATA_MAIN_ICON:
                value = publicMeta.main_icon;
                break;
            case BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET:
                value = publicMeta.is_unthethered_headset;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON:
                value = publicMeta.unthethered_left_icon;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON:
                value = publicMeta.unthethered_right_icon;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON:
                value = publicMeta.unthethered_case_icon;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY:
                value = publicMeta.unthethered_left_battery;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY:
                value = publicMeta.unthethered_right_battery;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY:
                value = publicMeta.unthethered_case_battery;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING:
                value = publicMeta.unthethered_left_charging;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING:
                value = publicMeta.unthethered_right_charging;
                break;
            case BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING:
                value = publicMeta.unthethered_case_charging;
                break;
            case BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI:
                value = publicMeta.enhanced_settings_ui_uri;
                break;
        }
        return value;
    }

    List<Integer> getChangedCustomizedMeta() {
        List<Integer> list = new ArrayList<>();
        if (publicMeta.manufacturer_name != null) {
            list.add(BluetoothDevice.METADATA_MANUFACTURER_NAME);
        }
        if (publicMeta.model_name != null) {
            list.add(BluetoothDevice.METADATA_MODEL_NAME);
        }
        if (publicMeta.software_version != null) {
            list.add(BluetoothDevice.METADATA_SOFTWARE_VERSION);
        }
        if (publicMeta.hardware_version != null) {
            list.add(BluetoothDevice.METADATA_HARDWARE_VERSION);
        }
        if (publicMeta.companion_app != null) {
            list.add(BluetoothDevice.METADATA_COMPANION_APP);
        }
        if (publicMeta.main_icon != null) {
            list.add(BluetoothDevice.METADATA_MAIN_ICON);
        }
        if (publicMeta.is_unthethered_headset != null) {
            list.add(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET);
        }
        if (publicMeta.unthethered_left_icon != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON);
        }
        if (publicMeta.unthethered_right_icon != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON);
        }
        if (publicMeta.unthethered_case_icon != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON);
        }
        if (publicMeta.unthethered_left_battery != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY);
        }
        if (publicMeta.unthethered_right_battery != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY);
        }
        if (publicMeta.unthethered_case_battery != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY);
        }
        if (publicMeta.unthethered_left_charging != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING);
        }
        if (publicMeta.unthethered_right_charging != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING);
        }
        if (publicMeta.unthethered_case_charging != null) {
            list.add(BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING);
        }
        if (publicMeta.enhanced_settings_ui_uri != null) {
            list.add(BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI);
        }
        return list;
    }
}
}
+124 −2
Original line number Original line Diff line number Diff line
@@ -68,10 +68,10 @@ public final class DatabaseManagerTest {
                MetadataDatabase.class).build();
                MetadataDatabase.class).build();


        mDatabaseManager = new DatabaseManager(mAdapterService);
        mDatabaseManager = new DatabaseManager(mAdapterService);
        //mDatabaseManager.doNotMigrateSettingGlobal();


        BluetoothDevice[] bondedDevices = {};
        BluetoothDevice[] bondedDevices = {};
        doReturn(bondedDevices).when(mAdapterService).getBondedDevices();
        doReturn(bondedDevices).when(mAdapterService).getBondedDevices();
        doNothing().when(mAdapterService).metadataChanged(anyString(), anyInt(), anyString());


        mDatabaseManager.start(mDatabase);
        mDatabaseManager.start(mDatabase);
        // Wait for handler thread finish its task.
        // Wait for handler thread finish its task.
@@ -182,11 +182,13 @@ public final class DatabaseManagerTest {


    @Test
    @Test
    public void testRemoveUnusedMetadata() {
    public void testRemoveUnusedMetadata() {
        // Insert two devices to database and cache, only mTestDevice is
        // Insert three devices to database and cache, only mTestDevice is
        // in the bonded list
        // in the bonded list
        BluetoothDevice otherDevice = BluetoothAdapter.getDefaultAdapter()
        BluetoothDevice otherDevice = BluetoothAdapter.getDefaultAdapter()
                .getRemoteDevice(OTHER_BT_ADDR);
                .getRemoteDevice(OTHER_BT_ADDR);
        Metadata otherData = new Metadata(OTHER_BT_ADDR);
        Metadata otherData = new Metadata(OTHER_BT_ADDR);
        // Add metadata for otherDevice
        otherData.setCustomizedMeta(0, "value");
        mDatabaseManager.mMetadataCache.put(OTHER_BT_ADDR, otherData);
        mDatabaseManager.mMetadataCache.put(OTHER_BT_ADDR, otherData);
        mDatabase.insert(otherData);
        mDatabase.insert(otherData);


@@ -201,6 +203,9 @@ public final class DatabaseManagerTest {
        // Wait for database update
        // Wait for database update
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());


        // Check removed device report metadata changed to null
        verify(mAdapterService).metadataChanged(OTHER_BT_ADDR, 0, null);

        List<Metadata> list = mDatabase.load();
        List<Metadata> list = mDatabase.load();


        // Check number of metadata in the database
        // Check number of metadata in the database
@@ -216,6 +221,85 @@ public final class DatabaseManagerTest {
        mDatabaseManager.mMetadataCache.clear();
        mDatabaseManager.mMetadataCache.clear();
    }
    }


    @Test
    public void testSetGetCustomMeta() {
        int badKey = 100;
        String value = "input value";

        // Device is not in database
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MANUFACTURER_NAME,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MODEL_NAME,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_SOFTWARE_VERSION,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_HARDWARE_VERSION,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_COMPANION_APP,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MAIN_ICON,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING,
                value, true);
        testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI,
                value, true);
        testSetGetCustomMetaCase(false, badKey, value, false);

        // Device is in database
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MANUFACTURER_NAME,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MODEL_NAME,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_SOFTWARE_VERSION,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_HARDWARE_VERSION,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_COMPANION_APP,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MAIN_ICON,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING,
                value, true);
        testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI,
                value, true);
    }

    void testSetGetProfilePriorityCase(boolean stored, int priority, int expectedPriority,
    void testSetGetProfilePriorityCase(boolean stored, int priority, int expectedPriority,
            boolean expectedSetResult) {
            boolean expectedSetResult) {
        if (stored) {
        if (stored) {
@@ -298,4 +382,42 @@ public final class DatabaseManagerTest {
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
        mDatabaseManager.mMetadataCache.clear();
        mDatabaseManager.mMetadataCache.clear();
    }
    }

    void testSetGetCustomMetaCase(boolean stored, int key, String value, boolean expectedResult) {
        String testValue = "test value";
        int verifyTime = 1;
        if (stored) {
            Metadata data = new Metadata(TEST_BT_ADDR);
            mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
            mDatabase.insert(data);
            Assert.assertEquals(expectedResult,
                    mDatabaseManager.setCustomMeta(mTestDevice, key, testValue));
            verify(mAdapterService).metadataChanged(TEST_BT_ADDR, key, testValue);
            verifyTime++;
        }
        Assert.assertEquals(expectedResult,
                mDatabaseManager.setCustomMeta(mTestDevice, key, value));
        if (expectedResult) {
            // Check for callback and get value
            verify(mAdapterService, times(verifyTime)).metadataChanged(TEST_BT_ADDR, key, value);
            Assert.assertEquals(value,
                    mDatabaseManager.getCustomMeta(mTestDevice, key));
        } else {
            Assert.assertNull(mDatabaseManager.getCustomMeta(mTestDevice, key));
            return;
        }
        // Wait for database update
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());

        // Check whether the value is saved in database
        List<Metadata> list = mDatabase.load();
        Metadata data = list.get(0);
        Assert.assertEquals(TEST_BT_ADDR, data.getAddress());
        Assert.assertEquals(value, data.getCustomizedMeta(key));

        mDatabase.deleteAll();
        // Wait for clear database
        TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
        mDatabaseManager.mMetadataCache.clear();
    }
}
}