Apply dialog style to User switcher dialog.

Apply the unified style and set just the inner content, relying on the
default title and buttons.

Also, fix using the vertical spacing in PseudoGridView.

Test: manual
Test: atest UserSwitchDialogControllerTest
Bug: 203666386
Change-Id: If6a0220979d9f9df584c29f4adce317341577cf4
Merged-In: If6a0220979d9f9df584c29f4adce317341577cf4
This commit is contained in:
Fabian Kozynski
2021-11-19 15:00:56 -05:00
parent 1a848af46f
commit a910be6dee
8 changed files with 39 additions and 277 deletions

View File

@@ -22,6 +22,6 @@
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
sysui:verticalSpacing="4dp"
sysui:verticalSpacing="20dp"
sysui:horizontalSpacing="4dp"
style="@style/UserDetailView" />

View File

@@ -24,8 +24,6 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="top|center_horizontal"
android:paddingTop="16dp"
android:minHeight="112dp"
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="true"

View File

@@ -15,75 +15,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<androidx.constraintlayout.widget.ConstraintLayout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
>
<TextView
android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:textAlignment="center"
android:text="@string/qs_user_switch_dialog_title"
android:textAppearance="@style/TextAppearance.Dialog.Title"
android:layout_marginBottom="32dp"
sysui:layout_constraintTop_toTopOf="parent"
sysui:layout_constraintStart_toStartOf="parent"
sysui:layout_constraintEnd_toEndOf="parent"
sysui:layout_constraintBottom_toTopOf="@id/grid"
/>
>
<com.android.systemui.qs.PseudoGridView
android:id="@+id/grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="28dp"
sysui:verticalSpacing="4dp"
sysui:horizontalSpacing="4dp"
sysui:fixedChildWidth="80dp"
sysui:layout_constraintTop_toBottomOf="@id/title"
sysui:layout_constraintStart_toStartOf="parent"
sysui:layout_constraintEnd_toEndOf="parent"
sysui:layout_constraintBottom_toTopOf="@id/barrier"
/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
sysui:barrierDirection="top"
sysui:constraint_referenced_ids="settings,done"
android:id="@+id/grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
sysui:verticalSpacing="20dp"
sysui:horizontalSpacing="4dp"
sysui:fixedChildWidth="80dp"
/>
<Button
android:id="@+id/settings"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:text="@string/quick_settings_more_user_settings"
sysui:layout_constraintTop_toBottomOf="@id/barrier"
sysui:layout_constraintBottom_toBottomOf="parent"
sysui:layout_constraintStart_toStartOf="parent"
sysui:layout_constraintEnd_toStartOf="@id/done"
sysui:layout_constraintHorizontal_chainStyle="spread_inside"
style="@style/Widget.Dialog.Button.BorderButton"
/>
<Button
android:id="@+id/done"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:text="@string/quick_settings_done"
sysui:layout_constraintTop_toBottomOf="@id/barrier"
sysui:layout_constraintBottom_toBottomOf="parent"
sysui:layout_constraintStart_toEndOf="@id/settings"
sysui:layout_constraintEnd_toEndOf="parent"
style="@style/Widget.Dialog.Button"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@@ -133,10 +133,7 @@ public class PseudoGridView extends ViewGroup {
x += width + mHorizontalSpacing;
}
}
y += maxHeight;
if (row > 0) {
y += mVerticalSpacing;
}
y += maxHeight + mVerticalSpacing;
}
}

View File

@@ -1,82 +0,0 @@
/*
* 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.qs.user
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManager
import com.android.systemui.qs.PseudoGridView
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.R
/**
* Dialog for switching users or creating new ones.
*/
class UserDialog(
context: Context
) : SystemUIDialog(context) {
// create() is no-op after creation
private lateinit var _doneButton: View
/**
* Button with text "Done" in dialog.
*/
val doneButton: View
get() {
create()
return _doneButton
}
private lateinit var _settingsButton: View
/**
* Button with text "User Settings" in dialog.
*/
val settingsButton: View
get() {
create()
return _settingsButton
}
private lateinit var _grid: PseudoGridView
/**
* Grid to populate with user avatar from adapter
*/
val grid: ViewGroup
get() {
create()
return _grid
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window?.apply {
setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
attributes.receiveInsetsIgnoringZOrder = true
setGravity(Gravity.CENTER)
}
setContentView(R.layout.qs_user_dialog_content)
_doneButton = requireViewById(R.id.done)
_settingsButton = requireViewById(R.id.settings)
_grid = requireViewById(R.id.grid)
}
}

View File

