Add last connected device concept

When connecting multiple audio devices,
Media and Sonification sounds comes out of the last connected device,
not a high-priority device.

Test: play music
Test: connect wired earphone // sound : wired earphone
Test: connect usb earphone // sound : usb earphone, not the wired earphone(high-priority)
Test: connect bluetooth headset // sound : bluetooth headset
Test: disconnect bluetooth headset // sound : usb earphone, not the wired earphone(high-priority)
Bug: 135749685

Change-Id: I579a04a04c97cc846b88e54fa83cdf3dad0b5cee
Signed-off-by: Baekgyeong Kim <baek.kim@samsung.com>
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
old mode 100644
new mode 100755
index b87c71d..a1c69f2
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -25,6 +25,7 @@
         "src/ProductStrategy.cpp",
         "src/VolumeCurve.cpp",
         "src/VolumeGroup.cpp",
+        "src/LastRemovableMediaDevices.cpp",
     ],
     cflags: [
         "-Wall",
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
old mode 100644
new mode 100755
index fca9a60..4cf0b90
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -20,6 +20,7 @@
 #include <EngineInterface.h>
 #include <ProductStrategy.h>
 #include <VolumeGroup.h>
+#include <LastRemovableMediaDevices.h>
 
 namespace android {
 namespace audio_policy {
@@ -49,10 +50,8 @@
         return mForceUse[usage];
     }
     android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
-                                               audio_policy_dev_state_t /*state*/) override
-    {
-        return NO_ERROR;
-    }
+                                               audio_policy_dev_state_t /*state*/) override;
+
     product_strategy_t getProductStrategyForAttributes(
             const audio_attributes_t &attr) const override;
 
@@ -86,6 +85,12 @@
 
     status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
 
+    std::vector<audio_devices_t> getLastRemovableMediaDevices(
+            device_out_group_t group = GROUP_NONE) const
+    {
+        return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+    }
+
     void dump(String8 *dst) const override;
 
 
@@ -115,11 +120,12 @@
 
     status_t restoreOriginVolumeCurve(audio_stream_type_t stream);
 
- private:
+private:
     AudioPolicyManagerObserver *mApmObserver = nullptr;
 
     ProductStrategyMap mProductStrategies;
     VolumeGroupMap mVolumeGroups;
+    LastRemovableMediaDevices mLastRemovableMediaDevices;
     audio_mode_t mPhoneState = AUDIO_MODE_NORMAL;  /**< current phone state. */
 
     /** current forced use configuration. */
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
new file mode 100755
index 0000000..88ac7a1
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -0,0 +1,52 @@
+/*

+ * Copyright (C) 2019 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.

+ */

+

+#ifndef ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H

+#define ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H

+

+#include <vector>

+#include <HwModule.h>

+#include <system/audio_policy.h>

+

+namespace android {

+

+typedef enum {

+    GROUP_NONE = -1,

+    GROUP_WIRED,

+    GROUP_BT_A2DP,

+    NUM_GROUP

+} device_out_group_t;

+

+class LastRemovableMediaDevices

+{

+public:

+    void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);

+    std::vector<audio_devices_t> getLastRemovableMediaDevices(

+            device_out_group_t group = GROUP_NONE) const;

+

+private:

+    struct DeviceGroupDescriptor {

+        sp<DeviceDescriptor> desc;

+        device_out_group_t group;

+    };

+    std::vector<DeviceGroupDescriptor> mMediaDevices;

+

+    device_out_group_t getDeviceOutGroup(audio_devices_t device) const;

+};

+

+} // namespace android

+

+#endif // ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
\ No newline at end of file
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 840eb34..45c43d8 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -63,6 +63,17 @@
     return NO_ERROR;
 }
 
+status_t EngineBase::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                              audio_policy_dev_state_t state)
+{
+    audio_devices_t deviceType = devDesc->type();
+    if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
+        mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
+    }
+
+    return NO_ERROR;
+}
+
 product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
 {
     return mProductStrategies.getProductStrategyForAttributes(attr);
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
new file mode 100755
index 0000000..0eb22ce
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -0,0 +1,78 @@
+/*

+ * Copyright (C) 2019 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.

+ */

+

+#define LOG_TAG "APM::AudioPolicyEngine/LastRemovableMediaDevices"

+//#define LOG_NDEBUG 0

+

+#include "LastRemovableMediaDevices.h"

+#include <log/log.h>

+

+namespace android {

+

+void LastRemovableMediaDevices::setRemovableMediaDevices(sp<DeviceDescriptor> desc,

+                                                         audio_policy_dev_state_t state)

+{

+    if (desc == nullptr) {

+        return;

+    } else {

+        if ((state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) &&

+                (getDeviceOutGroup(desc->type()) != GROUP_NONE)) {

+            setRemovableMediaDevices(desc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);

+            mMediaDevices.insert(mMediaDevices.begin(), {desc, getDeviceOutGroup(desc->type())});

+        } else if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {

+            for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {

+                if ((iter->desc)->equals(desc)) {

+                    mMediaDevices.erase(iter);

+                    break;

+                }

+            }

+        }

+    }

+}

+

+std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(

+        device_out_group_t group) const

+{

+    std::vector<audio_devices_t> ret;

+    for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {

+        if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {

+            ret.push_back((iter->desc)->type());

+        }

+    }

+    return ret;

+}

+

+device_out_group_t LastRemovableMediaDevices::getDeviceOutGroup(audio_devices_t device) const

+{

+    switch (device) {

+    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:

+    case AUDIO_DEVICE_OUT_LINE:

+    case AUDIO_DEVICE_OUT_WIRED_HEADSET:

+    case AUDIO_DEVICE_OUT_USB_HEADSET:

+    case AUDIO_DEVICE_OUT_USB_ACCESSORY:

+    case AUDIO_DEVICE_OUT_USB_DEVICE:

+    case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:

+        return GROUP_WIRED;

+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:

+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:

+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:

+        return GROUP_BT_A2DP;

+    default:

+        return GROUP_NONE;

+    }

+}

+

+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 0a88685..752ba92 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -176,7 +176,7 @@
         return mPolicyParameterMgr->setAvailableInputDevices(
                     deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
     }
-    return BAD_TYPE;
+    return EngineBase::setDeviceConnectionState(devDesc, state);
 }
 
 status_t Engine::loadAudioPolicyEngineConfig()
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
old mode 100644
new mode 100755
index 9dc0d64..de7e7ce
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -386,22 +386,20 @@
             devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
         }
         if ((devices2.isEmpty()) &&
-                (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
-                 outputs.isA2dpSupported()) {
-            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
-                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
-                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER});
-        }
-        if ((devices2.isEmpty()) &&
             (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
             devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
-        if (devices2.isEmpty()) {
-            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
-                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_LINE,
-                    AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_USB_HEADSET,
-                    AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
-                    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET});
+        if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
+            if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+                    outputs.isA2dpSupported()) {
+                // Get the last connected device of wired and bluetooth a2dp
+                devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+                        getLastRemovableMediaDevices());
+            } else {
+                // Get the last connected device of wired except bluetooth a2dp
+                devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+                        getLastRemovableMediaDevices(GROUP_WIRED));
+            }
         }
         if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
             // no sonification on aux digital (e.g. HDMI)