Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2b94eaf authored by Mill Chen's avatar Mill Chen
Browse files

[Catalyst] Ring volume migration (2/n)

NO_IFTTT=migrate other feature from controller

Bug: 373978964
Test: atest SeparateRingVolumePreferenceTest
Flag: com.android.settings.flags.catalyst_sound_screen
Change-Id: I4aba4c6688e4284fb23570ac999acf7b4039854d
parent 29bb7485
Loading
Loading
Loading
Loading
+70 −52
Original line number Diff line number Diff line
@@ -18,7 +18,14 @@ package com.android.settings.notification

import android.app.INotificationManager
import android.app.NotificationManager
import android.app.NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import android.media.AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
@@ -36,6 +43,8 @@ import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceIconProvider
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.metadata.ReadWritePermit
@@ -49,19 +58,18 @@ open class SeparateRingVolumePreference :
    RangeValue,
    PreferenceAvailabilityProvider,
    PreferenceIconProvider,
    PreferenceLifecycleProvider,
    PreferenceRestrictionMixin {

    private var broadcastReceiver: BroadcastReceiver? = null

    override val key: String
        get() = KEY

    override val title: Int
        get() = R.string.separate_ring_volume_option_title

    override fun getIcon(context: Context) =
        when {
            VolumeHelper.isMuted(context, STREAM_RING) -> getMuteIcon(context)
            else -> R.drawable.ic_ring_volume
        }
    override fun getIcon(context: Context) = context.getIconRes()

    override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume

@@ -103,67 +111,77 @@ open class SeparateRingVolumePreference :
        super.bind(preference, metadata)
        (preference as VolumeSeekBarPreference).apply {
            setStream(STREAM_RING)
            setMuteIcon(getMuteIcon(preference.context))
            setListener { updateContentDescription(this) }
            setSuppressionText(getSuppressionText(preference.context))
            setMuteIcon(context.getIconRes())
            updateContentDescription(context.getContentDescription())
            setListener { updateContentDescription(context.getContentDescription()) }
            setSuppressionText(context.getSuppressionText())
        }
    }

    override fun onStart(context: PreferenceLifecycleContext) {
        super.onStart(context)
        val receiver =
            object : BroadcastReceiver() {
                override fun onReceive(receiverContext: Context, intent: Intent) {
                    context.notifyPreferenceChange(KEY)
                }
            }
        context.registerReceiver(
            receiver,
            IntentFilter().apply {
                addAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED)
                addAction(INTERNAL_RINGER_MODE_CHANGED_ACTION)
            },
        )
        broadcastReceiver = receiver
    }

    override fun onStop(context: PreferenceLifecycleContext) {
        super.onStop(context)
        broadcastReceiver?.let { context.unregisterReceiver(it) }
    }

    open fun createAudioHelper(context: Context) = AudioHelper(context)

    private fun updateContentDescription(preference: VolumeSeekBarPreference) {
        val context = preference.context
        val ringerMode = getEffectiveRingerMode(context)
        when (ringerMode) {
            RINGER_MODE_VIBRATE ->
                preference.updateContentDescription(
                    context.getString(R.string.ringer_content_description_vibrate_mode)
                )
            RINGER_MODE_SILENT ->
                preference.updateContentDescription(
                    context.getString(R.string.ringer_content_description_silent_mode)
                )
            else -> preference.updateContentDescription(preference.title)
    companion object {
        const val KEY = "separate_ring_volume"
    }
}

    fun getMuteIcon(context: Context): Int {
        val ringerMode = getEffectiveRingerMode(context)
        return when (ringerMode) {
fun Context.getContentDescription() =
    when (getEffectiveRingerMode()) {
        RINGER_MODE_VIBRATE -> getString(R.string.ringer_content_description_vibrate_mode)
        RINGER_MODE_SILENT -> getString(R.string.ringer_content_description_silent_mode)
        else -> getString(R.string.separate_ring_volume_option_title)
    }

fun Context.getIconRes() =
    when (getEffectiveRingerMode()) {
        RINGER_MODE_NORMAL -> R.drawable.ic_ring_volume
        RINGER_MODE_VIBRATE -> R.drawable.ic_volume_ringer_vibrate
        else -> R.drawable.ic_ring_volume_off
    }
    }

    fun getEffectiveRingerMode(context: Context): Int {
        val hasVibrator = context.getSystemService(Vibrator::class.java)?.hasVibrator() ?: false
        val ringerMode = createAudioHelper(context).ringerModeInternal
fun Context.getEffectiveRingerMode(): Int {
    val hasVibrator = getSystemService(Vibrator::class.java)?.hasVibrator() ?: false
    val ringerMode =
        getSystemService(AudioManager::class.java)?.getRingerModeInternal() ?: RINGER_MODE_NORMAL
    return when {
        !hasVibrator && ringerMode == RINGER_MODE_VIBRATE -> RINGER_MODE_SILENT
        else -> ringerMode
    }
}

    private fun getSuppressionText(context: Context): String? {
        val suppressor = NotificationManager.from(context).getEffectsSuppressor()
        val notificationManager =
            INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE)
            )
        val hints = notificationManager.hintsFromListenerNoToken
fun Context.getSuppressionText(): String? {
    val suppressor = NotificationManager.from(this).getEffectsSuppressor()
    val hints =
        INotificationManager.Stub.asInterface(ServiceManager.getService(NOTIFICATION_SERVICE))
            ?.hintsFromListenerNoToken ?: 0
    return when {
            hintsMatch(hints) -> SuppressorHelper.getSuppressionText(context, suppressor)
            else -> null
        }
    }

    private fun hintsMatch(hints: Int) =
        (hints and HINT_HOST_DISABLE_CALL_EFFECTS) != 0 ||
            (hints and HINT_HOST_DISABLE_EFFECTS) != 0

    companion object {
        const val KEY = "separate_ring_volume"
            (hints and HINT_HOST_DISABLE_EFFECTS) != 0 ->
            SuppressorHelper.getSuppressionText(this, suppressor)
        else -> null
    }
}
// LINT.ThenChange(SeparateRingVolumePreferenceController.java)
+45 −45
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settings.notification

import android.content.ContextWrapper
import android.media.AudioManager
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
@@ -36,14 +37,15 @@ import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class SeparateRingVolumePreferenceTest {
    private var audioHelper = mock<AudioHelper>()
    private var audioManager = mock<AudioManager>()
    private var vibrator: Vibrator? = null
    private var ringVolumePreference = SeparateRingVolumePreference()

    private val context =
        object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
            override fun getSystemService(name: String): Any? =
                when {
                    name == getSystemServiceName(Vibrator::class.java) -> vibrator
                when (name) {
                    getSystemServiceName(Vibrator::class.java) -> vibrator
                    getSystemServiceName(AudioManager::class.java) -> audioManager
                    else -> super.getSystemService(name)
                }
        }
@@ -73,78 +75,76 @@ class SeparateRingVolumePreferenceTest {
    @Test
    fun getEffectiveRingerMode_noVibratorAndVibrateMode_shouldReturnSilentMode() {
        vibrator = mock { on { hasVibrator() } doReturn false }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
            }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(ringVolumePreference.getEffectiveRingerMode(context))
            .isEqualTo(RINGER_MODE_SILENT)
        assertThat(context.getEffectiveRingerMode()).isEqualTo(RINGER_MODE_SILENT)
    }

    @Test
    fun getEffectiveRingerMode_hasVibratorAndVibrateMode_shouldReturnVibrateMode() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
            }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(ringVolumePreference.getEffectiveRingerMode(context))
            .isEqualTo(RINGER_MODE_VIBRATE)
        assertThat(context.getEffectiveRingerMode()).isEqualTo(RINGER_MODE_VIBRATE)
    }

    @Test
    fun getEffectiveRingerMode_hasVibratorAndNormalMode_shouldReturnNormalMode() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_NORMAL }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
            }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_NORMAL }

        assertThat(ringVolumePreference.getEffectiveRingerMode(context))
            .isEqualTo(RINGER_MODE_NORMAL)
        assertThat(context.getEffectiveRingerMode()).isEqualTo(RINGER_MODE_NORMAL)
    }

    @Test
    fun getMuteIcon_normalMode_shouldReturnRingVolumeIcon() {
    fun getIconRes_normalMode_shouldReturnRingVolumeIcon() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_NORMAL }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
            }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_NORMAL }

        assertThat(ringVolumePreference.getMuteIcon(context)).isEqualTo(R.drawable.ic_ring_volume)
        assertThat(context.getIconRes()).isEqualTo(R.drawable.ic_ring_volume)
    }

    @Test
    fun getMuteIcon_vibrateMode_shouldReturnVibrateIcon() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
            }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(ringVolumePreference.getMuteIcon(context))
            .isEqualTo(R.drawable.ic_volume_ringer_vibrate)
        assertThat(context.getIconRes()).isEqualTo(R.drawable.ic_volume_ringer_vibrate)
    }

    @Test
    fun getMuteIcon_silentMode_shouldReturnSilentIcon() {
        vibrator = mock { on { hasVibrator() } doReturn false }
        audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
        ringVolumePreference =
            spy(ringVolumePreference).stub {
                onGeneric { createAudioHelper(context) } doReturn audioHelper
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(context.getIconRes()).isEqualTo(R.drawable.ic_ring_volume_off)
    }

        assertThat(ringVolumePreference.getMuteIcon(context))
            .isEqualTo(R.drawable.ic_ring_volume_off)
    @Test
    fun getContentDescription_normalMode_shouldReturnTitleDescription() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_NORMAL }

        assertThat(context.getContentDescription())
            .isEqualTo(context.getString(R.string.separate_ring_volume_option_title))
    }

    @Test
    fun getContentDescription_vibrateMode_shouldReturnVibrateModeDescription() {
        vibrator = mock { on { hasVibrator() } doReturn true }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(context.getContentDescription())
            .isEqualTo(context.getString(R.string.ringer_content_description_vibrate_mode))
    }

    @Test
    fun getContentDescription_silentMode_shouldReturnSilentModeDescription() {
        vibrator = mock { on { hasVibrator() } doReturn false }
        audioManager = mock { on { getRingerModeInternal() } doReturn RINGER_MODE_VIBRATE }

        assertThat(context.getContentDescription())
            .isEqualTo(context.getString(R.string.ringer_content_description_silent_mode))
    }
}
// LINT.ThenChange(SeparateRingVolumePreferenceControllerTest.java)