Allow users to open switcher in call for desktop

When input routing is enabled in desktop devices, allow users to open
switcher dialog during call/meeting.

Change-Id: Ia88352a4fb1619b08f86710cf21557fb3df7479a
Bug: b/355684672, b/357123258
Test: atest MediaOutputComponentInteractorTest
Flag: com.android.media.flags.enable_audio_input_device_routing_and_volume_control
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index feaf7fb..b94e906 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -15,6 +15,7 @@
  */
 package com.android.settingslib.media;
 
+import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
 import static android.media.MediaRoute2Info.TYPE_DOCK;
 import static android.media.MediaRoute2Info.TYPE_HDMI;
@@ -29,8 +30,6 @@
 import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
 
 import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
@@ -43,6 +42,8 @@
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.settingslib.R;
 import com.android.settingslib.media.flags.Flags;
@@ -72,7 +73,7 @@
             return context.getString(R.string.media_transfer_this_device_name_tv);
         } else if (isTablet()) {
             return context.getString(R.string.media_transfer_this_device_name_tablet);
-        } else if (inputRoutingEnabledAndIsDesktop()) {
+        } else if (inputRoutingEnabledAndIsDesktop(context)) {
             return context.getString(R.string.media_transfer_this_device_name_desktop);
         } else {
             return context.getString(R.string.media_transfer_this_device_name);
@@ -88,7 +89,7 @@
             case TYPE_WIRED_HEADSET:
             case TYPE_WIRED_HEADPHONES:
                 name =
-                        inputRoutingEnabledAndIsDesktop()
+                        inputRoutingEnabledAndIsDesktop(context)
                                 ? context.getString(R.string.media_transfer_headphone_name)
                                 : context.getString(R.string.media_transfer_wired_headphone_name);
                 break;
@@ -96,7 +97,7 @@
             case TYPE_USB_HEADSET:
             case TYPE_USB_ACCESSORY:
                 name =
-                        inputRoutingEnabledAndIsDesktop()
+                        inputRoutingEnabledAndIsDesktop(context)
                                 ? context.getString(R.string.media_transfer_usb_audio_name)
                                 : context.getString(R.string.media_transfer_wired_headphone_name);
                 break;
@@ -149,14 +150,13 @@
                 .contains("tablet");
     }
 
-    static boolean isDesktop() {
-        return Arrays.asList(SystemProperties.get("ro.build.characteristics").split(","))
-                .contains("desktop");
+    public static boolean isDesktop(@NonNull Context context) {
+        return context.getPackageManager().hasSystemFeature(FEATURE_PC);
     }
 
-    static boolean inputRoutingEnabledAndIsDesktop() {
+    public static boolean inputRoutingEnabledAndIsDesktop(@NonNull Context context) {
         return com.android.media.flags.Flags.enableAudioInputDeviceRoutingAndVolumeControl()
-                && isDesktop();
+                && isDesktop(context);
     }
 
     // MediaRoute2Info.getType was made public on API 34, but exists since API 30.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
index fa7f37c..449dc20 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
@@ -16,11 +16,16 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import android.content.mockedContext
+import android.content.packageManager
+import android.content.pm.PackageManager.FEATURE_PC
 import android.graphics.drawable.TestStubDrawable
 import android.media.AudioManager
+import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.media.flags.Flags;
 import com.android.settingslib.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -42,6 +47,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
 
 private const val builtInDeviceName = "This phone"
 
@@ -79,6 +85,8 @@
     fun inCall_stateIs_Calling() =
         with(kosmos) {
             testScope.runTest {
+                whenever(mockedContext.getPackageManager()).thenReturn(packageManager)
+                whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(false)
                 with(audioRepository) {
                     setMode(AudioManager.MODE_IN_CALL)
                     setCommunicationDevice(TestAudioDevicesFactory.builtInDevice())
@@ -98,6 +106,33 @@
             }
         }
 
+    @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+    @Test
+    fun inCall_stateIs_Calling_enableInputRouting_desktop() =
+        with(kosmos) {
+            testScope.runTest {
+                whenever(mockedContext.getPackageManager()).thenReturn(packageManager)
+                whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(true)
+
+                with(audioRepository) {
+                    setMode(AudioManager.MODE_IN_CALL)
+                    setCommunicationDevice(TestAudioDevicesFactory.builtInDevice())
+                }
+
+                val model by collectLastValue(underTest.mediaOutputModel.filterData())
+                runCurrent()
+
+                assertThat(model)
+                    .isEqualTo(
+                        MediaOutputComponentModel.Calling(
+                            device = AudioOutputDevice.BuiltIn(builtInDeviceName, testIcon),
+                            isInAudioSharing = false,
+                            canOpenAudioSwitcher = true,
+                        )
+                    )
+            }
+        }
+
     @Test
     fun hasSession_stateIs_MediaSession() =
         with(kosmos) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
index f94cbda..609ba02 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
@@ -16,7 +16,10 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import com.android.settingslib.media.PhoneMediaDevice.inputRoutingEnabledAndIsDesktop
+import android.content.Context
 import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
 import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
 import com.android.systemui.volume.domain.model.AudioOutputDevice
@@ -46,6 +49,7 @@
 class MediaOutputComponentInteractor
 @Inject
 constructor(
+    @Application private val context: Context,
     @VolumePanelScope private val coroutineScope: CoroutineScope,
     private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
     audioOutputInteractor: AudioOutputInteractor,
@@ -91,7 +95,8 @@
                         MediaOutputComponentModel.Calling(
                             device = currentAudioDevice,
                             isInAudioSharing = isInAudioSharing,
-                            canOpenAudioSwitcher = false,
+                            /* allow open switcher when input routing is enabled in desktop */
+                            canOpenAudioSwitcher = inputRoutingEnabledAndIsDesktop(context),
                         )
                     )
                 } else {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
index 63a1325..db66c3e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
 
+import android.content.mockedContext
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.volume.domain.interactor.audioModeInteractor
@@ -27,6 +28,7 @@
 val Kosmos.mediaOutputComponentInteractor by
     Kosmos.Fixture {
         MediaOutputComponentInteractor(
+            mockedContext,
             testScope.backgroundScope,
             mediaDeviceSessionInteractor,
             audioOutputInteractor,