diff options
4 files changed, 105 insertions, 8 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4c0c82fe5c2e..74ecf282750c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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; diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index 53f29b6f963a..865f96be1775 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 189abe2d55d0..cf4aaba107cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -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(); + } } - private int getDialogWidth() { + @Override + public void onConfigurationChanged(Configuration configuration) { + if (mLastConfigurationWidthDp != configuration.screenWidthDp + || mLastConfigurationHeightDp != configuration.screenHeightDp) { + mLastConfigurationWidthDp = configuration.screenWidthDp; + mLastConfigurationHeightDp = configuration.compatScreenWidthDp; + + 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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt index 7b65bccfa0e8..4f18f8c597b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt @@ -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 |