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

Commit 2642eed1 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Resize dialogs when the configuration changes

Before this CL, system dialogs would not react to configuration changes,
which would cause weird UI issues when folding into a smaller screen.

This CL makes all SystemUIDialog's listen for configuration changes, and
resize their window accordingly.

Bug: 204042506
Test: Manual
Change-Id: I4cf1dbfff2a95c83ed3e240d165eae60660c429b
parent 2d5edc33
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -879,6 +879,13 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    /** Remove a static config callback. */
    public static void removeConfigCallback(ConfigChangedCallback callback) {
        synchronized (sConfigCallbacks) {
            sConfigCallbacks.remove(callback);
        }
    }

    /** Add activity config callback to be notified about override config changes. */
    public void setActivityConfigCallback(ActivityConfigCallback callback) {
        mActivityConfigCallback = callback;
+21 −4
Original line number Diff line number Diff line
@@ -116,6 +116,10 @@ class DialogLaunchAnimator(
                    launchAnimation.ignoreNextCallToHide = true
                    dialog.hide()
                }

                override fun onSizeChanged() {
                    launchAnimation.onOriginalDialogSizeChanged()
                }
            })
        }

@@ -146,6 +150,7 @@ interface HostDialogProvider {
     *   2. call [dismissOverride] instead of doing any dismissing logic. The actual dismissing
     *      logic should instead be done inside the lambda passed to [dismissOverride], which will
     *      be called after the exit animation.
     *   3. Be full screen, i.e. have a window matching its parent size.
     *
     * See SystemUIHostDialogProvider for an example of implementation.
     */
@@ -183,6 +188,9 @@ interface DialogListener {

    /** Called when this dialog show() is called. */
    fun onShow()

    /** Called when this dialog size might have changed, e.g. because of configuration changes. */
    fun onSizeChanged()
}

private class DialogLaunchAnimation(
@@ -261,10 +269,6 @@ private class DialogLaunchAnimation(
        val window = hostDialog.window
            ?: throw IllegalStateException("There is no window associated to the host dialog")
        window.setBackgroundDrawableResource(android.R.color.transparent)
        window.setLayout(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT
        )

        // If we are using gesture navigation, then we can overlay the navigation/task bars with
        // the host dialog.
@@ -432,6 +436,19 @@ private class DialogLaunchAnimation(
        })
    }

    fun onOriginalDialogSizeChanged() {
        // The dialog is the single child of the root.
        if (hostDialogRoot.childCount != 1) {
            return
        }

        val dialogView = hostDialogRoot.getChildAt(0)
        val layoutParams = dialogView.layoutParams as? FrameLayout.LayoutParams ?: return
        layoutParams.width = originalDialog.window.attributes.width
        layoutParams.height = originalDialog.window.attributes.height
        dialogView.layoutParams = layoutParams
    }

    private fun maybeStartLaunchAnimation() {
        if (!isTouchSurfaceGhostDrawn || !isOriginalDialogViewLaidOut) {
            return
+68 −4
Original line number Diff line number Diff line
@@ -22,11 +22,15 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
@@ -49,7 +53,8 @@ import java.util.Set;
 * 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 implements ListenableDialog {
public class SystemUIDialog extends AlertDialog implements ListenableDialog,
        ViewRootImpl.ConfigChangedCallback {
    // TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
    private static final String FLAG_TABLET_DIALOG_WIDTH =
            "persist.systemui.flag_tablet_dialog_width";
@@ -57,6 +62,12 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
    private final Context mContext;
    private final DismissReceiver mDismissReceiver;
    private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>();
    private final Handler mHandler = new Handler();

    private int mLastWidth = Integer.MIN_VALUE;
    private int mLastHeight = Integer.MIN_VALUE;
    private int mLastConfigurationWidthDp = -1;
    private int mLastConfigurationHeightDp = -1;

    public SystemUIDialog(Context context) {
        this(context, R.style.Theme_SystemUI_Dialog);
@@ -82,11 +93,50 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set the dialog window size.
        getWindow().setLayout(getDialogWidth(), ViewGroup.LayoutParams.WRAP_CONTENT);
        Configuration config = getContext().getResources().getConfiguration();
        mLastConfigurationWidthDp = config.screenWidthDp;
        mLastConfigurationHeightDp = config.screenHeightDp;
        updateWindowSize();
    }

    private void updateWindowSize() {
        // Only the thread that created this dialog can update its window size.
        if (Looper.myLooper() != mHandler.getLooper()) {
            mHandler.post(this::updateWindowSize);
            return;
        }

        int width = getWidth();
        int height = getHeight();
        if (width == mLastWidth && height == mLastHeight) {
            return;
        }

        mLastWidth = width;
        mLastHeight = height;
        getWindow().setLayout(width, height);

        for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
            listener.onSizeChanged();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
        if (mLastConfigurationWidthDp != configuration.screenWidthDp
                || mLastConfigurationHeightDp != configuration.screenHeightDp) {
            mLastConfigurationWidthDp = configuration.screenWidthDp;
            mLastConfigurationHeightDp = configuration.compatScreenWidthDp;

    private int getDialogWidth() {
            updateWindowSize();
        }
    }

    /**
     * Return this dialog width. This method will be invoked when this dialog is created and when
     * the device configuration changes, and the result will be used to resize this dialog window.
     */
    protected int getWidth() {
        boolean isOnTablet =
                mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
        if (!isOnTablet) {
@@ -113,6 +163,14 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
        }
    }

    /**
     * Return this dialog height. This method will be invoked when this dialog is created and when
     * the device configuration changes, and the result will be used to resize this dialog window.
     */
    protected int getHeight() {
        return ViewGroup.LayoutParams.WRAP_CONTENT;
    }

    @Override
    protected void onStart() {
        super.onStart();
@@ -120,6 +178,10 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
        if (mDismissReceiver != null) {
            mDismissReceiver.register();
        }

        // Listen for configuration changes to resize this dialog window. This is mostly necessary
        // for foldables that often go from large <=> small screen when folding/unfolding.
        ViewRootImpl.addConfigCallback(this);
    }

    @Override
@@ -129,6 +191,8 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
        if (mDismissReceiver != null) {
            mDismissReceiver.unregister();
        }

        ViewRootImpl.removeConfigCallback(this);
    }

    @Override
+9 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package com.android.systemui.statusbar.phone
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup
import com.android.systemui.animation.HostDialogProvider

/** An implementation of [HostDialogProvider] to be used when animating SysUI dialogs. */
@@ -38,5 +39,13 @@ class SystemUIHostDialogProvider : HostDialogProvider {
                super.dismiss()
            }
        }

        override fun getWidth(): Int {
            return ViewGroup.LayoutParams.MATCH_PARENT
        }

        override fun getHeight(): Int {
            return ViewGroup.LayoutParams.MATCH_PARENT
        }
    }
}
 No newline at end of file