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

Commit ffbe61b7 authored by Angela Wang's avatar Angela Wang
Browse files

Seperated ambient mute state for different devices

Store seperated mute state for each devices instead of having an unified mute state. To reflect the mute icon behavior, if one device is mutable then the icon is mutable(clickable); if all devices are muted then the icon will show muted icon.

Flag: EXEMPT bugfix
Bug: 412968925
Test: manually test with real devices
Test: atest AmbientVolumePreferenceTest
Change-Id: Ib25fd1e1efff34fb6cf1b1f0e192fe7b5bb3c644
parent 271c3ca8
Loading
Loading
Loading
Loading
+71 −48
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.settings.bluetooth;

import static android.bluetooth.AudioInputControl.MUTE_DISABLED;
import static android.bluetooth.AudioInputControl.MUTE_MUTED;
import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;
import static android.view.View.GONE;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
@@ -27,6 +30,7 @@ import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_R

import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.ArrayMap;
import android.view.View;
import android.widget.ImageView;

@@ -74,13 +78,12 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
    private View mVolumeIconFrame;
    @Nullable
    private ImageView mVolumeIcon;

    private final BiMap<Integer, SliderPreference> mSideToSliderMap = HashBiMap.create();
    private final Map<Integer, Integer> mSideToMuteStateMap = new ArrayMap<>();
    private boolean mExpandable = true;
    private boolean mExpanded = false;
    private boolean mMutable = false;
    private boolean mMuted = false;
    private final BiMap<Integer, SliderPreference> mSideToSliderMap = HashBiMap.create();
    private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;

    private int mMetricsCategory;

    private final OnPreferenceChangeListener mPreferenceChangeListener =
