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

Commit 3756b091 authored by Satoshi Sanno's avatar Satoshi Sanno Committed by Amin Shaikh
Browse files

Unregister BroadcastReceiver of SystemUIDialog when it is dismissed

Symptom:
The number of registered BroadcastReceiver increases each time
SystemUIDialog is shown.
This is a leak of BroadcastReceiver.

Root cause:
SystemUIDialog#registerDismissListener(Dialog dialog) registers
a BroadcastReceiver.
But it never unregisters the BroadcastReceiver.
It had been unregistered when the dialog was dismissed previously.
But the unregistration process seems to have been erased by mistake
at refactoring.

Solution:
The unregistration process is added to registerDismissListener() again.
It sets the dialog's OnDismissListener to unregister the
BroadcastReceiver when the dialog is dismissed.

And, SystemUIDialog unregisters the BroadcastReceiver without using
registerDismissListener() to make its setOnDismissListener() available
to clients.

Bug: 134916873
Test: atest packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
Change-Id: Ic41ac46997362ce585819e660c398b47e6685eaf
parent fcd34bb8
Loading
Loading
Loading
Loading
+35 −11
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
@@ -34,10 +33,13 @@ import com.android.systemui.statusbar.policy.KeyguardMonitor;

/**
 * Base class for dialogs that should appear over panels and keyguard.
 * The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
 * and dismisses itself when it receives the broadcast.
 */
public class SystemUIDialog extends AlertDialog {

    private final Context mContext;
    private final DismissReceiver mDismissReceiver;

    public SystemUIDialog(Context context) {
        this(context, R.style.Theme_SystemUI_Dialog);
@@ -52,7 +54,19 @@ public class SystemUIDialog extends AlertDialog {
        attrs.setTitle(getClass().getSimpleName());
        getWindow().setAttributes(attrs);

        registerDismissListener(this);
        mDismissReceiver = new DismissReceiver(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mDismissReceiver.register();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mDismissReceiver.unregister();
    }

    public void setShowForAllUsers(boolean show) {
@@ -100,12 +114,22 @@ public class SystemUIDialog extends AlertDialog {
        return dialog;
    }

    /**
     * Registers a listener that dismisses the given dialog when it receives
     * the screen off / close system dialogs broadcast.
     * <p>
     * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
     * calling this because it causes a leak of BroadcastReceiver.
     *
     * @param dialog The dialog to be associated with the listener.
     */
    public static void registerDismissListener(Dialog dialog) {
        DismissReceiver dismissReceiver = new DismissReceiver(dialog);
        dialog.setOnDismissListener(d -> dismissReceiver.unregister());
        dismissReceiver.register();
    }

    private static class DismissReceiver extends BroadcastReceiver implements OnDismissListener {
    private static class DismissReceiver extends BroadcastReceiver {
        private static final IntentFilter INTENT_FILTER = new IntentFilter();
        static {
            INTENT_FILTER.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -125,16 +149,16 @@ public class SystemUIDialog extends AlertDialog {
            mRegistered = true;
        }

        void unregister() {
            if (mRegistered) {
                mDialog.getContext().unregisterReceiver(this);
                mRegistered = false;
            }
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            mDialog.dismiss();
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            if (mRegistered) {
                mDialog.getContext().unregisterReceiver(this);
                mRegistered = false;
    }
}
    }}
+9 −2
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@ package com.android.systemui.statusbar.phone;
import static junit.framework.Assert.assertTrue;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -52,13 +54,18 @@ public class SystemUIDialogTest extends SysuiTestCase {

    @Test
    public void testRegisterReceiver() {
        final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        final ArgumentCaptor<IntentFilter> intentFilterCaptor =
                ArgumentCaptor.forClass(IntentFilter.class);

        verify(mContextSpy).registerReceiverAsUser(any(), any(),
        mDialog.show();
        verify(mContextSpy).registerReceiverAsUser(broadcastReceiverCaptor.capture(), any(),
                intentFilterCaptor.capture(), any(), any());

        assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
    }

        mDialog.dismiss();
        verify(mContextSpy).unregisterReceiver(eq(broadcastReceiverCaptor.getValue()));
    }
}