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.
This commit is contained in:
committed by
Android (Google) Code Review
commit
a5088b1302
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<>();
|
||||
@@ -65,6 +73,41 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
||||
mDismissReceiver = new DismissReceiver(this);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user