@@ -127,11 +130,12 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
                : R.drawable.ambient_icon_background;
        mVolumeIconFrame.setBackgroundResource(volumeIconBackgroundResId);
        mVolumeIconFrame.setOnClickListener(v -> {
            if (!mMutable) {
            if (!isMutable()) {
                return;
            }
            setMuted(!mMuted);
            logMetrics(METRIC_KEY_AMBIENT_MUTE, mMuted ? 1 : 0);
            int updatedMuteState = isMuted() ? MUTE_NOT_MUTED : MUTE_MUTED;
            setSliderMuteState(SIDE_UNIFIED, updatedMuteState);
            logMetrics(METRIC_KEY_AMBIENT_MUTE, isMuted() ? 1 : 0);
            if (mListener != null) {
                mListener.onAmbientVolumeIconClick();
            }
@@ -140,6 +144,9 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV

        mExpandIcon = holder.itemView.requireViewById(R.id.expand_icon);
        mExpandIcon.setOnClickListener(v -> {
            if (!isControlExpandable()) {
                return;
            }
            setControlExpanded(!mExpanded);
            logMetrics(METRIC_KEY_AMBIENT_EXPAND, mExpanded ? 1 : 0);
            if (mListener != null) {
@@ -151,12 +158,14 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV

    @Override
    public void setControlExpandable(boolean expandable) {
        if (mExpandable != expandable) {
            mExpandable = expandable;
            if (!mExpandable) {
                setControlExpanded(false);
            }
            updateExpandIcon();
        }
    }

    @Override
    public boolean isControlExpandable() {
@@ -165,13 +174,12 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV

    @Override
    public void setControlExpanded(boolean expanded) {
        if (!mExpandable && expanded) {
            return;
        }
        if (mExpanded != expanded) {
            mExpanded = expanded;
            updateExpandIcon();
            updateLayout();
        }
    }

    @Override
    public boolean isControlExpanded() {
@@ -179,37 +187,51 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
    }

    @Override
    public void setMutable(boolean mutable) {
        mMutable = mutable;
        if (!mMutable) {
            mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
            setMuted(false);
        }
        updateVolumeIcon();
    public boolean isMutable() {
        return mSideToMuteStateMap.values().stream().anyMatch(mute -> mute != MUTE_DISABLED);
    }

    @Override
    public boolean isMutable() {
        return mMutable;
    public boolean isMuted() {
        return mSideToMuteStateMap.values().stream().allMatch(mute -> mute == MUTE_MUTED);
    }

    @Override
    public void setMuted(boolean muted) {
        if (!mMutable && muted) {
            return;
    public void setSliderMuteState(int side, int muteState) {
        if (side == SIDE_UNIFIED) {
            // propagate the mute state to all other sliders
            mSideToSliderMap.keySet().forEach(s -> {
                if (s != SIDE_UNIFIED) {
                    setSliderMuteState(s, muteState);
                }
        mMuted = muted;
        if (mMutable && mMuted) {
            for (SliderPreference slider : mSideToSliderMap.values()) {
            });
        } else {
            SliderPreference slider = mSideToSliderMap.get(side);
            if (slider != null) {
                mSideToMuteStateMap.put(side, muteState);
                if (muteState == MUTE_MUTED) {
                    slider.setValue(slider.getMin());
                }
                SliderPreference unifiedSlider = mSideToSliderMap.get(SIDE_UNIFIED);
                if (isMuted() && unifiedSlider != null) {
                    unifiedSlider.setValue(unifiedSlider.getMin());
                }
                updateVolumeLevel();
            }
        }
        updateVolumeIcon();
    }

    @Override
    public boolean isMuted() {
        return mMuted;
    public int getSliderMuteState(int side) {
        if (side == SIDE_UNIFIED) {
            if (!isMutable()) {
                return MUTE_DISABLED;
            } else {
                return isMuted() ? MUTE_MUTED : MUTE_NOT_MUTED;
            }
        } else {
            return mSideToMuteStateMap.getOrDefault(side, MUTE_DISABLED);
        }
    }

    @Override
@@ -239,7 +261,10 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
        SliderPreference slider = mSideToSliderMap.get(side);
        if (slider != null && slider.isEnabled() != enabled) {
            slider.setEnabled(enabled);
            updateLayout();
            if (!enabled) {
                slider.setValue(slider.getMin());
            }
            updateVolumeLevel();
        }
    }

@@ -269,9 +294,6 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
            } else {
                slider.setVisible(mExpanded);
            }
            if (!slider.isEnabled()) {
                slider.setValue(slider.getMin());
            }
        });
        updateVolumeLevel();
    }
@@ -287,7 +309,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV

    private void updateVolumeLevel() {
        int leftLevel, rightLevel;
        if (mExpanded) {
        if (isControlExpanded()) {
            leftLevel = getVolumeLevel(SIDE_LEFT);
            rightLevel = getVolumeLevel(SIDE_RIGHT);
        } else {
@@ -316,10 +338,11 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
        if (mExpandIcon == null) {
            return;
        }
        mExpandIcon.setVisibility(mExpandable ? VISIBLE : GONE);
        mExpandIcon.setRotation(mExpanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED);
        if (mExpandable) {
            final int stringRes = mExpanded ? R.string.bluetooth_ambient_volume_control_collapse
        mExpandIcon.setVisibility(isControlExpandable() ? VISIBLE : GONE);
        mExpandIcon.setRotation(isControlExpanded() ? ROTATION_EXPANDED : ROTATION_COLLAPSED);
        if (isControlExpandable()) {
            final int stringRes = isControlExpanded()
                    ? R.string.bluetooth_ambient_volume_control_collapse
                    : R.string.bluetooth_ambient_volume_control_expand;
            mExpandIcon.setContentDescription(getContext().getString(stringRes));
        } else {
@@ -331,9 +354,9 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV
        if (mVolumeIcon == null || mVolumeIconFrame == null) {
            return;
        }
        mVolumeIcon.setImageLevel(mMuted ? 0 : mVolumeLevel);
        if (mMutable) {
            final int stringRes = mMuted ? R.string.bluetooth_ambient_volume_unmute
        mVolumeIcon.setImageLevel(mVolumeLevel);
        if (isMutable()) {
            final int stringRes = isMuted() ? R.string.bluetooth_ambient_volume_unmute
                    : R.string.bluetooth_ambient_volume_mute;
            mVolumeIcon.setContentDescription(getContext().getString(stringRes));
            mVolumeIconFrame.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+58 −33
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.settings.bluetooth;

import static android.bluetooth.AudioInputControl.MUTE_DISABLED;
import static android.bluetooth.AudioInputControl.MUTE_MUTED;
import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;

import static com.android.settings.bluetooth.AmbientVolumePreference.ROTATION_COLLAPSED;
import static com.android.settings.bluetooth.AmbientVolumePreference.ROTATION_EXPANDED;
import static com.android.settings.bluetooth.AmbientVolumePreference.SIDE_UNIFIED;
@@ -89,7 +93,6 @@ public class AmbientVolumePreferenceTest {
        mPreference.setKey(KEY_AMBIENT_VOLUME);
        mPreference.setListener(mListener);
        mPreference.setControlExpandable(true);
        mPreference.setMutable(true);
        preferenceScreen.addPreference(mPreference);

        prepareDevices();
@@ -151,69 +154,91 @@ public class AmbientVolumePreferenceTest {
    }

    @Test
    public void setMutable_mutable_clickOnMuteIconChangeMuteState() {
        mPreference.setMutable(true);
        mPreference.setMuted(false);

        mVolumeIcon.callOnClick();
    public void updateLayout_expanded_volumeIconIsCorrect() {
        mPreference.setControlExpanded(true);
        mPreference.updateLayout();

        assertThat(mPreference.isMuted()).isTrue();
        int expectedLevel = calculateVolumeLevel(TEST_LEFT_VOLUME_LEVEL, TEST_RIGHT_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }

    @Test
    public void setMutable_notMutable_clickOnMuteIconWontChangeMuteState() {
        mPreference.setMutable(false);
        mPreference.setMuted(false);

        mVolumeIcon.callOnClick();
    public void updateLayout_notExpanded_volumeIconIsCorrect() {
        mPreference.setControlExpanded(false);
        mPreference.updateLayout();

        assertThat(mPreference.isMuted()).isFalse();
        int expectedLevel = calculateVolumeLevel(TEST_UNIFIED_VOLUME_LEVEL,
                TEST_UNIFIED_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }

    @Test
    public void updateLayout_mute_volumeIconIsCorrect() {
        mPreference.setMuted(true);
        mPreference.updateLayout();
    public void setSliderEnabled_expandedAndLeftIsDisabled_volumeIconIcCorrect() {
        mPreference.setControlExpanded(true);
        mPreference.setSliderEnabled(SIDE_LEFT, false);

        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(0);
        int expectedLevel = calculateVolumeLevel(0, TEST_RIGHT_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }

    @Test
    public void updateLayout_unmuteAndExpanded_volumeIconIsCorrect() {
        mPreference.setMuted(false);
    public void setSliderValue_expandedAndLeftValueChanged_volumeIconIsCorrect() {
        mPreference.setControlExpanded(true);
        mPreference.updateLayout();
        mPreference.setSliderValue(SIDE_LEFT, 4);

        int expectedLevel = calculateVolumeLevel(TEST_LEFT_VOLUME_LEVEL, TEST_RIGHT_VOLUME_LEVEL);
        int expectedLevel = calculateVolumeLevel(4, TEST_RIGHT_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }

    @Test
    public void updateLayout_unmuteAndNotExpanded_volumeIconIsCorrect() {
        mPreference.setMuted(false);
        mPreference.setControlExpanded(false);
        mPreference.updateLayout();
    public void isMutable_bothSideNotMutable_returnFalse() {
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_DISABLED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_DISABLED);

        int expectedLevel = calculateVolumeLevel(TEST_UNIFIED_VOLUME_LEVEL,
                TEST_UNIFIED_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
        assertThat(mPreference.isMutable()).isFalse();
    }

    @Test
    public void setSliderEnabled_expandedAndLeftIsDisabled_volumeIconIcCorrect() {
    public void isMutable_oneSideMutable_returnTrue() {
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_DISABLED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_NOT_MUTED);

        assertThat(mPreference.isMutable()).isTrue();
    }

    @Test
    public void isMuted_bothSideMuted_returnTrue() {
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_MUTED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_MUTED);

        assertThat(mPreference.isMuted()).isTrue();
    }

    @Test
    public void isMuted_oneSideNotMuted_returnFalse() {
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_MUTED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_NOT_MUTED);

        assertThat(mPreference.isMuted()).isFalse();
    }

    @Test
    public void setSliderMuteState_muteLeft_volumeIconIsCorrect() {
        mPreference.setControlExpanded(true);
        mPreference.setSliderEnabled(SIDE_LEFT, false);
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_MUTED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_NOT_MUTED);

        int expectedLevel = calculateVolumeLevel(0, TEST_RIGHT_VOLUME_LEVEL);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }

    @Test
    public void setSliderValue_expandedAndLeftValueChanged_volumeIconIcCorrect() {
    public void setSliderMuteState_muteLeftAndRight_volumeIconIsCorrect() {
        mPreference.setControlExpanded(true);
        mPreference.setSliderValue(SIDE_LEFT, 4);
        mPreference.setSliderMuteState(SIDE_LEFT, MUTE_MUTED);
        mPreference.setSliderMuteState(SIDE_RIGHT, MUTE_MUTED);

        int expectedLevel = calculateVolumeLevel(4, TEST_RIGHT_VOLUME_LEVEL);
        int expectedLevel = calculateVolumeLevel(0, 0);
        assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel);
    }