Merge "[Media Quality] Move away from Guava" into main
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 34a47ac..288426b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -226,7 +226,6 @@
         "securebox",
         "apache-commons-math",
         "battery_saver_flag_lib",
-        "guava",
         "notification_flags_lib",
         "power_hint_flags_lib",
         "biometrics_flags_lib",
diff --git a/services/core/java/com/android/server/media/quality/BiMap.java b/services/core/java/com/android/server/media/quality/BiMap.java
new file mode 100644
index 0000000..82b8284
--- /dev/null
+++ b/services/core/java/com/android/server/media/quality/BiMap.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 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.media.quality;
+
+import android.util.ArrayMap;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A very basic bidirectional map.
+ *
+ * @param <K> data type of Key
+ * @param <V> data type of Value
+ */
+public class BiMap<K, V> {
+    private Map<K, V> mPrimaryMap = new ArrayMap<>();
+    private Map<V, K> mSecondaryMap = new ArrayMap<>();
+
+    /**
+     * Add key and associated value to the map
+     *
+     * @param key key to add
+     * @param value value to add
+     * @return true if successfully added, false otherwise
+     */
+    public boolean put(K key, V value) {
+        if (key == null || value == null || mPrimaryMap.containsKey(key)
+                || mSecondaryMap.containsKey(value)) {
+            return false;
+        }
+
+        mPrimaryMap.put(key, value);
+        mSecondaryMap.put(value, key);
+        return true;
+    }
+
+    /**
+     * Remove key and associated value from the map
+     *
+     * @param key key to remove
+     * @return true if removed, false otherwise
+     */
+    public boolean remove(K key) {
+        if (key == null) {
+            return false;
+        }
+        if (mPrimaryMap.containsKey(key)) {
+            V value = getValue(key);
+            mPrimaryMap.remove(key);
+            mSecondaryMap.remove(value);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Remove value and associated key from the map
+     *
+     * @param value value to remove
+     * @return true if removed, false otherwise
+     */
+    public boolean removeValue(V value) {
+        if (value == null) {
+            return false;
+        }
+        return remove(getKey(value));
+    }
+
+    /**
+     * Get the value
+     *
+     * @param key key for which to get value
+     * @return V
+     */
+    public V getValue(K key) {
+        return mPrimaryMap.get(key);
+    }
+
+    /**
+     * Get the key
+     *
+     * @param value value for which to get key
+     * @return K
+     */
+    public K getKey(V value) {
+        return mSecondaryMap.get(value);
+    }
+
+    /**
+     * Get the values of the map.
+     * @return Collection
+     */
+    public Collection<V> getValues() {
+        return mPrimaryMap.values();
+    }
+
+    /**
+     * Clear the map
+     */
+    public void clear() {
+        mPrimaryMap.clear();
+        mSecondaryMap.clear();
+    }
+}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 1673b8e..ce2242b 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -37,9 +37,6 @@
 
 import com.android.server.SystemService;
 
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -66,8 +63,8 @@
     public MediaQualityService(Context context) {
         super(context);
         mContext = context;
-        mPictureProfileTempIdMap = HashBiMap.create();
-        mSoundProfileTempIdMap = HashBiMap.create();
+        mPictureProfileTempIdMap = new BiMap<>();
+        mSoundProfileTempIdMap = new BiMap<>();
         mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
         mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
         mMediaQualityDbHelper.setIdleConnectionTimeout(30);
@@ -96,7 +93,7 @@
             Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
                     null, values);
             populateTempIdMap(mPictureProfileTempIdMap, id);
-            pp.setProfileId(mPictureProfileTempIdMap.get(id));
+            pp.setProfileId(mPictureProfileTempIdMap.getValue(id));
             return pp;
         }
 
@@ -107,7 +104,7 @@
 
         @Override
         public void removePictureProfile(String id, UserHandle user) {
-            Long intId = mPictureProfileTempIdMap.inverse().get(id);
+            Long intId = mPictureProfileTempIdMap.getKey(id);
             if (intId != null) {
                 SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
                 String selection = BaseParameters.PARAMETER_ID + " = ?";
@@ -202,7 +199,7 @@
             Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
                     null, values);
             populateTempIdMap(mSoundProfileTempIdMap, id);
-            sp.setProfileId(mSoundProfileTempIdMap.get(id));
+            sp.setProfileId(mSoundProfileTempIdMap.getValue(id));
             return sp;
         }
 
@@ -213,7 +210,7 @@
 
         @Override
         public void removeSoundProfile(String id, UserHandle user) {
-            Long intId = mSoundProfileTempIdMap.inverse().get(id);
+            Long intId = mSoundProfileTempIdMap.getKey(id);
             if (intId != null) {
                 SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
                 String selection = BaseParameters.PARAMETER_ID + " = ?";
@@ -284,9 +281,9 @@
         }
 
         private void populateTempIdMap(BiMap<Long, String> map, Long id) {
-            if (id != null && map.get(id) == null) {
+            if (id != null && map.getValue(id) == null) {
                 String uuid = UUID.randomUUID().toString();
-                while (map.inverse().containsKey(uuid)) {
+                while (map.getKey(uuid) != null) {
                     uuid = UUID.randomUUID().toString();
                 }
                 map.put(id, uuid);
@@ -386,7 +383,7 @@
             int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID);
             Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null;
             populateTempIdMap(map, dbId);
-            return map.get(dbId);
+            return map.getValue(dbId);
         }
 
         private int getType(Cursor cursor) {