Skip to content

Commit

Permalink
feat(android): add custom transparency/noise canceling
Browse files Browse the repository at this point in the history
Adds support for custom transparency modes and custom noise canceling
mode.
  • Loading branch information
Oppzippy committed Aug 17, 2023
1 parent 6f9c003 commit 5af9c0a
Show file tree
Hide file tree
Showing 23 changed files with 521 additions and 40 deletions.
112 changes: 112 additions & 0 deletions android/app/schemas/com.oppzippy.openscq30.room.AppDatabase/5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"formatVersion": 1,
"database": {
"version": 5,
"identityHash": "3b07aa86fadee45ee085045a3eccae5b",
"entities": [
{
"tableName": "equalizer_custom_profile",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `values` BLOB NOT NULL, PRIMARY KEY(`name`))",
"fields": [
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "values",
"columnName": "values",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"name"
]
},
"indices": [
{
"name": "index_equalizer_custom_profile_values",
"unique": true,
"columnNames": [
"values"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_equalizer_custom_profile_values` ON `${TABLE_NAME}` (`values`)"
}
],
"foreignKeys": []
},
{
"tableName": "quick_preset",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `ambientSoundMode` TEXT, `noiseCancelingMode` TEXT, `transparencyMode` TEXT, `customNoiseCanceling` INTEGER, `presetEqualizerProfile` TEXT, `customEqualizerProfileName` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ambientSoundMode",
"columnName": "ambientSoundMode",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "noiseCancelingMode",
"columnName": "noiseCancelingMode",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "transparencyMode",
"columnName": "transparencyMode",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "customNoiseCanceling",
"columnName": "customNoiseCanceling",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "presetEqualizerProfile",
"columnName": "presetEqualizerProfile",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "customEqualizerProfileName",
"columnName": "customEqualizerProfileName",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3b07aa86fadee45ee085045a3eccae5b')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasTextExactly
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
Expand All @@ -14,6 +15,7 @@ import com.oppzippy.openscq30.features.quickpresets.storage.QuickPresetDao
import com.oppzippy.openscq30.lib.bindings.AmbientSoundMode
import com.oppzippy.openscq30.lib.bindings.NoiseCancelingMode
import com.oppzippy.openscq30.lib.bindings.PresetEqualizerProfile
import com.oppzippy.openscq30.lib.bindings.TransparencyMode
import com.oppzippy.openscq30.ui.quickpresets.QuickPresetScreen
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
Expand Down Expand Up @@ -51,6 +53,8 @@ class DeviceSettingsQuickPresetsTest {
private lateinit var name: SemanticsMatcher
private lateinit var ambientSoundMode: SemanticsMatcher
private lateinit var noiseCancelingMode: SemanticsMatcher
private lateinit var transparencyMode: SemanticsMatcher
private lateinit var customNoiseCanceling: SemanticsMatcher
private lateinit var equalizer: SemanticsMatcher
private lateinit var presetProfile: SemanticsMatcher
private lateinit var customProfile: SemanticsMatcher
Expand All @@ -64,6 +68,10 @@ class DeviceSettingsQuickPresetsTest {
hasTextExactly(composeRule.activity.getString(R.string.ambient_sound_mode))
noiseCancelingMode =
hasTextExactly(composeRule.activity.getString(R.string.noise_canceling_mode))
transparencyMode =
hasTextExactly(composeRule.activity.getString(R.string.transparency_mode))
customNoiseCanceling =
hasTextExactly(composeRule.activity.getString(R.string.custom_noise_canceling))
equalizer = hasTextExactly(composeRule.activity.getString(R.string.equalizer))
presetProfile = hasTestTag("quickPresetPresetEqualizerProfile")
customProfile = hasTestTag("quickPresetCustomEqualizerProfile")
Expand Down Expand Up @@ -95,6 +103,21 @@ class DeviceSettingsQuickPresetsTest {
assertEquals(AmbientSoundMode.Transparency, quickPresetDao.get(0)?.ambientSoundMode)
}

@Test
fun acceptsTransparencyMode() = runTest {
composeRule.setContent {
QuickPresetScreen()
}
assertEquals(null, quickPresetDao.get(0)?.transparencyMode)

composeRule.onNode(transparencyMode).performClick()
assertEquals(TransparencyMode.VocalMode, quickPresetDao.get(0)?.transparencyMode)

composeRule.onNodeWithText(composeRule.activity.getString(R.string.fully_transparent))
.performClick()
assertEquals(TransparencyMode.FullyTransparent, quickPresetDao.get(0)?.transparencyMode)
}

@Test
fun acceptsNoiseCancelingMode() = runTest {
composeRule.setContent {
Expand All @@ -109,6 +132,21 @@ class DeviceSettingsQuickPresetsTest {
assertEquals(NoiseCancelingMode.Outdoor, quickPresetDao.get(0)?.noiseCancelingMode)
}

@Test
fun acceptsCustomNoiseCanceling() = runTest {
composeRule.setContent {
QuickPresetScreen()
}
assertEquals(null, quickPresetDao.get(0)?.customNoiseCanceling)

composeRule.onNode(customNoiseCanceling).performClick()
assertEquals(0.toShort(), quickPresetDao.get(0)?.customNoiseCanceling?.value())

composeRule.onNodeWithTag("customNoiseCancelingSlider").performClick()
// clicks in the middle of the 0-10 slider, which is 5
assertEquals(5.toShort(), quickPresetDao.get(0)?.customNoiseCanceling?.value())
}

@Test
fun acceptsPresetEqualizerProfile() = runTest {
composeRule.setContent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.oppzippy.openscq30
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assertIsNotSelected
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasTextExactly
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.performClick
Expand All @@ -11,6 +12,7 @@ import com.oppzippy.openscq30.lib.bindings.CustomNoiseCanceling
import com.oppzippy.openscq30.lib.bindings.NoiseCancelingMode
import com.oppzippy.openscq30.lib.bindings.SoundModes
import com.oppzippy.openscq30.lib.bindings.TransparencyMode
import com.oppzippy.openscq30.ui.soundmode.NoiseCancelingType
import com.oppzippy.openscq30.ui.soundmode.SoundModeSettings
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
Expand Down Expand Up @@ -39,7 +41,11 @@ class DeviceSettingsSoundModeTest {
private lateinit var noiseCancelingModes: List<SemanticsMatcher>
private lateinit var outdoor: SemanticsMatcher
private lateinit var indoor: SemanticsMatcher
private lateinit var custom: SemanticsMatcher
private lateinit var transport: SemanticsMatcher
private lateinit var fullyTransparent: SemanticsMatcher
private lateinit var vocalMode: SemanticsMatcher
private lateinit var customNoiseCanceling: SemanticsMatcher

@Before
fun setUp() {
Expand All @@ -50,9 +56,14 @@ class DeviceSettingsSoundModeTest {
noiseCanceling = hasTextExactly(composeRule.activity.getString(R.string.noise_canceling))
outdoor = hasTextExactly(composeRule.activity.getString(R.string.outdoor))
indoor = hasTextExactly(composeRule.activity.getString(R.string.indoor))
custom = hasTextExactly(composeRule.activity.getString(R.string.custom))
transport = hasTextExactly(composeRule.activity.getString(R.string.transport))
fullyTransparent =
hasTextExactly(composeRule.activity.getString(R.string.fully_transparent))
vocalMode = hasTextExactly(composeRule.activity.getString(R.string.vocal_mode))
customNoiseCanceling = hasTestTag("customNoiseCancelingSlider")
ambientSoundModes = listOf(normal, transparency, noiseCanceling)
noiseCancelingModes = listOf(outdoor, indoor, transport)
noiseCancelingModes = listOf(outdoor, indoor, transport, custom)
}

@Test
Expand Down Expand Up @@ -83,6 +94,8 @@ class DeviceSettingsSoundModeTest {
CustomNoiseCanceling(0),
),
onAmbientSoundModeChange = onAmbientSoundModeChange,
hasTransparencyModes = false,
noiseCancelingType = NoiseCancelingType.None,
)
}
composeRule.onNode(transparency).performClick()
Expand All @@ -91,6 +104,30 @@ class DeviceSettingsSoundModeTest {
}
}

@Test
fun setsTransparencyMode() {
val onTransparencyModeChange =
mockk<(transparencyMode: TransparencyMode) -> Unit>(relaxed = true)

composeRule.setContent {
SoundModeSettings(
soundModes = SoundModes(
AmbientSoundMode.Normal,
NoiseCancelingMode.Indoor,
TransparencyMode.VocalMode,
CustomNoiseCanceling(0),
),
onTransparencyModeChange = onTransparencyModeChange,
hasTransparencyModes = true,
noiseCancelingType = NoiseCancelingType.None,
)
}
composeRule.onNode(fullyTransparent).performClick()
verify(exactly = 1) {
onTransparencyModeChange(TransparencyMode.FullyTransparent)
}
}

@Test
fun setsNoiseCancelingMode() {
val onNoiseCancelingModeChange =
Expand All @@ -105,6 +142,8 @@ class DeviceSettingsSoundModeTest {
CustomNoiseCanceling(0),
),
onNoiseCancelingModeChange = onNoiseCancelingModeChange,
hasTransparencyModes = true,
noiseCancelingType = NoiseCancelingType.Custom,
)
}
composeRule.onNode(outdoor).performClick()
Expand All @@ -113,6 +152,31 @@ class DeviceSettingsSoundModeTest {
}
}

@Test
fun setsCustomNoiseCanceling() {
val onCustomNoiseCancelingChange =
mockk<(customNoiseCanceling: CustomNoiseCanceling) -> Unit>(relaxed = true)

composeRule.setContent {
SoundModeSettings(
soundModes = SoundModes(
AmbientSoundMode.Normal,
NoiseCancelingMode.Custom,
TransparencyMode.VocalMode,
CustomNoiseCanceling(0),
),
onCustomNoiseCancelingChange = onCustomNoiseCancelingChange,
hasTransparencyModes = false,
noiseCancelingType = NoiseCancelingType.Custom,
)
}
// clicks in the middle of the 0-10 slider, so 5
composeRule.onNode(customNoiseCanceling).performClick()
verify(exactly = 1) {
onCustomNoiseCancelingChange(any())
}
}

private fun renderInitialSoundMode(
ambientSoundMode: AmbientSoundMode,
noiseCancelingMode: NoiseCancelingMode,
Expand All @@ -125,6 +189,8 @@ class DeviceSettingsSoundModeTest {
TransparencyMode.VocalMode,
CustomNoiseCanceling(0),
),
hasTransparencyModes = true,
noiseCancelingType = NoiseCancelingType.Custom,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.oppzippy.openscq30.features.quickpresets.storage
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.oppzippy.openscq30.lib.bindings.AmbientSoundMode
import com.oppzippy.openscq30.lib.bindings.CustomNoiseCanceling
import com.oppzippy.openscq30.lib.bindings.NoiseCancelingMode
import com.oppzippy.openscq30.lib.bindings.PresetEqualizerProfile
import com.oppzippy.openscq30.lib.bindings.TransparencyMode

@Entity(
tableName = "quick_preset",
Expand All @@ -14,6 +16,8 @@ data class QuickPreset(
val name: String? = null,
val ambientSoundMode: AmbientSoundMode? = null,
val noiseCancelingMode: NoiseCancelingMode? = null,
val transparencyMode: TransparencyMode? = null,
val customNoiseCanceling: CustomNoiseCanceling? = null,
val presetEqualizerProfile: PresetEqualizerProfile? = null,
val customEqualizerProfileName: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ sealed class Packet {
}
}

class SoundModeUpdate(val packet: SoundModeUpdatePacket) : Packet()
class StateUpdate(val packet: StateUpdatePacket) : Packet()
class SetSoundModeOk(val packet: SetSoundModeOkPacket) : Packet()
class SetEqualizerOk(val packet: SetEqualizerOkPacket) : Packet()
class SoundModeUpdate(val inner: SoundModeUpdatePacket) : Packet()
class StateUpdate(val inner: StateUpdatePacket) : Packet()
class SetSoundModeOk(val inner: SetSoundModeOkPacket) : Packet()
class SetEqualizerOk(val inner: SetEqualizerOkPacket) : Packet()
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ class SoundcoreDeviceFactoryImpl(private val context: Context) : SoundcoreDevice
}

val packet = callbacks.packetsFlow.first { it is Packet.StateUpdate } as Packet.StateUpdate
return SoundcoreDeviceImpl(gatt, callbacks, scope, packet.packet.toSoundcoreDeviceState())
return SoundcoreDeviceImpl(gatt, callbacks, scope, packet.inner.toSoundcoreDeviceState())
}
}
Loading

0 comments on commit 5af9c0a

Please sign in to comment.