Add setting page for the Spatial audio

The Spatial audio settings page control the state for the phone speaker
and the wired headphones

Test: make RunSettingsRoboTests

Bug: 220811398
Change-Id: I49e3fab48186d09357a8481652bdccb4aa5d044a
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cb6bcff..6df5b92 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8531,6 +8531,24 @@
     <!-- Setting summary for controlling how caption text display in real time [CHAR LIMIT=NONE]-->
     <string name="live_caption_summary">Automatically caption media</string>
 
+    <!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
+    <string name="spatial_audio_speaker">Phone speaker</string>
+
+    <!-- Output device type for the wired headphones that is available for spatializer effect. [CHAR LIMIT=NONE]-->
+    <string name="spatial_audio_wired_headphones">Wired headphones</string>
+
+    <!-- Sound: Summary for the spatializer effect. [CHAR LIMIT=NONE]-->
+    <string name="spatial_audio_text">Spatial Audio creates immersive sound that seems like it’s coming from all around you. Only works with some media.</string>
+
+    <!-- Sound: Summary for the Spatial audio setting when it is off. [CHAR LIMIT=NONE]-->
+    <string name="spatial_summary_off">Off</string>
+
+    <!-- Sound: Summary for the Spatial audio setting when it is on with one output device enabled. [CHAR LIMIT=NONE]-->
+    <string name="spatial_summary_on_one">On / <xliff:g id="output device" example="Phone speaker">%1$s</xliff:g></string>
+
+    <!-- Sound: Summary for the Spatial audio setting when it is on with two output devices enabled. [CHAR LIMIT=NONE]-->
+    <string name="spatial_summary_on_two">On / <xliff:g id="output device" example="Phone speaker">%1$s</xliff:g> and <xliff:g id="output device" example="Wired headphones">%2$s</xliff:g></string>
+
     <!-- Sound: Summary for the Do not Disturb option that describes how many automatic rules (schedules) are enabled [CHAR LIMIT=NONE]-->
     <string name="zen_mode_settings_schedules_summary">
         {count, plural,
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index d79594c..f25b6ec 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -111,6 +111,15 @@
         settings:keywords="@string/sound_settings"/>
 
     <!-- Live Caption -110 and Now Playing -105-->
+
+    <!-- Spatial audio -->
+    <Preference
+        android:key="spatial_audio_summary"
+        android:title="@string/spatial_audio_title"
+        android:fragment="com.android.settings.notification.SpatialAudioSettings"
+        android:order="-107"
+        settings:controller="com.android.settings.notification.SpatialAudioParentPreferenceController"/>
+
     <Preference
         android:key="media_controls_summary"
         android:title="@string/media_controls_title"
@@ -154,13 +163,6 @@
         android:ringtoneType="alarm"
         android:order="-60"/>
 
-    <!-- Spatial audio -->
-    <SwitchPreference
-        android:key="spatial_audio"
-        android:title="@string/spatial_audio_title"
-        android:order="-55"
-        settings:controller="com.android.settings.notification.SpatialAudioPreferenceController"/>
-
     <!-- Dial pad tones -->
     <SwitchPreference
         android:key="dial_pad_tones"
diff --git a/res/xml/spatial_audio_settings.xml b/res/xml/spatial_audio_settings.xml
new file mode 100644
index 0000000..da33986
--- /dev/null
+++ b/res/xml/spatial_audio_settings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/spatial_audio_title">
+
+    <com.android.settingslib.widget.TopIntroPreference
+        android:key="spatial_audio_top_intro"
+        android:title="@string/spatial_audio_text"
+        settings:searchable="false"/>
+
+    <SwitchPreference
+        android:key="spatial_audio"
+        android:title="@string/spatial_audio_speaker"
+        settings:controller="com.android.settings.notification.SpatialAudioPreferenceController"/>
+
+    <SwitchPreference
+        android:key="spatial_audio_wired_headphones"
+        android:title="@string/spatial_audio_wired_headphones"
+        settings:controller="com.android.settings.notification.SpatialAudioWiredHeadphonesController"/>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/notification/SpatialAudioParentPreferenceController.java b/src/com/android/settings/notification/SpatialAudioParentPreferenceController.java
new file mode 100644
index 0000000..52eea54
--- /dev/null
+++ b/src/com/android/settings/notification/SpatialAudioParentPreferenceController.java
@@ -0,0 +1,76 @@
+/*
+ * 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.settings.notification;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.Spatializer;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Parent menu summary of the Spatial audio settings
+ */
+public class SpatialAudioParentPreferenceController extends BasePreferenceController {
+    private static final String TAG = "SpatialAudioSetting";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Spatializer mSpatializer;
+    private SpatialAudioPreferenceController mSpatialAudioPreferenceController;
+    private SpatialAudioWiredHeadphonesController mSpatialAudioWiredHeadphonesController;
+
+    public SpatialAudioParentPreferenceController(Context context, String key) {
+        super(context, key);
+        AudioManager audioManager = context.getSystemService(AudioManager.class);
+        mSpatializer = audioManager.getSpatializer();
+        mSpatialAudioPreferenceController = new SpatialAudioPreferenceController(context);
+        mSpatialAudioWiredHeadphonesController = new SpatialAudioWiredHeadphonesController(context);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        int level = mSpatializer.getImmersiveAudioLevel();
+        if (DEBUG) {
+            Log.d(TAG, "spatialization level: " + level);
+        }
+        return level == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE
+                ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        boolean speakerOn = mSpatialAudioPreferenceController.isAvailable()
+                && mSpatialAudioWiredHeadphonesController.isChecked();
+        boolean wiredHeadphonesOn = mSpatialAudioWiredHeadphonesController.isAvailable()
+                && mSpatialAudioWiredHeadphonesController.isChecked();
+        if (speakerOn && wiredHeadphonesOn) {
+            return mContext.getString(R.string.spatial_summary_on_two,
+                    mContext.getString(R.string.spatial_audio_speaker),
+                    mContext.getString(R.string.spatial_audio_wired_headphones));
+        } else if (speakerOn) {
+            return mContext.getString(R.string.spatial_summary_on_one,
+                    mContext.getString(R.string.spatial_audio_speaker));
+        } else if (wiredHeadphonesOn) {
+            return mContext.getString(R.string.spatial_summary_on_one,
+                    mContext.getString(R.string.spatial_audio_wired_headphones));
+        } else {
+            return mContext.getString(R.string.spatial_summary_off);
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/SpatialAudioPreferenceController.java b/src/com/android/settings/notification/SpatialAudioPreferenceController.java
index 7bca516..b9a0776 100644
--- a/src/com/android/settings/notification/SpatialAudioPreferenceController.java
+++ b/src/com/android/settings/notification/SpatialAudioPreferenceController.java
@@ -17,46 +17,61 @@
 package com.android.settings.notification;
 
 import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.Spatializer;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
 
 /**
- * The controller of the Spatial audio setting in the SoundSettings.
+ * The controller of the Spatial audio setting for speaker in the SoundSettings.
  */
 public class SpatialAudioPreferenceController extends TogglePreferenceController {
 
     private static final String KEY_SPATIAL_AUDIO = "spatial_audio";
 
     private final Spatializer mSpatializer;
+    @VisibleForTesting
+    final AudioDeviceAttributes mSpeaker = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, ""
+    );
 
     public SpatialAudioPreferenceController(Context context) {
-        super(context, KEY_SPATIAL_AUDIO);
+        this(context, KEY_SPATIAL_AUDIO);
+    }
+
+    public SpatialAudioPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
         AudioManager audioManager = context.getSystemService(AudioManager.class);
         mSpatializer = audioManager.getSpatializer();
     }
 
     @Override
     public int getAvailabilityStatus() {
-        return mSpatializer.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE
-                ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
+        return mSpatializer.isAvailableForDevice(mSpeaker) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
     public boolean isChecked() {
-        return mSpatializer.isEnabled();
+        return mSpatializer.getCompatibleAudioDevices().contains(mSpeaker);
     }
 
     @Override
     public boolean setChecked(boolean isChecked) {
-        mSpatializer.setEnabled(isChecked);
+        if (isChecked) {
+            mSpatializer.addCompatibleAudioDevice(mSpeaker);
+        } else {
+            mSpatializer.removeCompatibleAudioDevice(mSpeaker);
+        }
         return isChecked == isChecked();
     }
 
     @Override
     public int getSliceHighlightMenuRes() {
-        return R.string.menu_key_notifications;
+        return R.string.menu_key_sound;
     }
 }
diff --git a/src/com/android/settings/notification/SpatialAudioSettings.java b/src/com/android/settings/notification/SpatialAudioSettings.java
new file mode 100644
index 0000000..eb68e87
--- /dev/null
+++ b/src/com/android/settings/notification/SpatialAudioSettings.java
@@ -0,0 +1,69 @@
+/*
+ * 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.settings.notification;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Spatial audio settings located in the sound menu
+ */
+@SearchIndexable
+public class SpatialAudioSettings extends DashboardFragment {
+
+    private static final String TAG = "SpatialAudioSettings";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_SPATIAL_AUDIO;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.spatial_audio_settings;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        controllers.add(new SpatialAudioPreferenceController(context));
+        controllers.add(new SpatialAudioWiredHeadphonesController(context));
+        return controllers;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.spatial_audio_settings) {
+                @Override
+                public List<AbstractPreferenceController> createPreferenceControllers(
+                        Context context) {
+                    return buildPreferenceControllers(context);
+                }
+            };
+}
diff --git a/src/com/android/settings/notification/SpatialAudioWiredHeadphonesController.java b/src/com/android/settings/notification/SpatialAudioWiredHeadphonesController.java
new file mode 100644
index 0000000..cd723f9
--- /dev/null
+++ b/src/com/android/settings/notification/SpatialAudioWiredHeadphonesController.java
@@ -0,0 +1,79 @@
+/*
+ * 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.settings.notification;
+
+import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.Spatializer;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * The controller of the Spatial audio setting for wired headphones in the SoundSettings.
+ */
+public class SpatialAudioWiredHeadphonesController extends TogglePreferenceController {
+
+    private static final String KEY_SPATIAL_AUDIO_WIRED_HEADPHONES =
+            "spatial_audio_wired_headphones";
+
+    private final Spatializer mSpatializer;
+    @VisibleForTesting
+    final AudioDeviceAttributes mWiredHeadphones = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_WIRED_HEADPHONES, ""
+    );
+
+    public SpatialAudioWiredHeadphonesController(Context context) {
+        this(context, KEY_SPATIAL_AUDIO_WIRED_HEADPHONES);
+    }
+
+    public SpatialAudioWiredHeadphonesController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+        AudioManager audioManager = context.getSystemService(AudioManager.class);
+        mSpatializer = audioManager.getSpatializer();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mSpatializer.isAvailableForDevice(mWiredHeadphones) ? AVAILABLE
+                : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mSpatializer.getCompatibleAudioDevices().contains(mWiredHeadphones);
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        if (isChecked) {
+            mSpatializer.addCompatibleAudioDevice(mWiredHeadphones);
+        } else {
+            mSpatializer.removeCompatibleAudioDevice(mWiredHeadphones);
+        }
+        return isChecked == isChecked();
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_sound;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/SpatialAudioParentPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/SpatialAudioParentPreferenceControllerTest.java
new file mode 100644
index 0000000..9242cf0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/SpatialAudioParentPreferenceControllerTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.settings.notification;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.Spatializer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SpatialAudioParentPreferenceControllerTest {
+
+    private static final String KEY = "spatial_audio_summary";
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private AudioManager mAudioManager;
+    @Mock
+    private Spatializer mSpatializer;
+
+    private SpatialAudioParentPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+        when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
+        mController = new SpatialAudioParentPreferenceController(mContext, KEY);
+    }
+
+    @Test
+    public void getAvailabilityStatus_levelNone_shouldReturnUnsupported() {
+        when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
+                Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_levelMultiChannel_shouldReturnAvailable() {
+        when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
+                Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/SpatialAudioPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/SpatialAudioPreferenceControllerTest.java
index 66d18ec..e57b897 100644
--- a/tests/robotests/src/com/android/settings/notification/SpatialAudioPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/SpatialAudioPreferenceControllerTest.java
@@ -30,7 +30,6 @@
 import android.media.Spatializer;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -39,7 +38,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-@Ignore("b/200896161")
 @RunWith(RobolectricTestRunner.class)
 public class SpatialAudioPreferenceControllerTest {
 
@@ -56,36 +54,36 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        when((Object) mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+        when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
         when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
         mController = new SpatialAudioPreferenceController(mContext);
     }
 
     @Test
-    public void getAvailabilityStatus_levelNone_shouldReturnUnsupported() {
-        when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
-                Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE);
+    public void getAvailabilityStatus_unavailable_shouldReturnUnavailable() {
+        when(mSpatializer.isAvailableForDevice(mController.mSpeaker)).thenReturn(false);
+
         assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
     }
 
     @Test
-    public void getAvailabilityStatus_levelMultiChannel_shouldReturnAvailable() {
-        when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
-                Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+    public void getAvailabilityStatus_available_shouldReturnAvailable() {
+        when(mSpatializer.isAvailableForDevice(mController.mSpeaker)).thenReturn(true);
+
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
-    public void setChecked_withTrue_shouldEnableSpatializer() {
+    public void setChecked_withTrue_enablesDeviceSpatializer() {
         mController.setChecked(true);
 
-        verify(mSpatializer).setEnabled(true);
+        verify(mSpatializer).addCompatibleAudioDevice(mController.mSpeaker);
     }
 
     @Test
-    public void setChecked_withFalse_shouldDisableSpatializer() {
+    public void setChecked_withFalse_disablesDeviceSpatializer() {
         mController.setChecked(false);
 
-        verify(mSpatializer).setEnabled(false);
+        verify(mSpatializer).removeCompatibleAudioDevice(mController.mSpeaker);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/SpatialAudioWiredHeadphonesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/SpatialAudioWiredHeadphonesPreferenceControllerTest.java
new file mode 100644
index 0000000..29525e4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/SpatialAudioWiredHeadphonesPreferenceControllerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.settings.notification;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.Spatializer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SpatialAudioWiredHeadphonesPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private AudioManager mAudioManager;
+    @Mock
+    private Spatializer mSpatializer;
+
+    private SpatialAudioWiredHeadphonesController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+        when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
+        mController = new SpatialAudioWiredHeadphonesController(mContext);
+    }
+
+    @Test
+    public void getAvailabilityStatus_unavailable_shouldReturnUnavailable() {
+        when(mSpatializer.isAvailableForDevice(mController.mWiredHeadphones)).thenReturn(false);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_available_shouldReturnAvailable() {
+        when(mSpatializer.isAvailableForDevice(mController.mWiredHeadphones)).thenReturn(true);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void setChecked_withTrue_enablesDeviceSpatializer() {
+        mController.setChecked(true);
+
+        verify(mSpatializer).addCompatibleAudioDevice(mController.mWiredHeadphones);
+    }
+
+    @Test
+    public void setChecked_withFalse_disablesDeviceSpatializer() {
+        mController.setChecked(false);
+
+        verify(mSpatializer).removeCompatibleAudioDevice(mController.mWiredHeadphones);
+    }
+}