Skip to content

Commit 266b6d3

Browse files
author
John Qualls
authored
Change the name of AudioDeviceSelector class to AudioSwitch (#56)
* Add modify audio settings permission to manifest * Move all selector classes to the top level package * Rename AudioDeviceSelector -> AudioSwitch * Update changelog * update gradle.properties * Change version in changelog to 0.3.0 * change http to https for jfrog oss url
1 parent 0675fe6 commit 266b6d3

19 files changed

+215
-231
lines changed

CHANGELOG.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
Enhancements
66

7-
- Added `AudioDeviceSelector.VERSION` constant so developers can access the version of AudioSwitch at runtime.
8-
- Added `AudioDeviceSelector.loggingEnabled` property so developers can configure AudioSwitch logging behavior at runtime. By default, AudioSwitch logging is disabled. Reference the following snippet to enable AudioSwitch logging:
7+
- Changed the name of the `AudioDeviceSelector` class to `AudioSwitch`.
8+
- Added the [MODIFY_AUDIO_SETTINGS](https://developer.android.com/reference/android/Manifest.permission#MODIFY_AUDIO_SETTINGS) to the library manifest so it can be automatically consumed by applications.
9+
- Added `AudioSwitch.VERSION` constant so developers can access the version of AudioSwitch at runtime.
10+
- Added `AudioSwitch.loggingEnabled` property so developers can configure AudioSwitch logging behavior at runtime. By default, AudioSwitch logging is disabled. Reference the following snippet to enable AudioSwitch logging:
911

1012
```kotlin
11-
val audioDeviceSelector = AudioDeviceSelector(context)
13+
val audioSwitch = AudioSwitch(context)
1214

13-
audioDeviceSelector.loggingEnabled = true
15+
audioSwitch.loggingEnabled = true
1416

15-
audioDeviceSelector.start { _, _ -> }
17+
audioSwitch.start { _, _ -> }
1618
```
1719

1820
### 0.2.1

README.md

+17-17
Original file line numberDiff line numberDiff line change
@@ -44,57 +44,57 @@ maven {
4444
implementation 'com.twilio:audioswitch:$version-SNAPSHOT'
4545
```
4646

47-
### AudioDeviceSelector Setup
48-
Instantiate an instance of the [AudioDeviceSelector](audioswitch/src/main/java/com/twilio/audioswitch/selection/AudioDeviceSelector.kt) class, passing a reference to the application context.
47+
### AudioSwitch Setup
48+
Instantiate an instance of the [AudioSwitch](audioswitch/src/main/java/com/twilio/audioswitch/AudioSwitch.kt) class, passing a reference to the application context.
4949

5050
```kotlin
51-
val audioDeviceSelector = AudioDeviceSelector(applicationContext)
51+
val audioSwitch = AudioSwitch(applicationContext)
5252
```
5353

5454
### Listen for Devices
55-
To begin listening for live audio device changes, call the start function and pass a lambda that will receive [AudioDevices](audioswitch/src/main/java/com/twilio/audioswitch/selection/AudioDevice.kt) when they become available.
55+
To begin listening for live audio device changes, call the start function and pass a lambda that will receive [AudioDevices](audioswitch/src/main/java/com/twilio/audioswitch/AudioDevice.kt) when they become available.
5656

5757
```kotlin
58-
audioDeviceSelector.start { audioDevices, selectedDevice ->
58+
audioSwitch.start { audioDevices, selectedDevice ->
5959
// TODO update UI with audio devices
6060
}
6161
```
6262
You can also retrieve the available and selected audio devices manually at any time by calling the following properties:
6363
```kotlin
64-
val devices: List<AudioDevice> = audioDeviceSelector.availableAudioDevices
65-
val selectedDevice: AudioDevice? = audioDeviceSelector.selectedAudioDevice
64+
val devices: List<AudioDevice> = audioSwitch.availableAudioDevices
65+
val selectedDevice: AudioDevice? = audioSwitch.selectedAudioDevice
6666
```
6767
**Note:** Don't forget to stop listening for audio devices when no longer needed in order to prevent a memory leak.
6868
```kotlin
69-
audioDeviceSelector.stop()
69+
audioSwitch.stop()
7070
```
7171

7272
### Select a Device
7373
Before activating an AudioDevice, it needs to be selected first.
7474
```kotlin
75-
devices.find { it is AudioDevice.Speakerphone }?.let { audioDeviceSelector.selectDevice(it) }
75+
devices.find { it is AudioDevice.Speakerphone }?.let { audioSwitch.selectDevice(it) }
7676
```
7777
If no device is selected, then the library will automatically select a device based on the following priority: `BluetoothHeadset -> WiredHeadset -> Earpiece -> Speakerphone`.
7878

7979
### Activate a Device
8080
Activating a device acquires audio focus with [voice communication usage](https://developer.android.com/reference/android/media/AudioAttributes#USAGE_VOICE_COMMUNICATION) and begins routing audio input/output to the selected device.
8181
```kotlin
82-
audioDeviceSelector.activate()
82+
audioSwitch.activate()
8383
```
8484
Make sure to revert back to the prior audio state when it makes sense to do so in your app.
8585
```kotlin
86-
audioDeviceSelector.deactivate()
86+
audioSwitch.deactivate()
8787
```
88-
**Note:** The `stop()` function will call `deactivate()` before closing AudioDeviceSelector resources.
88+
**Note:** The `stop()` function will call `deactivate()` before closing AudioSwitch resources.
8989

9090
## Bluetooth Support
9191

9292
Multiple connected bluetooth headsets are supported.
93-
- The library will accurately display the up to date active bluetooth headset within the `AudiodDeviceSelector` `availableAudioDevices` and `selectedAudioDevice` functions.
93+
- The library will accurately display the up to date active bluetooth headset within the `AudioSwitch` `availableAudioDevices` and `selectedAudioDevice` functions.
9494
- Other connected headsets are not stored by the library at this moment.
9595
- In the event of a failure to connecting audio to a bluetooth headset, the library will revert the selected audio device (this is usually the Earpiece on a phone).
9696
- If a user would like to switch between multiple Bluetooth headsets, then they need to switch the active bluetooth headset from the system Bluetooth settings.
97-
- The newly activated headset will be propagated to the `AudiodDeviceSelector` `availableAudioDevices` and `selectedAudioDevice` functions.
97+
- The newly activated headset will be propagated to the `AudioSwitch` `availableAudioDevices` and `selectedAudioDevice` functions.
9898

9999
## Java Compatibility
100100

@@ -105,11 +105,11 @@ Audioswitch is compatible with apps written in Java that [target Java 8](https:/
105105
By default, AudioSwitch logging is disabled. Reference the following snippet to enable AudioSwitch logging:
106106

107107
```kotlin
108-
val audioDeviceSelector = AudioDeviceSelector(context)
108+
val audioSwitch = AudioSwitch(context)
109109

110-
audioDeviceSelector.loggingEnabled = true
110+
audioSwitch.loggingEnabled = true
111111

112-
audioDeviceSelector.start { _, _ -> }
112+
audioSwitch.start { _, _ -> }
113113
```
114114

115115

audioswitch/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ publishing {
9292
}
9393

9494
artifactory {
95-
contextUrl = 'http://oss.jfrog.org'
95+
contextUrl = 'https://oss.jfrog.org'
9696
publish {
9797
repository {
9898
repoKey = 'oss-snapshot-local'

audioswitch/src/androidTest/java/com.twilio.audioswitch/AudioDeviceSelectorTest.kt renamed to audioswitch/src/androidTest/java/com.twilio.audioswitch/AudioSwitchTest.kt

+19-21
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package com.twilio.audioswitch
33
import androidx.test.annotation.UiThreadTest
44
import androidx.test.ext.junit.runners.AndroidJUnit4
55
import androidx.test.platform.app.InstrumentationRegistry
6-
import com.twilio.audioswitch.selection.AudioDevice
7-
import com.twilio.audioswitch.selection.AudioDeviceSelector
86
import junit.framework.TestCase.assertEquals
97
import junit.framework.TestCase.assertFalse
108
import junit.framework.TestCase.assertNotNull
@@ -13,55 +11,55 @@ import org.junit.Test
1311
import org.junit.runner.RunWith
1412

1513
@RunWith(AndroidJUnit4::class)
16-
class AudioDeviceSelectorTest {
14+
class AudioSwitchTest {
1715

1816
private val context = InstrumentationRegistry.getInstrumentation().context
1917

2018
@Test
2119
@UiThreadTest
2220
fun `it_should_disable_logging_by_default`() {
23-
val audioDeviceSelector = AudioDeviceSelector(context)
21+
val audioSwitch = AudioSwitch(context)
2422

25-
assertFalse(audioDeviceSelector.loggingEnabled)
23+
assertFalse(audioSwitch.loggingEnabled)
2624
}
2725

2826
@Test
2927
@UiThreadTest
3028
fun `it_should_allow_enabling_logging`() {
31-
val audioDeviceSelector = AudioDeviceSelector(context)
29+
val audioSwitch = AudioSwitch(context)
3230

33-
audioDeviceSelector.loggingEnabled = true
31+
audioSwitch.loggingEnabled = true
3432

35-
assertTrue(audioDeviceSelector.loggingEnabled)
33+
assertTrue(audioSwitch.loggingEnabled)
3634
}
3735

3836
@Test
3937
@UiThreadTest
4038
fun `it_should_allow_toggling_logging_while_in_use`() {
41-
val audioDeviceSelector = AudioDeviceSelector(context)
42-
audioDeviceSelector.loggingEnabled = true
43-
assertTrue(audioDeviceSelector.loggingEnabled)
44-
audioDeviceSelector.start { _, _ -> }
45-
val earpiece = audioDeviceSelector.availableAudioDevices
39+
val audioSwitch = AudioSwitch(context)
40+
audioSwitch.loggingEnabled = true
41+
assertTrue(audioSwitch.loggingEnabled)
42+
audioSwitch.start { _, _ -> }
43+
val earpiece = audioSwitch.availableAudioDevices
4644
.find { it is AudioDevice.Earpiece }
4745
assertNotNull(earpiece)
48-
audioDeviceSelector.selectDevice(earpiece!!)
49-
assertEquals(earpiece, audioDeviceSelector.selectedAudioDevice)
50-
audioDeviceSelector.stop()
46+
audioSwitch.selectDevice(earpiece!!)
47+
assertEquals(earpiece, audioSwitch.selectedAudioDevice)
48+
audioSwitch.stop()
5149

52-
audioDeviceSelector.loggingEnabled = false
53-
assertFalse(audioDeviceSelector.loggingEnabled)
50+
audioSwitch.loggingEnabled = false
51+
assertFalse(audioSwitch.loggingEnabled)
5452

55-
audioDeviceSelector.start { _, _ -> }
56-
audioDeviceSelector.stop()
53+
audioSwitch.start { _, _ -> }
54+
audioSwitch.stop()
5755
}
5856

5957
@Test
6058
@UiThreadTest
6159
fun `it_should_return_valid_semver_formatted_version`() {
6260
val semVerRegex = Regex("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-([0-9A-" +
6361
"Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+)?$")
64-
val version: String = AudioDeviceSelector.VERSION
62+
val version: String = AudioSwitch.VERSION
6563
assertNotNull(version)
6664
assertTrue(version.matches(semVerRegex))
6765
}

audioswitch/src/androidTest/java/com.twilio.audioswitch/AutomaticDeviceSelectionTest.kt

+7-8
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ package com.twilio.audioswitch
33
import androidx.test.annotation.UiThreadTest
44
import androidx.test.ext.junit.runners.AndroidJUnit4
55
import androidx.test.filters.LargeTest
6-
import com.twilio.audioswitch.selection.AudioDevice.Earpiece
7-
import com.twilio.audioswitch.selection.AudioDeviceSelector
6+
import com.twilio.audioswitch.AudioDevice.Earpiece
87
import org.hamcrest.CoreMatchers.equalTo
98
import org.hamcrest.MatcherAssert.assertThat
109
import org.junit.Assert.assertEquals
@@ -18,20 +17,20 @@ class AutomaticDeviceSelectionTest {
1817
@UiThreadTest
1918
@Test
2019
fun `it_should_select_the_bluetooth_audio_device_by_default`() {
21-
val (audioDeviceSelector, bluetoothHeadsetReceiver) = setupFakeAudioDeviceSelector(getInstrumentationContext())
20+
val (audioSwitch, bluetoothHeadsetReceiver) = setupFakeAudioSwitch(getInstrumentationContext())
2221

23-
audioDeviceSelector.start { _, _ -> }
22+
audioSwitch.start { _, _ -> }
2423
simulateBluetoothSystemIntent(getInstrumentationContext(), bluetoothHeadsetReceiver)
2524

26-
assertEquals("Fake Headset", audioDeviceSelector.selectedAudioDevice!!.name)
25+
assertEquals("Fake Headset", audioSwitch.selectedAudioDevice!!.name)
2726
}
2827

2928
@UiThreadTest
3029
@Test
3130
fun `it_should_select_the_earpiece_audio_device_by_default`() {
32-
val audioDeviceSelector = AudioDeviceSelector(getInstrumentationContext())
33-
audioDeviceSelector.start { _, _ -> }
31+
val audioSwitch = AudioSwitch(getInstrumentationContext())
32+
audioSwitch.start { _, _ -> }
3433

35-
assertThat(audioDeviceSelector.selectedAudioDevice is Earpiece, equalTo(true))
34+
assertThat(audioSwitch.selectedAudioDevice is Earpiece, equalTo(true))
3635
}
3736
}

audioswitch/src/androidTest/java/com.twilio.audioswitch/MultipleBluetoothHeadsetsTest.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ class MultipleBluetoothHeadsetsTest {
1919
@UiThreadTest
2020
@Test
2121
fun `it_should_assert_the_second_bluetooth_headset_when_two_are_connected`() {
22-
val (audioDeviceSelector, bluetoothHeadsetReceiver) = setupFakeAudioDeviceSelector(getInstrumentationContext())
22+
val (audioSwitch, bluetoothHeadsetReceiver) = setupFakeAudioSwitch(getInstrumentationContext())
2323

24-
audioDeviceSelector.start { _, _ -> }
25-
audioDeviceSelector.activate()
24+
audioSwitch.start { _, _ -> }
25+
audioSwitch.activate()
2626
simulateBluetoothSystemIntent(getInstrumentationContext(), bluetoothHeadsetReceiver)
2727
simulateBluetoothSystemIntent(getInstrumentationContext(), bluetoothHeadsetReceiver, HEADSET_2_NAME)
2828

29-
assertThat(audioDeviceSelector.selectedAudioDevice!!.name, equalTo(HEADSET_2_NAME))
30-
assertThat(audioDeviceSelector.availableAudioDevices.first().name, equalTo(HEADSET_2_NAME))
31-
assertThat(audioDeviceSelector.availableAudioDevices.find { it.name == HEADSET_NAME },
29+
assertThat(audioSwitch.selectedAudioDevice!!.name, equalTo(HEADSET_2_NAME))
30+
assertThat(audioSwitch.availableAudioDevices.first().name, equalTo(HEADSET_2_NAME))
31+
assertThat(audioSwitch.availableAudioDevices.find { it.name == HEADSET_NAME },
3232
`is`(nullValue()))
3333
assertThat(isSpeakerPhoneOn(), equalTo(false)) // Best we can do for asserting if a fake BT headset is activated
3434
}

audioswitch/src/androidTest/java/com.twilio.audioswitch/TestUtil.kt

+3-6
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@ import com.twilio.audioswitch.android.FakeBluetoothIntentProcessor
1212
import com.twilio.audioswitch.android.HEADSET_NAME
1313
import com.twilio.audioswitch.android.Logger
1414
import com.twilio.audioswitch.bluetooth.BluetoothHeadsetManager
15-
import com.twilio.audioswitch.selection.AudioDeviceManager
16-
import com.twilio.audioswitch.selection.AudioDeviceSelector
17-
import com.twilio.audioswitch.selection.AudioFocusRequestWrapper
1815
import com.twilio.audioswitch.wired.WiredHeadsetReceiver
1916

20-
internal fun setupFakeAudioDeviceSelector(context: Context):
21-
Pair<AudioDeviceSelector, BluetoothHeadsetManager> {
17+
internal fun setupFakeAudioSwitch(context: Context):
18+
Pair<AudioSwitch, BluetoothHeadsetManager> {
2219

2320
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
2421
val logger = Logger()
@@ -35,7 +32,7 @@ internal fun setupFakeAudioDeviceSelector(context: Context):
3532
} ?: run {
3633
null
3734
}
38-
return Pair(AudioDeviceSelector(logger,
35+
return Pair(AudioSwitch(logger,
3936
audioDeviceManager,
4037
wiredHeadsetReceiver,
4138
headsetManager),

audioswitch/src/androidTest/java/com.twilio.audioswitch/UserDeviceSelectionTest.kt

+18-19
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import androidx.test.annotation.UiThreadTest
44
import androidx.test.ext.junit.runners.AndroidJUnit4
55
import androidx.test.filters.LargeTest
66
import androidx.test.platform.app.InstrumentationRegistry
7-
import com.twilio.audioswitch.selection.AudioDevice.BluetoothHeadset
8-
import com.twilio.audioswitch.selection.AudioDevice.Earpiece
9-
import com.twilio.audioswitch.selection.AudioDevice.Speakerphone
10-
import com.twilio.audioswitch.selection.AudioDeviceSelector
7+
import com.twilio.audioswitch.AudioDevice.BluetoothHeadset
8+
import com.twilio.audioswitch.AudioDevice.Earpiece
9+
import com.twilio.audioswitch.AudioDevice.Speakerphone
1110
import org.hamcrest.CoreMatchers.`is`
1211
import org.hamcrest.CoreMatchers.equalTo
1312
import org.hamcrest.CoreMatchers.notNullValue
@@ -24,43 +23,43 @@ class UserDeviceSelectionTest {
2423
@UiThreadTest
2524
@Test
2625
fun `it_should_select_the_earpiece_audio_device_when_the_user_selects_it`() {
27-
val audioDeviceSelector = AudioDeviceSelector(context)
28-
audioDeviceSelector.start { _, _ -> }
29-
val earpiece = audioDeviceSelector.availableAudioDevices
26+
val audioSwitch = AudioSwitch(context)
27+
audioSwitch.start { _, _ -> }
28+
val earpiece = audioSwitch.availableAudioDevices
3029
.find { it is Earpiece }
3130
assertThat(earpiece, `is`(notNullValue()))
3231

33-
audioDeviceSelector.selectDevice(earpiece!!)
32+
audioSwitch.selectDevice(earpiece!!)
3433

35-
assertThat(audioDeviceSelector.selectedAudioDevice, equalTo(earpiece))
34+
assertThat(audioSwitch.selectedAudioDevice, equalTo(earpiece))
3635
}
3736

3837
@UiThreadTest
3938
@Test
4039
fun `it_should_select_the_speakerphone_audio_device_when_the_user_selects_it`() {
41-
val audioDeviceSelector = AudioDeviceSelector(context)
42-
audioDeviceSelector.start { _, _ -> }
43-
val speakerphone = audioDeviceSelector.availableAudioDevices
40+
val audioSwitch = AudioSwitch(context)
41+
audioSwitch.start { _, _ -> }
42+
val speakerphone = audioSwitch.availableAudioDevices
4443
.find { it is Speakerphone }
4544
assertThat(speakerphone, `is`(notNullValue()))
4645

47-
audioDeviceSelector.selectDevice(speakerphone!!)
46+
audioSwitch.selectDevice(speakerphone!!)
4847

49-
assertThat(audioDeviceSelector.selectedAudioDevice, equalTo(speakerphone))
48+
assertThat(audioSwitch.selectedAudioDevice, equalTo(speakerphone))
5049
}
5150

5251
@UiThreadTest
5352
@Test
5453
fun `it_should_select_the_bluetooth_audio_device_when_the_user_selects_it`() {
55-
val (audioDeviceSelector, bluetoothHeadsetReceiver) = setupFakeAudioDeviceSelector(context)
56-
audioDeviceSelector.start { _, _ -> }
54+
val (audioSwitch, bluetoothHeadsetReceiver) = setupFakeAudioSwitch(context)
55+
audioSwitch.start { _, _ -> }
5756
simulateBluetoothSystemIntent(context, bluetoothHeadsetReceiver)
58-
val bluetoothDevice = audioDeviceSelector.availableAudioDevices
57+
val bluetoothDevice = audioSwitch.availableAudioDevices
5958
.find { it is BluetoothHeadset }
6059
assertThat(bluetoothDevice, `is`(notNullValue()))
6160

62-
audioDeviceSelector.selectDevice(bluetoothDevice!!)
61+
audioSwitch.selectDevice(bluetoothDevice!!)
6362

64-
assertThat(audioDeviceSelector.selectedAudioDevice, equalTo(bluetoothDevice))
63+
assertThat(audioSwitch.selectedAudioDevice, equalTo(bluetoothDevice))
6564
}
6665
}

audioswitch/src/main/AndroidManifest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
package="com.twilio.audioswitch" >
33

44
<uses-permission android:name="android.permission.BLUETOOTH" />
5+
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
56

67
</manifest>

audioswitch/src/main/java/com/twilio/audioswitch/selection/AudioDevice.kt renamed to audioswitch/src/main/java/com/twilio/audioswitch/AudioDevice.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package com.twilio.audioswitch.selection
1+
package com.twilio.audioswitch
22

33
/**
4-
* This class represents a single audio device that has been retrieved by the [AudioDeviceSelector].
4+
* This class represents a single audio device that has been retrieved by the [AudioSwitch].
55
*/
66
sealed class AudioDevice {
77

audioswitch/src/main/java/com/twilio/audioswitch/selection/AudioDeviceChangeListener.kt renamed to audioswitch/src/main/java/com/twilio/audioswitch/AudioDeviceChangeListener.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
package com.twilio.audioswitch.selection
1+
package com.twilio.audioswitch
22

33
/** A listener that receives the most recently available [AudioDevice]s.
44
* Receives a list of the most recently available [AudioDevice]s. Also provides the
5-
* currently selected [AudioDevice] from [AudioDeviceSelector].
5+
* currently selected [AudioDevice] from [AudioSwitch].
66
*
77
* @param audioDevices the list of [AudioDevice]s or an empty list if none are available.
88
* @param selectedAudioDevice the currently selected device or null if no device has been selected.

0 commit comments

Comments
 (0)