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

Commit 94204aa4 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge changes from topic "dialog-aod" into sc-v2-dev

* changes:
  Resize dialogs when the configuration changes
  Disable dialog exit animation when locking (1/2)
parents c5a94538 2642eed1
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;
+40 −26
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@ private const val TAG = "DialogLaunchAnimator"
/**
 * A class that allows dialogs to be started in a seamless way from a view that is transforming
 * nicely into the starting dialog.
 *
 * Important: Don't forget to call [DialogLaunchAnimator.onDozeAmountChanged] when the doze amount
 * changes to gracefully handle dialogs fading out when the device is dozing.
 */
class DialogLaunchAnimator(
    private val context: Context,
@@ -89,8 +86,17 @@ class DialogLaunchAnimator(
        // host dialog.
        if (dialog is ListenableDialog) {
            dialog.addListener(object : DialogListener {
                override fun onDismiss() {
                override fun onDismiss(reason: DialogListener.DismissReason) {
                    dialog.removeListener(this)

                    // We disable the exit animation if we are dismissing the dialog because the
                    // device is being locked, otherwise the animation looks bad if AOD is enabled.
                    // If AOD is disabled the screen will directly becomes black and we won't see
                    // the animation anyways.
                    if (reason == DialogListener.DismissReason.DEVICE_LOCKED) {
                        launchAnimation.exitAnimationDisabled = true
                    }

                    hostDialog.dismiss()
                }

@@ -110,6 +116,10 @@ class DialogLaunchAnimator(
                    launchAnimation.ignoreNextCallToHide = true
                    dialog.hide()
                }

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

@@ -117,13 +127,6 @@ class DialogLaunchAnimator(
        return hostDialog
    }

    /** Notify the current doze amount, to ensure that dialogs fade out when dozing. */
    // TODO(b/193634619): Replace this by some mandatory constructor parameter to make sure that we
    // don't forget to call this when the doze amount changes.
    fun onDozeAmountChanged(amount: Float) {
        currentAnimations.forEach { it.onDozeAmountChanged(amount) }
    }

    /**
     * Ensure that all dialogs currently shown won't animate into their touch surface when
     * dismissed.
@@ -147,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.
     */
@@ -168,14 +172,25 @@ interface ListenableDialog {
}

interface DialogListener {
    /** The reason why a dialog was dismissed. */
    enum class DismissReason {
        UNKNOWN,

        /** The device was locked, which dismissed this dialog. */
        DEVICE_LOCKED,
    }

    /** Called when this dialog dismiss() is called. */
    fun onDismiss()
    fun onDismiss(reason: DismissReason)

    /** Called when this dialog hide() is called. */
    fun onHide()

    /** 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(
@@ -254,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.
@@ -425,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
@@ -638,14 +662,4 @@ private class DialogLaunchAnimation(

        return (touchSurface.parent as? View)?.isShown ?: true
    }

    internal fun onDozeAmountChanged(amount: Float) {
        val alpha = Interpolators.ALPHA_OUT.getInterpolation(1 - amount)
        val decorView = this.hostDialog.window?.decorView ?: return
        if (decorView.hasOverlappingRendering() && alpha > 0.0f &&
            alpha < 1.0f && decorView.layerType != View.LAYER_TYPE_HARDWARE) {
            decorView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
        }
        decorView.alpha = alpha
    }
}
+1 −7
Original line number Diff line number Diff line
@@ -136,7 +136,6 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.biometrics.AuthRippleController;
@@ -680,7 +679,6 @@ public class StatusBar extends SystemUI implements

    private HeadsUpAppearanceController mHeadsUpAppearanceController;
    private final ActivityLaunchAnimator mActivityLaunchAnimator;
    private final DialogLaunchAnimator mDialogLaunchAnimator;
    private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
    protected StatusBarNotificationPresenter mPresenter;
    private NotificationActivityStarter mNotificationActivityStarter;
@@ -806,8 +804,7 @@ public class StatusBar extends SystemUI implements
            Optional<StartingSurface> startingSurfaceOptional,
            TunerService tunerService,
            DumpManager dumpManager,
            ActivityLaunchAnimator activityLaunchAnimator,
            DialogLaunchAnimator dialogLaunchAnimator) {
            ActivityLaunchAnimator activityLaunchAnimator) {
        super(context);
        mNotificationsController = notificationsController;
        mLightBarController = lightBarController;
@@ -919,7 +916,6 @@ public class StatusBar extends SystemUI implements

        mActivityIntentHelper = new ActivityIntentHelper(mContext);
        mActivityLaunchAnimator = activityLaunchAnimator;
        mDialogLaunchAnimator = dialogLaunchAnimator;

        // The status bar background may need updating when the ongoing call status changes.
        mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode());
@@ -4480,8 +4476,6 @@ public class StatusBar extends SystemUI implements
                            && !mBiometricUnlockController.isWakeAndUnlock()) {
                        mLightRevealScrim.setRevealAmount(1f - linear);
                    }

                    mDialogLaunchAnimator.onDozeAmountChanged(linear);
                }

                @Override
+92 −9
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;
@@ -35,6 +39,7 @@ import android.view.WindowManager.LayoutParams;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.DialogListener;
import com.android.systemui.animation.DialogListener.DismissReason;
import com.android.systemui.animation.ListenableDialog;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -48,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";
@@ -56,12 +62,22 @@ 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);
    }

    public SystemUIDialog(Context context, int theme) {
        this(context, theme, true /* dismissOnDeviceLock */);
    }

    public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
        super(context, theme);
        mContext = context;

@@ -70,18 +86,57 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
        attrs.setTitle(getClass().getSimpleName());
        getWindow().setAttributes(attrs);

        mDismissReceiver = new DismissReceiver(this);
        mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
    }

    @Override
    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;

            updateWindowSize();
        }
    }

    private int getDialogWidth() {
    /**
     * 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) {
@@ -108,18 +163,38 @@ 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();

        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
    protected void onStop() {
        super.onStop();

        if (mDismissReceiver != null) {
            mDismissReceiver.unregister();
        }

        ViewRootImpl.removeConfigCallback(this);
    }

    @Override
    public void addListener(DialogListener listener) {
        mDialogListeners.add(listener);
@@ -132,10 +207,14 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {

    @Override
    public void dismiss() {
        dismiss(DismissReason.UNKNOWN);
    }

    private void dismiss(DismissReason reason) {
        super.dismiss();

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

@@ -251,7 +330,11 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (mDialog instanceof SystemUIDialog) {
                ((SystemUIDialog) mDialog).dismiss(DismissReason.DEVICE_LOCKED);
            } else {
                mDialog.dismiss();
            }
        }
    }
}
+16 −1
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. */
@@ -16,12 +17,18 @@ class SystemUIHostDialogProvider : HostDialogProvider {
        return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride)
    }

    /**
     * This host dialog is a SystemUIDialog so that it's displayed above all SystemUI windows. Note
     * that it is not automatically dismissed when the device is locked, but only when the hosted
     * (original) dialog is dismissed. That way, the behavior of the dialog (dismissed when locking
     * or not) is consistent with when the dialog is shown with or without the dialog animator.
     */
    private class SystemUIHostDialog(
        context: Context,
        theme: Int,
        private val onCreateCallback: () -> Unit,
        private val dismissOverride: (() -> Unit) -> Unit
    ) : SystemUIDialog(context, theme) {
    ) : SystemUIDialog(context, theme, false /* dismissOnDeviceLock */) {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            onCreateCallback()
@@ -32,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
Loading