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

Commit f447cbbc authored by Jason Chiu's avatar Jason Chiu
Browse files

Fix the ANR in panel when changing volume continuously

When users open volume panel and keep on changing the volume slider for
a while, the panel starts to defer the slider updating, and finally gets
stuck and causes an ANR.

Root cause:
Volume panel has four volume adjusting slices. Each of them registers
a broadcast receiver to listen to the volume changed and muted events.
However, when the media volume changes, AudioManager will send four
broadcasts (music, assistant, accessibility, tts) to every receiver, and
each of them will reload slice four times. Thus, one media volume
changed event will lead to 16 (4*4) UI updates. Consequently, keeping on
sliding the volume bar will trigger hundreds of broadcasts and UI
updates, which makes the system busy and getting stuck.

Solution:
Introduce a VolumeSliceHelper to integrate the broadcasts of the volume
slices specifically.
1. Only register one broadcast receiver to reduce the broadcast loading
   since the four slices are listening to the same signal.
2. Filter the only one eligible broadcast among the multiple concurrent
   ones, and then relay it to the registered slice.
3. Listen to one more action STREAM_DEVICES_CHANGED_ACTION to update the
   volume panel when audio output device changes.

Test: robotest, visual
Fixes: 144134209
Fixes: 160489394
Change-Id: I780b9eee35802b19a5f0ab0a7d07bd3e081f5556
Merged-In: I780b9eee35802b19a5f0ab0a7d07bd3e081f5556
(cherry picked from commit 2c7b77da)
parent ca04ccd9
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -3258,6 +3258,11 @@
            android:permission="android.permission.MANAGE_SLICE_PERMISSIONS"
            android:exported="true" />

        <receiver
            android:name=".slices.VolumeSliceRelayReceiver"
            android:permission="android.permission.MANAGE_SLICE_PERMISSIONS"
            android:exported="true" />

        <!-- Couldn't be triggered from outside of settings. Statsd can trigger it because we send
             PendingIntent to it-->
        <receiver android:name=".fuelgauge.batterytip.AnomalyDetectionReceiver"
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ public abstract class AdjustVolumeRestrictedPreferenceController extends
        filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
        filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
        filter.addAction(AudioManager.MASTER_MUTE_CHANGED_ACTION);
        filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
        return filter;
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -107,7 +107,10 @@ public abstract class VolumeSeekBarPreferenceController extends
        return mHelper.getMinVolume(getAudioStream());
    }

    protected abstract int getAudioStream();
    /**
     * @return the audio stream type
     */
    public abstract int getAudioStream();

    protected abstract int getMuteIcon();

+10 −0
Original line number Diff line number Diff line
@@ -216,6 +216,16 @@ public class CustomSliceRegistry {
            .appendPath("ring_volume")
            .build();

    /**
     * Full {@link Uri} for the all volume Slices.
     */
    public static final Uri VOLUME_SLICES_URI = new Uri.Builder()
            .scheme(ContentResolver.SCHEME_CONTENT)
            .authority(SettingsSliceProvider.SLICE_AUTHORITY)
            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
            .appendPath("volume_slices")
            .build();

    /**
     * Full {@link Uri} for the Wifi Calling Slice.
     */
+12 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.notification.VolumeSeekBarPreferenceController;
import com.android.settings.notification.zen.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.SliceBroadcastRelay;
@@ -184,7 +185,10 @@ public class SettingsSliceProvider extends SliceProvider {

    @Override
    public void onSliceUnpinned(Uri sliceUri) {
        SliceBroadcastRelay.unregisterReceivers(getContext(), sliceUri);
        final Context context = getContext();
        if (!VolumeSliceHelper.unregisterUri(context, sliceUri)) {
            SliceBroadcastRelay.unregisterReceivers(context, sliceUri);
        }
        ThreadUtils.postOnMainThread(() -> stopBackgroundWorker(sliceUri));
    }

@@ -390,8 +394,14 @@ public class SettingsSliceProvider extends SliceProvider {

        final IntentFilter filter = controller.getIntentFilter();
        if (filter != null) {
            if (controller instanceof VolumeSeekBarPreferenceController) {
                // Register volume slices to a broadcast relay to reduce unnecessary UI updates
                VolumeSliceHelper.registerIntentToUri(getContext(), filter, uri,
                        ((VolumeSeekBarPreferenceController) controller).getAudioStream());
            } else {
                registerIntentToUri(filter, uri);
            }
        }

        ThreadUtils.postOnMainThread(() -> startBackgroundWorker(controller, uri));

Loading