@@ -21,13 +21,16 @@ import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.provider.Settings
import android.view.LayoutInflater
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
import javax.inject.Provider
@@ -40,7 +43,7 @@ class UserSwitchDialogController @VisibleForTesting constructor(
private val activityStarter: ActivityStarter,
private val falsingManager: FalsingManager,
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val dialogFactory: (Context) -> UserDialog
private val dialogFactory: (Context) -> SystemUIDialog
) {
@Inject
@@ -54,7 +57,7 @@ class UserSwitchDialogController @VisibleForTesting constructor(
activityStarter,
falsingManager,
dialogLaunchAnimator,
{ UserDialog(it) }
{ SystemUIDialog(it) }
)
companion object {
@@ -71,9 +74,10 @@ class UserSwitchDialogController @VisibleForTesting constructor(
with(dialogFactory(view.context)) {
setShowForAllUsers(true)
setCanceledOnTouchOutside(true)
create() // Needs to be called before we can retrieve views
settingsButton.setOnClickListener {
setTitle(R.string.qs_user_switch_dialog_title)
setPositiveButton(R.string.quick_settings_done, null)
setNeutralButton(R.string.quick_settings_more_user_settings) { _, _ ->
if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
activityStarter.postStartActivityDismissingKeyguard(
@@ -81,12 +85,14 @@ class UserSwitchDialogController @VisibleForTesting constructor(
0
)
}
dismiss()
}
doneButton.setOnClickListener { dismiss() }
val gridFrame = LayoutInflater.from(this.context)
.inflate(R.layout.qs_user_dialog_content, null)
setView(gridFrame)
val adapter = userDetailViewAdapterProvider.get()
adapter.linkToViewGroup(grid)
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
val hostDialog = dialogLaunchAnimator.showFromView(this, view)
adapter.injectDialogShower(DialogShowerImpl(hostDialog, dialogLaunchAnimator))

View File

@@ -1,62 +0,0 @@
/*
* 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.qs.user
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class UserDialogTest : SysuiTestCase() {
private lateinit var dialog: UserDialog
@Before
fun setUp() {
dialog = UserDialog(mContext)
}
@After
fun tearDown() {
dialog.dismiss()
}
@Test
fun doneButtonExists() {
assertThat(dialog.doneButton).isInstanceOf(View::class.java)
}
@Test
fun settingsButtonExists() {
assertThat(dialog.settingsButton).isInstanceOf(View::class.java)
}
@Test
fun gridExistsAndIsViewGroup() {
assertThat(dialog.grid).isInstanceOf(ViewGroup::class.java)
}
}

View File

@@ -17,6 +17,7 @@
package com.android.systemui.qs.user
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.provider.Settings
import android.testing.AndroidTestingRunner
@@ -28,6 +29,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PseudoGridView
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -43,7 +45,6 @@ import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.argThat
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -53,27 +54,21 @@ import org.mockito.MockitoAnnotations
class UserSwitchDialogControllerTest : SysuiTestCase() {
@Mock
private lateinit var dialog: UserDialog
private lateinit var dialog: SystemUIDialog
@Mock
private lateinit var falsingManager: FalsingManager
@Mock
private lateinit var settingsView: View
@Mock
private lateinit var doneView: View
@Mock
private lateinit var activityStarter: ActivityStarter
@Mock
private lateinit var userDetailViewAdapter: UserDetailView.Adapter
@Mock
private lateinit var launchView: View
@Mock
private lateinit var gridView: PseudoGridView
@Mock
private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
@Mock
private lateinit var hostDialog: Dialog
@Captor
private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener>
private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener>
private lateinit var controller: UserSwitchDialogController
@@ -81,11 +76,8 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
`when`(dialog.settingsButton).thenReturn(settingsView)
`when`(dialog.doneButton).thenReturn(doneView)
`when`(dialog.grid).thenReturn(gridView)
`when`(launchView.context).thenReturn(mContext)
`when`(dialog.context).thenReturn(mContext)
`when`(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
.thenReturn(hostDialog)
@@ -104,30 +96,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
verify(dialogLaunchAnimator).showFromView(dialog, launchView)
}
@Test
fun createCalledBeforeDoneButton() {
controller.showDialog(launchView)
val inOrder = inOrder(dialog)
inOrder.verify(dialog).create()
inOrder.verify(dialog).doneButton
}
@Test
fun createCalledBeforeSettingsButton() {
controller.showDialog(launchView)
val inOrder = inOrder(dialog)
inOrder.verify(dialog).create()
inOrder.verify(dialog).settingsButton
}
@Test
fun createCalledBeforeGrid() {
controller.showDialog(launchView)
val inOrder = inOrder(dialog)
inOrder.verify(dialog).create()
inOrder.verify(dialog).grid
}
@Test
fun dialog_showForAllUsers() {
controller.showDialog(launchView)
@@ -143,51 +111,44 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
@Test
fun adapterAndGridLinked() {
controller.showDialog(launchView)
verify(userDetailViewAdapter).linkToViewGroup(gridView)
verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>())
}
@Test
fun clickDoneButton_dismiss() {
fun doneButtonSetWithNullHandler() {
controller.showDialog(launchView)
verify(doneView).setOnClickListener(capture(clickCaptor))
clickCaptor.value.onClick(doneView)
verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
verify(dialog).dismiss()
verify(dialog).setPositiveButton(anyInt(), eq(null))
}
@Test
fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() {
fun clickSettingsButton_noFalsing_opensSettings() {
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(false)
controller.showDialog(launchView)
verify(settingsView).setOnClickListener(capture(clickCaptor))
verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor))
clickCaptor.value.onClick(settingsView)
clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL)
verify(activityStarter)
.postStartActivityDismissingKeyguard(
argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)),
eq(0)
)
verify(dialog).dismiss()
}
@Test
fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() {
fun clickSettingsButton_Falsing_notOpensSettings() {
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(true)
controller.showDialog(launchView)
verify(settingsView).setOnClickListener(capture(clickCaptor))
verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor))
clickCaptor.value.onClick(settingsView)
clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL)
verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
verify(dialog).dismiss()
}
@Test