From aaeae6404581c176cadd66b5e2a205d12f949edb Mon Sep 17 00:00:00 2001 From: Giulio Fiscella Date: Fri, 17 Feb 2023 17:12:21 +0000 Subject: [PATCH] New privacy dialog go/new-sysui-privacy-dialog Bug: 283456173 Test: atest SystemUITests Change-Id: I63e6200e418fff94acc8dd7eaa551d15e049ba8a --- .../animation/DialogLaunchAnimator.kt | 95 +--- .../src/com/android/systemui/util/Dialog.kt | 111 ++++ .../privacy_dialog_expand_toggle_down.xml | 31 + .../privacy_dialog_expand_toggle_up.xml | 31 + .../privacy_dialog_background_circle.xml | 29 + ...alog_background_large_top_large_bottom.xml | 39 ++ ...alog_background_large_top_small_bottom.xml | 39 ++ ...alog_background_small_top_large_bottom.xml | 39 ++ ...alog_background_small_top_small_bottom.xml | 39 ++ .../drawable/privacy_dialog_check_icon.xml | 25 + ...privacy_dialog_default_permission_icon.xml | 25 + .../privacy_dialog_expand_toggle_down.xml | 30 + .../privacy_dialog_expand_toggle_up.xml | 30 + .../res/layout/privacy_dialog_card_button.xml | 26 + .../res/layout/privacy_dialog_item_v2.xml | 89 +++ .../SystemUI/res/layout/privacy_dialog_v2.xml | 109 ++++ packages/SystemUI/res/values/colors.xml | 3 +- packages/SystemUI/res/values/dimens.xml | 3 + packages/SystemUI/res/values/ids.xml | 4 + packages/SystemUI/res/values/strings.xml | 43 +- packages/SystemUI/res/values/styles.xml | 18 + .../privacy/PrivacyDialogControllerV2.kt | 282 +++++----- .../systemui/privacy/PrivacyDialogEvent.kt | 11 +- .../systemui/privacy/PrivacyDialogV2.kt | 529 ++++++++++++++---- .../systemui/privacy/logging/PrivacyLogger.kt | 21 +- .../qs/HeaderPrivacyIconsController.kt | 2 +- .../privacy/PrivacyDialogControllerV2Test.kt | 189 ++++--- .../systemui/privacy/PrivacyDialogV2Test.kt | 452 ++++++--------- .../qs/HeaderPrivacyIconsControllerTest.kt | 12 +- 29 files changed, 1663 insertions(+), 693 deletions(-) create mode 100644 packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml create mode 100644 packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_background_circle.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_background_large_top_large_bottom.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_background_large_top_small_bottom.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_background_small_top_large_bottom.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_background_small_top_small_bottom.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_check_icon.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_default_permission_icon.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml create mode 100644 packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml create mode 100644 packages/SystemUI/res/layout/privacy_dialog_card_button.xml create mode 100644 packages/SystemUI/res/layout/privacy_dialog_item_v2.xml create mode 100644 packages/SystemUI/res/layout/privacy_dialog_v2.xml 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 dbfa192f5ec48..37b1ee543e463 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -32,11 +32,10 @@ import android.view.ViewRootImpl import android.view.WindowInsets import android.view.WindowManager import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS -import android.widget.FrameLayout import com.android.app.animation.Interpolators import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CujType -import com.android.systemui.animation.view.LaunchableFrameLayout +import com.android.systemui.util.maybeForceFullscreen import com.android.systemui.util.registerAnimationOnBackInvoked import kotlin.math.roundToInt @@ -622,96 +621,12 @@ private class AnimatedDialog( viewGroupWithBackground } else { - // We will make the dialog window (and therefore its DecorView) fullscreen to make - // it possible to animate outside its bounds. - // - // Before that, we add a new View as a child of the DecorView with the same size and - // gravity as that DecorView, then we add all original children of the DecorView to - // that new View. Finally we remove the background of the DecorView and add it to - // the new View, then we make the DecorView fullscreen. This new View now acts as a - // fake (non fullscreen) window. - // - // On top of that, we also add a fullscreen transparent background between the - // DecorView and the view that we added so that we can dismiss the dialog when this - // view is clicked. This is necessary because DecorView overrides onTouchEvent and - // therefore we can't set the click listener directly on the (now fullscreen) - // DecorView. - val fullscreenTransparentBackground = FrameLayout(dialog.context) - decorView.addView( - fullscreenTransparentBackground, - 0 /* index */, - FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - ) - - val dialogContentWithBackground = LaunchableFrameLayout(dialog.context) - dialogContentWithBackground.background = decorView.background - - // Make the window background transparent. Note that setting the window (or - // DecorView) background drawable to null leads to issues with background color (not - // being transparent) or with insets that are not refreshed. Therefore we need to - // set it to something not null, hence we are using android.R.color.transparent - // here. - window.setBackgroundDrawableResource(android.R.color.transparent) - - // Close the dialog when clicking outside of it. - fullscreenTransparentBackground.setOnClickListener { dialog.dismiss() } - dialogContentWithBackground.isClickable = true - - // Make sure the transparent and dialog backgrounds are not focusable by - // accessibility - // features. - fullscreenTransparentBackground.importantForAccessibility = - View.IMPORTANT_FOR_ACCESSIBILITY_NO - dialogContentWithBackground.importantForAccessibility = - View.IMPORTANT_FOR_ACCESSIBILITY_NO - - fullscreenTransparentBackground.addView( - dialogContentWithBackground, - FrameLayout.LayoutParams( - window.attributes.width, - window.attributes.height, - window.attributes.gravity - ) - ) - - // Move all original children of the DecorView to the new View we just added. - for (i in 1 until decorView.childCount) { - val view = decorView.getChildAt(1) - decorView.removeViewAt(1) - dialogContentWithBackground.addView(view) - } - - // Make the window fullscreen and add a layout listener to ensure it stays - // fullscreen. - window.setLayout(MATCH_PARENT, MATCH_PARENT) - decorViewLayoutListener = - View.OnLayoutChangeListener { - v, - left, - top, - right, - bottom, - oldLeft, - oldTop, - oldRight, - oldBottom -> - if ( - window.attributes.width != MATCH_PARENT || - window.attributes.height != MATCH_PARENT - ) { - // The dialog size changed, copy its size to dialogContentWithBackground - // and make the dialog window full screen again. - val layoutParams = dialogContentWithBackground.layoutParams - layoutParams.width = window.attributes.width - layoutParams.height = window.attributes.height - dialogContentWithBackground.layoutParams = layoutParams - window.setLayout(MATCH_PARENT, MATCH_PARENT) - } - } - decorView.addOnLayoutChangeListener(decorViewLayoutListener) - + val (dialogContentWithBackground, decorViewLayoutListener) = + dialog.maybeForceFullscreen()!! + this.decorViewLayoutListener = decorViewLayoutListener dialogContentWithBackground } + this.dialogContentWithBackground = dialogContentWithBackground dialogContentWithBackground.setTag(R.id.tag_dialog_background, true) diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt index 428856dc5f300..0f63548b6f0c1 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt @@ -18,6 +18,9 @@ package com.android.systemui.util import android.app.Dialog import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout import android.window.OnBackInvokedDispatcher import com.android.systemui.animation.back.BackAnimationSpec import com.android.systemui.animation.back.BackTransformation @@ -25,6 +28,7 @@ import com.android.systemui.animation.back.applyTo import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi import com.android.systemui.animation.back.onBackAnimationCallbackFrom import com.android.systemui.animation.back.registerOnBackInvokedCallbackOnViewAttached +import com.android.systemui.animation.view.LaunchableFrameLayout /** * Register on the Dialog's [OnBackInvokedDispatcher] an animation using the [BackAnimationSpec]. @@ -49,3 +53,110 @@ fun Dialog.registerAnimationOnBackInvoked( ), ) } + +/** + * Make the dialog window (and therefore its DecorView) fullscreen to make it possible to animate + * outside its bounds. No-op if the dialog is already fullscreen. + * + *

Returns null if the dialog is already fullscreen. Otherwise, returns a pair containing a view + * and a layout listener. The new view matches the original dialog DecorView in size, position, and + * background. This new view will be a child of the modified, transparent, fullscreen DecorView. The + * layout listener is listening to changes to the modified DecorView. It is the responsibility of + * the caller to deregister the listener when the dialog is dismissed. + */ +fun Dialog.maybeForceFullscreen(): Pair? { + // Create the dialog so that its onCreate() method is called, which usually sets the dialog + // content. + create() + + val window = window!! + val decorView = window.decorView as ViewGroup + + val isWindowFullscreen = + window.attributes.width == MATCH_PARENT && window.attributes.height == MATCH_PARENT + if (isWindowFullscreen) { + return null + } + + // We will make the dialog window (and therefore its DecorView) fullscreen to make it possible + // to animate outside its bounds. + // + // Before that, we add a new View as a child of the DecorView with the same size and gravity as + // that DecorView, then we add all original children of the DecorView to that new View. Finally + // we remove the background of the DecorView and add it to the new View, then we make the + // DecorView fullscreen. This new View now acts as a fake (non fullscreen) window. + // + // On top of that, we also add a fullscreen transparent background between the DecorView and the + // view that we added so that we can dismiss the dialog when this view is clicked. This is + // necessary because DecorView overrides onTouchEvent and therefore we can't set the click + // listener directly on the (now fullscreen) DecorView. + val fullscreenTransparentBackground = FrameLayout(context) + decorView.addView( + fullscreenTransparentBackground, + 0 /* index */, + FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + ) + + val dialogContentWithBackground = LaunchableFrameLayout(context) + dialogContentWithBackground.background = decorView.background + + // Make the window background transparent. Note that setting the window (or DecorView) + // background drawable to null leads to issues with background color (not being transparent) or + // with insets that are not refreshed. Therefore we need to set it to something not null, hence + // we are using android.R.color.transparent here. + window.setBackgroundDrawableResource(android.R.color.transparent) + + // Close the dialog when clicking outside of it. + fullscreenTransparentBackground.setOnClickListener { dismiss() } + dialogContentWithBackground.isClickable = true + + // Make sure the transparent and dialog backgrounds are not focusable by accessibility + // features. + fullscreenTransparentBackground.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO + dialogContentWithBackground.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO + + fullscreenTransparentBackground.addView( + dialogContentWithBackground, + FrameLayout.LayoutParams( + window.attributes.width, + window.attributes.height, + window.attributes.gravity + ) + ) + + // Move all original children of the DecorView to the new View we just added. + for (i in 1 until decorView.childCount) { + val view = decorView.getChildAt(1) + decorView.removeViewAt(1) + dialogContentWithBackground.addView(view) + } + + // Make the window fullscreen and add a layout listener to ensure it stays fullscreen. + window.setLayout(MATCH_PARENT, MATCH_PARENT) + val decorViewLayoutListener = + View.OnLayoutChangeListener { + v, + left, + top, + right, + bottom, + oldLeft, + oldTop, + oldRight, + oldBottom -> + if ( + window.attributes.width != MATCH_PARENT || window.attributes.height != MATCH_PARENT + ) { + // The dialog size changed, copy its size to dialogContentWithBackground and make + // the dialog window full screen again. + val layoutParams = dialogContentWithBackground.layoutParams + layoutParams.width = window.attributes.width + layoutParams.height = window.attributes.height + dialogContentWithBackground.layoutParams = layoutParams + window.setLayout(MATCH_PARENT, MATCH_PARENT) + } + } + decorView.addOnLayoutChangeListener(decorViewLayoutListener) + + return dialogContentWithBackground to decorViewLayoutListener +} diff --git a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml new file mode 100644 index 0000000000000..16076b17a6e57 --- /dev/null +++ b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml new file mode 100644 index 0000000000000..309770ddd76d3 --- /dev/null +++ b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_background_circle.xml b/packages/SystemUI/res/drawable/privacy_dialog_background_circle.xml new file mode 100644 index 0000000000000..f63c2ffbfdad9 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_background_circle.xml @@ -0,0 +1,29 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_large_bottom.xml b/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_large_bottom.xml new file mode 100644 index 0000000000000..5d5529ff1a508 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_large_bottom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_small_bottom.xml b/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_small_bottom.xml new file mode 100644 index 0000000000000..310b0becf10c4 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_background_large_top_small_bottom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_large_bottom.xml b/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_large_bottom.xml new file mode 100644 index 0000000000000..e89bdd31ca179 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_large_bottom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_small_bottom.xml b/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_small_bottom.xml new file mode 100644 index 0000000000000..fcf0b1c5091f2 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_background_small_top_small_bottom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_check_icon.xml b/packages/SystemUI/res/drawable/privacy_dialog_check_icon.xml new file mode 100644 index 0000000000000..b9f5d60abd8bb --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_check_icon.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/privacy_dialog_default_permission_icon.xml b/packages/SystemUI/res/drawable/privacy_dialog_default_permission_icon.xml new file mode 100644 index 0000000000000..ea8f9c2839ec1 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_default_permission_icon.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml new file mode 100644 index 0000000000000..f8b99f4a0ee4b --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml new file mode 100644 index 0000000000000..ae60d517ceb4d --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/packages/SystemUI/res/layout/privacy_dialog_card_button.xml b/packages/SystemUI/res/layout/privacy_dialog_card_button.xml new file mode 100644 index 0000000000000..e297b939e2b81 --- /dev/null +++ b/packages/SystemUI/res/layout/privacy_dialog_card_button.xml @@ -0,0 +1,26 @@ + +