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

Commit 955b2132 authored by jiabin's avatar jiabin
Browse files

Refactor audio device type in audio frameworks.

As audio device type can not be used as bit mask any more, refactoring
the code to use a set for a combination of audio device type instead.

Bug: 135621476
Test: atest AudioDeviceBrokerTest
Test: audio smoke test
Change-Id: I2c6fabfafcc6eaf607975076d9ee1a78887a2c85
Merged-In: I2c6fabfafcc6eaf607975076d9ee1a78887a2c85
parent e16beef1
Loading
Loading
Loading
Loading
+142 −72
Original line number Diff line number Diff line
@@ -30,7 +30,9 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
 * TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java.
@@ -541,51 +543,75 @@ public class AudioSystem

    public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;

    public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
                                              DEVICE_OUT_SPEAKER |
                                              DEVICE_OUT_WIRED_HEADSET |
                                              DEVICE_OUT_WIRED_HEADPHONE |
                                              DEVICE_OUT_BLUETOOTH_SCO |
                                              DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
                                              DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
                                              DEVICE_OUT_BLUETOOTH_A2DP |
                                              DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                                              DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
                                              DEVICE_OUT_HDMI |
                                              DEVICE_OUT_ANLG_DOCK_HEADSET |
                                              DEVICE_OUT_DGTL_DOCK_HEADSET |
                                              DEVICE_OUT_USB_ACCESSORY |
                                              DEVICE_OUT_USB_DEVICE |
                                              DEVICE_OUT_REMOTE_SUBMIX |
                                              DEVICE_OUT_TELEPHONY_TX |
                                              DEVICE_OUT_LINE |
                                              DEVICE_OUT_HDMI_ARC |
                                              DEVICE_OUT_SPDIF |
                                              DEVICE_OUT_FM |
                                              DEVICE_OUT_AUX_LINE |
                                              DEVICE_OUT_SPEAKER_SAFE |
                                              DEVICE_OUT_IP |
                                              DEVICE_OUT_BUS |
                                              DEVICE_OUT_PROXY |
                                              DEVICE_OUT_USB_HEADSET |
                                              DEVICE_OUT_HEARING_AID |
                                              DEVICE_OUT_DEFAULT);
    public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
                                                   DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                                                   DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
    public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
                                                  DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
                                                  DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
    // Deprecated in R because multiple device types are no longer accessed as a bit mask.
    // Removing this will get lint warning about changing hidden apis.
    @UnsupportedAppUsage
    public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
                                                  DEVICE_OUT_USB_DEVICE |
                                                  DEVICE_OUT_USB_HEADSET);
    public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
                                                                DEVICE_OUT_HDMI_ARC |
                                                                DEVICE_OUT_SPDIF);
    public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER =
            (DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO |
             DEVICE_OUT_SPEAKER);

    public static final Set<Integer> DEVICE_OUT_ALL_SET;
    public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET;
    public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET;
    public static final Set<Integer> DEVICE_OUT_ALL_USB_SET;
    public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET;
    public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET;
    static {
        DEVICE_OUT_ALL_SET = new HashSet<>();
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADSET);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADPHONE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ANLG_DOCK_HEADSET);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DGTL_DOCK_HEADSET);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_ACCESSORY);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_DEVICE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_REMOTE_SUBMIX);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_TELEPHONY_TX);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_LINE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI_ARC);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPDIF);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_FM);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID);
        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT);

        DEVICE_OUT_ALL_A2DP_SET = new HashSet<>();
        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);

        DEVICE_OUT_ALL_SCO_SET = new HashSet<>();
        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);

        DEVICE_OUT_ALL_USB_SET = new HashSet<>();
        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_ACCESSORY);
        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_DEVICE);
        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_HEADSET);

        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET = new HashSet<>();
        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_AUX_LINE);
        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_HDMI_ARC);
        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_SPDIF);

        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>();
        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET);
        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER);
    }

    // input devices
    @UnsupportedAppUsage
@@ -633,37 +659,47 @@ public class AudioSystem
    @UnsupportedAppUsage
    public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;

    public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
                                             DEVICE_IN_AMBIENT |
                                             DEVICE_IN_BUILTIN_MIC |
                                             DEVICE_IN_BLUETOOTH_SCO_HEADSET |
                                             DEVICE_IN_WIRED_HEADSET |
                                             DEVICE_IN_HDMI |
                                             DEVICE_IN_TELEPHONY_RX |
                                             DEVICE_IN_BACK_MIC |
                                             DEVICE_IN_REMOTE_SUBMIX |
                                             DEVICE_IN_ANLG_DOCK_HEADSET |
                                             DEVICE_IN_DGTL_DOCK_HEADSET |
                                             DEVICE_IN_USB_ACCESSORY |
                                             DEVICE_IN_USB_DEVICE |
                                             DEVICE_IN_FM_TUNER |
                                             DEVICE_IN_TV_TUNER |
                                             DEVICE_IN_LINE |
                                             DEVICE_IN_SPDIF |
                                             DEVICE_IN_BLUETOOTH_A2DP |
                                             DEVICE_IN_LOOPBACK |
                                             DEVICE_IN_IP |
                                             DEVICE_IN_BUS |
                                             DEVICE_IN_PROXY |
                                             DEVICE_IN_USB_HEADSET |
                                             DEVICE_IN_BLUETOOTH_BLE |
                                             DEVICE_IN_HDMI_ARC |
                                             DEVICE_IN_ECHO_REFERENCE |
                                             DEVICE_IN_DEFAULT);
    public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
    public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
                                                 DEVICE_IN_USB_DEVICE |
                                                 DEVICE_IN_USB_HEADSET);
    public static final Set<Integer> DEVICE_IN_ALL_SET;
    public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
    public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
    static {
        DEVICE_IN_ALL_SET = new HashSet<>();
        DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_AMBIENT);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BUILTIN_MIC);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_WIRED_HEADSET);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_TELEPHONY_RX);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BACK_MIC);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_REMOTE_SUBMIX);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_ANLG_DOCK_HEADSET);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_DGTL_DOCK_HEADSET);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_ACCESSORY);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_DEVICE);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_FM_TUNER);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_TV_TUNER);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_LINE);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_SPDIF);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_A2DP);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_LOOPBACK);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_IP);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BUS);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_PROXY);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_HEADSET);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE);
        DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT);

        DEVICE_IN_ALL_SCO_SET = new HashSet<>();
        DEVICE_IN_ALL_SCO_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);

        DEVICE_IN_ALL_USB_SET = new HashSet<>();
        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
    }

    // device states, must match AudioSystem::device_connection_state
    @UnsupportedAppUsage
