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

Commit e6c6f738 authored by Angela Wang's avatar Angela Wang Committed by Android (Google) Code Review
Browse files

Merge "Seperated ambient mute state for different devices" into main

parents 887dec9e ffbe61b7
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);
    }