diff options
| author | 2021-10-29 09:28:24 +0000 | |
|---|---|---|
| committer | 2021-10-29 09:28:24 +0000 | |
| commit | a5088b1302b879b871565ba07aa0953774e13f29 (patch) | |
| tree | 9b2b47bc76508a050844d3fc181d074722cd7276 | |
| parent | 6c20a8f525dcd90e5b85380747aed3ebd0ec1971 (diff) | |
| parent | 4de63945eab26b78591e776acec98d7f0dca52c2 (diff) | |
Merge changes from topic "dialog-width" into sc-v2-dev
* changes:
Make all SystemUIDialog's the same configurable width (1/2)
Synchronize dialog launch animations
Animate the internet dialog launch.
19 files changed, 306 insertions, 149 deletions
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 c2b36089d0a7..669a054eaa2a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -21,11 +21,16 @@ import android.content.Context import android.graphics.Color import android.os.Looper import android.util.Log +import android.view.GhostView import android.view.Gravity import android.view.View import android.view.ViewGroup -import android.view.ViewTreeObserver +import android.view.ViewTreeObserver.OnPreDrawListener +import android.view.WindowInsets import android.view.WindowManager +import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR +import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN +import android.view.WindowManagerPolicyConstants import android.widget.FrameLayout private const val TAG = "DialogLaunchAnimator" @@ -221,10 +226,12 @@ private class DialogLaunchAnimation( private var isDismissing = false private var dismissRequested = false - private var drawHostDialog = false var ignoreNextCallToHide = false var exitAnimationDisabled = false + private var isTouchSurfaceGhostDrawn = false + private var isOriginalDialogViewLaidOut = false + fun start() { // Show the host (fullscreen) dialog, to which we will add the stolen dialog view. hostDialog.show() @@ -252,19 +259,76 @@ private class DialogLaunchAnimation( WindowManager.LayoutParams.MATCH_PARENT ) - // Prevent the host dialog from drawing until the animation starts. - hostDialogRoot.viewTreeObserver.addOnPreDrawListener( - object : ViewTreeObserver.OnPreDrawListener { - override fun onPreDraw(): Boolean { - if (drawHostDialog) { - hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this) - return true - } + // If we are using gesture navigation, then we can overlay the navigation/task bars with + // the host dialog. + val navigationMode = context.resources.getInteger( + com.android.internal.R.integer.config_navBarInteractionMode) + if (navigationMode == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL) { + window.attributes.fitInsetsTypes = window.attributes.fitInsetsTypes and + WindowInsets.Type.navigationBars().inv() + window.addFlags(FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_INSET_DECOR) + window.setDecorFitsSystemWindows(false) + } - return false - } + // Disable the dim. We will enable it once we start the animation. + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + + // Add a temporary touch surface ghost as soon as the window is ready to draw. This + // temporary ghost will be drawn together with the touch surface, but in the host dialog + // window. Once it is drawn, we will make the touch surface invisible, and then start the + // animation. We do all this synchronization to avoid flicker that would occur if we made + // the touch surface invisible too early (before its ghost is drawn), leading to one or more + // frames with a hole instead of the touch surface (or its ghost). + hostDialogRoot.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener { + override fun onPreDraw(): Boolean { + hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this) + addTemporaryTouchSurfaceGhost() + return true } - ) + }) + hostDialogRoot.invalidate() + } + + private fun addTemporaryTouchSurfaceGhost() { + // Create a ghost of the touch surface (which will make the touch surface invisible) and add + // it to the host dialog. We will wait for this ghost to be drawn before starting the + // animation. + val ghost = GhostView.addGhost(touchSurface, hostDialogRoot) + + // The ghost of the touch surface was just created, so the touch surface was made invisible. + // We make it visible again until the ghost is actually drawn. + touchSurface.visibility = View.VISIBLE + + // Wait for the ghost to be drawn before continuing. + ghost.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener { + override fun onPreDraw(): Boolean { + ghost.viewTreeObserver.removeOnPreDrawListener(this) + onTouchSurfaceGhostDrawn() + return true + } + }) + ghost.invalidate() + } + + private fun onTouchSurfaceGhostDrawn() { + // Make the touch surface invisible and make sure that it stays invisible as long as the + // dialog is shown or animating. + touchSurface.visibility = View.INVISIBLE + if (touchSurface is LaunchableView) { + touchSurface.setShouldBlockVisibilityChanges(true) + } + + // Add a pre draw listener to (maybe) start the animation once the touch surface is + // actually invisible. + touchSurface.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener { + override fun onPreDraw(): Boolean { + touchSurface.viewTreeObserver.removeOnPreDrawListener(this) + isTouchSurfaceGhostDrawn = true + maybeStartLaunchAnimation() + return true + } + }) + touchSurface.invalidate() } /** Get the content view of [originalDialog] and pass it to [then]. */ @@ -276,7 +340,7 @@ private class DialogLaunchAnimation( ?: throw IllegalStateException("Dialog does not have any android.R.id.content view") androidContent.viewTreeObserver.addOnPreDrawListener( - object : ViewTreeObserver.OnPreDrawListener { + object : OnPreDrawListener { override fun onPreDraw(): Boolean { if (androidContent.childCount == 1) { androidContent.viewTreeObserver.removeOnPreDrawListener(this) @@ -354,32 +418,47 @@ private class DialogLaunchAnimation( oldBottom: Int ) { dialogView.removeOnLayoutChangeListener(this) - startAnimation( - isLaunching = true, - onLaunchAnimationStart = { drawHostDialog = true }, - onLaunchAnimationEnd = { - touchSurface.setTag(R.id.launch_animation_running, null) - - // We hide the touch surface when the dialog is showing. We will make this - // view visible again when dismissing the dialog. - // TODO(b/193634619): Provide an easy way for views to check if they should - // be hidden because of a dialog launch so that they don't override this - // visibility when updating/refreshing itself. - touchSurface.visibility = View.INVISIBLE - - isLaunching = false - - // dismiss was called during the animation, dismiss again now to actually - // dismiss. - if (dismissRequested) { - hostDialog.dismiss() - } - } - ) + + isOriginalDialogViewLaidOut = true + maybeStartLaunchAnimation() } }) } + private fun maybeStartLaunchAnimation() { + if (!isTouchSurfaceGhostDrawn || !isOriginalDialogViewLaidOut) { + return + } + + // Show the background dim. + hostDialog.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + + startAnimation( + isLaunching = true, + onLaunchAnimationStart = { + // Remove the temporary ghost. Another ghost (that ghosts only the touch surface + // content, and not its background) will be added right after this and will be + // animated. + GhostView.removeGhost(touchSurface) + }, + onLaunchAnimationEnd = { + touchSurface.setTag(R.id.launch_animation_running, null) + + // We hide the touch surface when the dialog is showing. We will make this + // view visible again when dismissing the dialog. + touchSurface.visibility = View.INVISIBLE + + isLaunching = false + + // dismiss was called during the animation, dismiss again now to actually + // dismiss. + if (dismissRequested) { + hostDialog.dismiss() + } + } + ) + } + private fun onHostDialogDismissed(actualDismiss: () -> Unit) { if (Looper.myLooper() != Looper.getMainLooper()) { context.mainExecutor.execute { onHostDialogDismissed(actualDismiss) } @@ -417,6 +496,11 @@ private class DialogLaunchAnimation( if (!shouldAnimateDialogIntoView()) { Log.i(TAG, "Skipping animation of dialog into the touch surface") + // Make sure we allow the touch surface to change its visibility again. + if (touchSurface is LaunchableView) { + touchSurface.setShouldBlockVisibilityChanges(false) + } + // If the view is invisible it's probably because of us, so we make it visible again. if (touchSurface.visibility == View.INVISIBLE) { touchSurface.visibility = View.VISIBLE @@ -434,10 +518,33 @@ private class DialogLaunchAnimation( hostDialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) }, onLaunchAnimationEnd = { + // Make sure we allow the touch surface to change its visibility again. + if (touchSurface is LaunchableView) { + touchSurface.setShouldBlockVisibilityChanges(false) + } + touchSurface.visibility = View.VISIBLE originalDialogView!!.visibility = View.INVISIBLE - dismissDialogs(true /* instantDismiss */) - onDialogDismissed(this@DialogLaunchAnimation) + + // The animated ghost was just removed. We create a temporary ghost that will be + // removed only once we draw the touch surface, to avoid flickering that would + // happen when removing the ghost too early (before the touch surface is drawn). + GhostView.addGhost(touchSurface, hostDialogRoot) + + touchSurface.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener { + override fun onPreDraw(): Boolean { + touchSurface.viewTreeObserver.removeOnPreDrawListener(this) + + // Now that the touch surface was drawn, we can remove the temporary ghost + // and instantly dismiss the dialog. + GhostView.removeGhost(touchSurface) + dismissDialogs(true /* instantDismiss */) + onDialogDismissed(this@DialogLaunchAnimation) + + return true + } + }) + touchSurface.invalidate() } ) } @@ -472,10 +579,13 @@ private class DialogLaunchAnimation( } override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { + // During launch, onLaunchAnimationStart will be used to remove the temporary touch + // surface ghost so it is important to call this before calling + // onLaunchAnimationStart on the controller (which will create its own ghost). + onLaunchAnimationStart() + startViewController.onLaunchAnimationStart(isExpandingFullyAbove) endViewController.onLaunchAnimationStart(isExpandingFullyAbove) - - onLaunchAnimationStart() } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt new file mode 100644 index 000000000000..80a3eb839940 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.animation + +/** A view that can expand/launch into an app or a dialog. */ +interface LaunchableView { + /** + * Set whether this view should block/prevent all visibility changes. This ensures that this + * view remains invisible during the launch animation given that it is ghosted and already drawn + * somewhere else. + * + * Note that when this is set to true, both the [normal][android.view.View.setVisibility] and + * [transition][android.view.View.setTransitionVisibility] visibility changes must be blocked. + */ + fun setShouldBlockVisibilityChanges(block: Boolean) +}
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml deleted file mode 100644 index 3ceb0f6ac06a..000000000000 --- a/packages/SystemUI/res/drawable/internet_dialog_background.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<inset xmlns:android="http://schemas.android.com/apk/res/android"> - <shape android:shape="rectangle"> - <corners android:radius="8dp" /> - <solid android:color="?android:attr/colorBackground" /> - </shape> -</inset> diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml deleted file mode 100644 index 14672ef3dcfe..000000000000 --- a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2021 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<inset xmlns:android="http://schemas.android.com/apk/res/android"> - <shape android:shape="rectangle"> - <corners - android:topLeftRadius="@dimen/internet_dialog_corner_radius" - android:topRightRadius="@dimen/internet_dialog_corner_radius" - android:bottomLeftRadius="@dimen/internet_dialog_corner_radius" - android:bottomRightRadius="@dimen/internet_dialog_corner_radius"/> - <solid android:color="?android:attr/colorBackground" /> - </shape> -</inset> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 79ac737ba304..f4faa62430db 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -20,8 +20,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/internet_connectivity_dialog" android:layout_width="@dimen/large_dialog_width" - android:layout_height="@dimen/internet_dialog_list_max_height" - android:background="@drawable/internet_dialog_rounded_top_corner_background" + android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 85f8f0957a08..4e578615f30f 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -105,5 +105,5 @@ <dimen name="qs_detail_margin_top">0dp</dimen> <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) --> - <dimen name="large_dialog_width">624dp</dimen> + <dimen name="large_dialog_width">504dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7293f3148ae4..db6985d2b61f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1602,7 +1602,6 @@ <!-- Internet panel related dimensions --> <dimen name="internet_dialog_list_margin">12dp</dimen> - <dimen name="internet_dialog_list_max_height">662dp</dimen> <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) --> <dimen name="large_dialog_width">@dimen/match_parent</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index ff299eae8cf2..9bdd572a8eba 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -956,10 +956,6 @@ <item name="android:textColor">?android:attr/textColorPrimary</item> </style> - <style name="Theme.SystemUI.Dialog.Internet"> - <item name="android:windowBackground">@drawable/internet_dialog_background</item> - </style> - <style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault"> <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index 6895ef10fd07..26ce645eefc5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -104,8 +104,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements lp.setFitInsetsIgnoringVisibility(true); window.setAttributes(lp); window.setContentView(mDialogView); - window.setLayout(mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width), - ViewGroup.LayoutParams.WRAP_CONTENT); mHeaderTitle = mDialogView.requireViewById(R.id.header_title); mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt index 9e8f6b82c182..23482677038c 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt @@ -24,7 +24,6 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowInsets import android.widget.ImageView import android.widget.TextView @@ -65,7 +64,6 @@ class PrivacyDialog( window?.apply { attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars() attributes.receiveInsetsIgnoringZOrder = true - setLayout(context.resources.getDimensionPixelSize(R.dimen.qs_panel_width), WRAP_CONTENT) setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 36101c9e2587..69be33261995 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -42,6 +42,7 @@ import androidx.annotation.VisibleForTesting import com.android.settingslib.Utils import com.android.systemui.FontSizeUtils import com.android.systemui.R +import com.android.systemui.animation.LaunchableView import com.android.systemui.plugins.qs.QSIconView import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.qs.QSTile.BooleanState @@ -54,7 +55,7 @@ open class QSTileViewImpl @JvmOverloads constructor( context: Context, private val _icon: QSIconView, private val collapsed: Boolean = false -) : QSTileView(context), HeightOverrideable { +) : QSTileView(context), HeightOverrideable, LaunchableView { companion object { private const val INVALID = -1 @@ -130,6 +131,8 @@ open class QSTileViewImpl @JvmOverloads constructor( private var lastStateDescription: CharSequence? = null private var tileState = false private var lastState = INVALID + private var blockVisibilityChanges = false + private var lastVisibility = View.VISIBLE private val locInScreen = IntArray(2) @@ -319,6 +322,36 @@ open class QSTileViewImpl @JvmOverloads constructor( return sideView } + override fun setShouldBlockVisibilityChanges(block: Boolean) { + blockVisibilityChanges = block + + if (block) { + lastVisibility = visibility + } else { + visibility = lastVisibility + } + } + + override fun setVisibility(visibility: Int) { + if (blockVisibilityChanges) { + lastVisibility = visibility + return + } + + super.setVisibility(visibility) + } + + override fun setTransitionVisibility(visibility: Int) { + if (blockVisibilityChanges) { + // View.setTransitionVisibility just sets the visibility flag, so we don't have to save + // the transition visibility separately from the normal visibility. + lastVisibility = visibility + return + } + + super.setTransitionVisibility(visibility) + } + // Accessibility override fun onInitializeAccessibilityEvent(event: AccessibilityEvent) { @@ -484,7 +517,7 @@ open class QSTileViewImpl @JvmOverloads constructor( } private fun setColor(color: Int) { - colorBackgroundDrawable.setTint(color) + colorBackgroundDrawable.mutate().setTint(color) paintColor = color } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 98d0a72685ba..23b2a7642e36 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -124,7 +124,7 @@ public class InternetTile extends QSTileImpl<SignalState> { protected void handleClick(@Nullable View view) { mHandler.post(() -> mInternetDialogFactory.create(true, mAccessPointController.canConfigMobileData(), - mAccessPointController.canConfigWifi())); + mAccessPointController.canConfigWifi(), view)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 58e899285e3b..204dd46189d8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -15,14 +15,10 @@ */ package com.android.systemui.qs.tiles.dialog; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; - import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA; import android.app.AlertDialog; import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Network; import android.net.NetworkCapabilities; @@ -41,10 +37,7 @@ import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.Window; -import android.view.WindowInsets; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; @@ -130,7 +123,6 @@ public class InternetDialog extends SystemUIDialog implements private Switch mWiFiToggle; private FrameLayout mDoneLayout; private Drawable mBackgroundOn; - private int mListMaxHeight; private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private boolean mCanConfigMobileData; @@ -149,20 +141,11 @@ public class InternetDialog extends SystemUIDialog implements mInternetDialogSubTitle.setText(getSubtitleText()); }; - private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> { - // Set max height for list - if (mInternetDialogLayout.getHeight() > mListMaxHeight) { - ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams(); - params.height = mListMaxHeight; - mInternetDialogLayout.setLayoutParams(params); - } - }; - public InternetDialog(Context context, InternetDialogFactory internetDialogFactory, InternetDialogController internetDialogController, boolean canConfigMobileData, boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler, @Background Executor executor) { - super(context, R.style.Theme_SystemUI_Dialog_Internet); + super(context); if (DEBUG) { Log.d(TAG, "Init InternetDialog"); } @@ -184,8 +167,6 @@ public class InternetDialog extends SystemUIDialog implements return false; } }; - mListMaxHeight = context.getResources().getDimensionPixelSize( - R.dimen.internet_dialog_list_max_height); mUiEventLogger = uiEventLogger; mAdapter = new InternetAdapter(mInternetDialogController); if (!aboveStatusBar) { @@ -203,21 +184,9 @@ public class InternetDialog extends SystemUIDialog implements mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog, null); final Window window = getWindow(); - final WindowManager.LayoutParams layoutParams = window.getAttributes(); - layoutParams.gravity = Gravity.BOTTOM; - // Move down the dialog to overlay the navigation bar. - layoutParams.setFitInsetsTypes( - layoutParams.getFitInsetsTypes() & ~WindowInsets.Type.navigationBars()); - layoutParams.setFitInsetsSides(WindowInsets.Side.all()); - layoutParams.setFitInsetsIgnoringVisibility(true); - window.setAttributes(layoutParams); window.setContentView(mDialogView); - //Only fix the width for large screen or tablet. - window.setLayout(mContext.getResources().getDimensionPixelSize( - R.dimen.large_dialog_width), ViewGroup.LayoutParams.WRAP_CONTENT); + window.setWindowAnimations(R.style.Animation_InternetDialog); - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - window.addFlags(FLAG_LAYOUT_NO_LIMITS); mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog); mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title); @@ -244,8 +213,6 @@ public class InternetDialog extends SystemUIDialog implements mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle); mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle); mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on); - mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener( - mInternetListLayoutListener); mInternetDialogTitle.setText(getDialogTitleText()); mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index 40590a76536e..5673136e1828 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -71,6 +71,7 @@ import com.android.settingslib.mobile.TelephonyIcons; import com.android.settingslib.net.SignalStrengthUtil; import com.android.settingslib.wifi.WifiUtils; import com.android.systemui.R; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -152,6 +153,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private ToastFactory mToastFactory; private SignalDrawable mSignalDrawable; private LocationController mLocationController; + private DialogLaunchAnimator mDialogLaunchAnimator; @VisibleForTesting static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; @@ -202,7 +204,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, WindowManager windowManager, ToastFactory toastFactory, @Background Handler workerHandler, CarrierConfigTracker carrierConfigTracker, - LocationController locationController) { + LocationController locationController, + DialogLaunchAnimator dialogLaunchAnimator) { if (DEBUG) { Log.d(TAG, "Init InternetDialogController"); } @@ -231,6 +234,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mToastFactory = toastFactory; mSignalDrawable = new SignalDrawable(mContext); mLocationController = locationController; + mDialogLaunchAnimator = dialogLaunchAnimator; } void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { @@ -596,20 +600,32 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } void launchNetworkSetting() { + // Dismissing a dialog into its touch surface and starting an activity at the same time + // looks bad, so let's make sure the dialog just fades out quickly. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); mCallback.dismissDialog(); + mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0); } void launchWifiNetworkDetailsSetting(String key) { Intent intent = getWifiDetailsSettingsIntent(key); if (intent != null) { + // Dismissing a dialog into its touch surface and starting an activity at the same time + // looks bad, so let's make sure the dialog just fades out quickly. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); mCallback.dismissDialog(); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); } } void launchWifiScanningSetting() { + // Dismissing a dialog into its touch surface and starting an activity at the same time + // looks bad, so let's make sure the dialog just fades out quickly. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); mCallback.dismissDialog(); + final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt index ea5df17bca58..93828b3bcc99 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt @@ -18,9 +18,11 @@ package com.android.systemui.qs.tiles.dialog import android.content.Context import android.os.Handler import android.util.Log +import android.view.View import com.android.internal.logging.UiEventLogger +import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import java.util.concurrent.Executor import javax.inject.Inject @@ -37,14 +39,20 @@ class InternetDialogFactory @Inject constructor( @Background private val executor: Executor, private val internetDialogController: InternetDialogController, private val context: Context, - private val uiEventLogger: UiEventLogger + private val uiEventLogger: UiEventLogger, + private val dialogLaunchAnimator: DialogLaunchAnimator ) { companion object { var internetDialog: InternetDialog? = null } - /** Creates a [InternetDialog]. */ - fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) { + /** Creates a [InternetDialog]. The dialog will be animated from [view] if it is not null. */ + fun create( + aboveStatusBar: Boolean, + canConfigMobileData: Boolean, + canConfigWifi: Boolean, + view: View? + ) { if (internetDialog != null) { if (DEBUG) { Log.d(TAG, "InternetDialog is showing, do not create it twice.") @@ -54,7 +62,11 @@ class InternetDialogFactory @Inject constructor( internetDialog = InternetDialog(context, this, internetDialogController, canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler, executor) - internetDialog?.show() + if (view != null) { + dialogLaunchAnimator.showFromView(internetDialog!!, view) + } else { + internetDialog?.show() + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt index 01afa56fc496..26d1bbde2a54 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt @@ -71,10 +71,6 @@ class UserDialog( setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars() attributes.receiveInsetsIgnoringZOrder = true - setLayout( - context.resources.getDimensionPixelSize(R.dimen.notification_panel_width), - ViewGroup.LayoutParams.WRAP_CONTENT - ) setGravity(Gravity.CENTER) } setContentView(R.layout.qs_user_dialog_content) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java index f72178f0c8b0..daae43f69d3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java @@ -811,7 +811,8 @@ public class NetworkControllerImpl extends BroadcastReceiver break; case Settings.Panel.ACTION_INTERNET_CONNECTIVITY: mMainHandler.post(() -> mInternetDialogFactory.create(true, - mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi())); + mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(), + null /* view */)); break; default: int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 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 9415d5082d10..18aa6893e7bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -22,7 +22,11 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Bundle; +import android.os.SystemProperties; import android.os.UserHandle; +import android.util.TypedValue; +import android.view.ViewGroup; import android.view.Window; import android.view.WindowInsets.Type; import android.view.WindowManager; @@ -45,6 +49,10 @@ import java.util.Set; * and dismisses itself when it receives the broadcast. */ public class SystemUIDialog extends AlertDialog implements ListenableDialog { + // 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"; + private final Context mContext; private final DismissReceiver mDismissReceiver; private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>(); @@ -66,6 +74,41 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { } @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Set the dialog window size. + getWindow().setLayout(getDialogWidth(), ViewGroup.LayoutParams.WRAP_CONTENT); + } + + private int getDialogWidth() { + boolean isOnTablet = + mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600; + if (!isOnTablet) { + return ViewGroup.LayoutParams.MATCH_PARENT; + } + + int flagValue = SystemProperties.getInt(FLAG_TABLET_DIALOG_WIDTH, 0); + if (flagValue == -1) { + // The width of bottom sheets (624dp). + return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 624, + mContext.getResources().getDisplayMetrics())); + } else if (flagValue == -2) { + // The suggested small width for all dialogs (348dp) + return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 348, + mContext.getResources().getDisplayMetrics())); + } else if (flagValue > 0) { + // Any given width. + return Math.round( + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, flagValue, + mContext.getResources().getDisplayMetrics())); + } else { + // By default we use the same width as the notification shade in portrait mode (504dp). + return mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width); + } + } + + @Override protected void onStart() { super.onStart(); mDismissReceiver.register(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java index 5cea7632192b..eb03b5ff2a6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java @@ -45,6 +45,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.wifi.WifiUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; @@ -138,6 +139,8 @@ public class InternetDialogControllerTest extends SysuiTestCase { private CarrierConfigTracker mCarrierConfigTracker; @Mock private LocationController mLocationController; + @Mock + private DialogLaunchAnimator mDialogLaunchAnimator; private TestableResources mTestableResources; private MockInternetDialogController mInternetDialogController; @@ -174,7 +177,7 @@ public class InternetDialogControllerTest extends SysuiTestCase { mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher, mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController, mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker, - mLocationController); + mLocationController, mDialogLaunchAnimator); mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, mInternetDialogController.mOnSubscriptionsChangedListener); mInternetDialogController.onStart(mInternetDialogCallback, true); @@ -654,12 +657,13 @@ public class InternetDialogControllerTest extends SysuiTestCase { KeyguardStateController keyguardStateController, WindowManager windowManager, ToastFactory toastFactory, Handler workerHandler, CarrierConfigTracker carrierConfigTracker, - LocationController locationController) { + LocationController locationController, + DialogLaunchAnimator dialogLaunchAnimator) { super(context, uiEventLogger, starter, accessPointController, subscriptionManager, telephonyManager, wifiManager, connectivityManager, handler, mainExecutor, broadcastDispatcher, keyguardUpdateMonitor, globalSettings, keyguardStateController, windowManager, toastFactory, workerHandler, - carrierConfigTracker, locationController); + carrierConfigTracker, locationController, dialogLaunchAnimator); mGlobalSettings = globalSettings; } |