@@ -1222,6 +1258,40 @@ public class AudioSystem
        return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume;
    }

    /**
     * Return a set of audio device types from a bit mask audio device type, which may
     * represent multiple audio device types.
     * FIXME: Remove this when getting ride of bit mask usage of audio device types.
     */
    public static Set<Integer> generateAudioDeviceTypesSet(int types) {
        Set<Integer> deviceTypes = new HashSet<>();
        Set<Integer> allDeviceTypes =
                (types & DEVICE_BIT_IN) == 0 ? DEVICE_OUT_ALL_SET : DEVICE_IN_ALL_SET;
        for (int deviceType : allDeviceTypes) {
            if ((types & deviceType) == deviceType) {
                deviceTypes.add(deviceType);
            }
        }
        return deviceTypes;
    }

    /**
     * Return the intersection of two audio device types collections.
     */
    public static Set<Integer> intersectionAudioDeviceTypes(
            @NonNull Set<Integer> a, @NonNull Set<Integer> b) {
        Set<Integer> intersection = new HashSet<>(a);
        intersection.retainAll(b);
        return intersection;
    }

    /**
     * Return true if the audio device types collection only contains the given device type.
     */
    public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) {
        return types.size() == 1 && types.contains(type);
    }

    public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
            (1 << STREAM_MUSIC) |
            (1 << STREAM_RING) |
+32 −18
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * Class to manage the inventory of all connected devices.
@@ -372,9 +374,14 @@ public class AudioDeviceInventory {
        mDeviceBroker.postObserveDevicesForAllStreams();
    }

    private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
                    | AudioSystem.DEVICE_OUT_LINE | AudioSystem.DEVICE_OUT_ALL_USB;
    private static final Set<Integer> DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET;
    static {
        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET = new HashSet<>();
        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
    }

    /*package*/ void onSetWiredDeviceConnectionState(
                            AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
@@ -382,7 +389,7 @@ public class AudioDeviceInventory {

        synchronized (mConnectedDevices) {
            if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
                    && ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
                mDeviceBroker.setBluetoothA2dpOnInt(true,
                        "onSetWiredDeviceConnectionState state DISCONNECTED");
            }
@@ -393,7 +400,7 @@ public class AudioDeviceInventory {
                return;
            }
            if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
                if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
                    mDeviceBroker.setBluetoothA2dpOnInt(false,
                            "onSetWiredDeviceConnectionState state not DISCONNECTED");
                }
@@ -764,13 +771,19 @@ public class AudioDeviceInventory {
    // - none of these devices are connected anymore after one is disconnected AND
    // - the device being disconnected is actually used for music.
    // Access synchronized on mConnectedDevices
    private int mBecomingNoisyIntentDevices =
            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
                    | AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI
                    | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET
                    | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
                    | AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE
                    | AudioSystem.DEVICE_OUT_HEARING_AID;
    private static final Set<Integer> BECOMING_NOISY_INTENT_DEVICES_SET;
    static {
        BECOMING_NOISY_INTENT_DEVICES_SET = new HashSet<>();
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
        BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
        BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
    }

    // must be called before removing the device from mConnectedDevices
    // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
@@ -781,16 +794,16 @@ public class AudioDeviceInventory {
        if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
            return 0;
        }
        if ((device & mBecomingNoisyIntentDevices) == 0) {
        if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) {
            return 0;
        }
        int delay = 0;
        int devices = 0;
        Set<Integer> devices = new HashSet<>();
        for (int i = 0; i < mConnectedDevices.size(); i++) {
            int dev = mConnectedDevices.valueAt(i).mDeviceType;
            if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
                    && ((dev & mBecomingNoisyIntentDevices) != 0)) {
                devices |= dev;
                    && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) {
                devices.add(dev);
            }
        }
        if (musicDevice == AudioSystem.DEVICE_NONE) {
@@ -801,8 +814,9 @@ public class AudioDeviceInventory {
        // because music routing is altered in this case.
        // also checks whether media routing if affected by a dynamic policy or mirroring
        if (((device == musicDevice) || mDeviceBroker.isInCommunication())
                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()
                        && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) {
                && AudioSystem.isSingleAudioDeviceType(devices, device)
                && !mDeviceBroker.hasMediaDynamicPolicy()
                && (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) {
            if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)
                    && !mDeviceBroker.hasAudioFocusUsers()) {
                // no media playback, not a "becoming noisy" situation, otherwise it could cause
+105 −86

File changed.

Preview size limit exceeded, changes collapsed.