1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.qs.user 18 19 import android.content.DialogInterface 20 import android.content.Intent 21 import android.provider.Settings 22 import android.widget.Button 23 import androidx.test.ext.junit.runners.AndroidJUnit4 24 import androidx.test.filters.SmallTest 25 import com.android.internal.logging.UiEventLogger 26 import com.android.systemui.SysuiTestCase 27 import com.android.systemui.animation.DialogTransitionAnimator 28 import com.android.systemui.animation.Expandable 29 import com.android.systemui.plugins.ActivityStarter 30 import com.android.systemui.plugins.FalsingManager 31 import com.android.systemui.qs.PseudoGridView 32 import com.android.systemui.qs.QSUserSwitcherEvent 33 import com.android.systemui.qs.tiles.UserDetailView 34 import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor 35 import com.android.systemui.statusbar.phone.SystemUIDialog 36 import com.android.systemui.util.mockito.capture 37 import com.android.systemui.util.mockito.eq 38 import com.android.systemui.util.mockito.mock 39 import com.android.systemui.util.mockito.whenever 40 import org.junit.Before 41 import org.junit.Test 42 import org.junit.runner.RunWith 43 import org.mockito.ArgumentCaptor 44 import org.mockito.ArgumentMatcher 45 import org.mockito.Captor 46 import org.mockito.Mock 47 import org.mockito.Mockito.anyBoolean 48 import org.mockito.Mockito.anyInt 49 import org.mockito.Mockito.argThat 50 import org.mockito.Mockito.never 51 import org.mockito.Mockito.verify 52 import org.mockito.Mockito.`when` 53 import org.mockito.MockitoAnnotations 54 import org.mockito.kotlin.any 55 56 @SmallTest 57 @RunWith(AndroidJUnit4::class) 58 class UserSwitchDialogControllerTest : SysuiTestCase() { 59 60 @Mock private lateinit var dialogFactory: SystemUIDialog.Factory 61 @Mock private lateinit var dialog: SystemUIDialog 62 @Mock private lateinit var falsingManager: FalsingManager 63 @Mock private lateinit var activityStarter: ActivityStarter 64 @Mock private lateinit var userDetailViewAdapter: UserDetailView.Adapter 65 @Mock private lateinit var launchExpandable: Expandable 66 @Mock private lateinit var neutralButton: Button 67 @Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator 68 @Mock private lateinit var uiEventLogger: UiEventLogger 69 @Captor private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener> 70 71 private lateinit var controller: UserSwitchDialogController 72 73 @Before setUpnull74 fun setUp() { 75 MockitoAnnotations.initMocks(this) 76 77 whenever(dialog.context).thenReturn(mContext) 78 whenever(dialogFactory.create(eq(mContext))).thenReturn(dialog) 79 80 controller = 81 UserSwitchDialogController( 82 { userDetailViewAdapter }, 83 activityStarter, 84 falsingManager, 85 mDialogTransitionAnimator, 86 uiEventLogger, 87 dialogFactory, 88 FakeShadeDialogContextInteractor(mContext), 89 ) 90 } 91 92 @Test showDialog_callsDialogShownull93 fun showDialog_callsDialogShow() { 94 val launchController = mock<DialogTransitionAnimator.Controller>() 95 `when`(launchExpandable.dialogTransitionController(any())).thenReturn(launchController) 96 controller.showDialog(launchExpandable) 97 verify(mDialogTransitionAnimator).show(eq(dialog), eq(launchController), anyBoolean()) 98 verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) 99 } 100 101 @Test dialog_showForAllUsersnull102 fun dialog_showForAllUsers() { 103 controller.showDialog(launchExpandable) 104 verify(dialog).setShowForAllUsers(true) 105 } 106 107 @Test dialog_cancelOnTouchOutsidenull108 fun dialog_cancelOnTouchOutside() { 109 controller.showDialog(launchExpandable) 110 verify(dialog).setCanceledOnTouchOutside(true) 111 } 112 113 @Test adapterAndGridLinkednull114 fun adapterAndGridLinked() { 115 controller.showDialog(launchExpandable) 116 verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>()) 117 } 118 119 @Test doneButtonLogsCorrectlynull120 fun doneButtonLogsCorrectly() { 121 controller.showDialog(launchExpandable) 122 123 verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor)) 124 125 clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) 126 127 verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE) 128 } 129 130 @Test clickSettingsButton_noFalsing_opensSettingsnull131 fun clickSettingsButton_noFalsing_opensSettings() { 132 `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) 133 134 controller.showDialog(launchExpandable) 135 136 verify(dialog) 137 .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) 138 `when`(dialog.getButton(DialogInterface.BUTTON_NEUTRAL)).thenReturn(neutralButton) 139 140 clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) 141 142 verify(activityStarter) 143 .postStartActivityDismissingKeyguard( 144 argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)), 145 eq(0), 146 eq(null), 147 ) 148 verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS) 149 } 150 151 @Test clickSettingsButton_Falsing_notOpensSettingsnull152 fun clickSettingsButton_Falsing_notOpensSettings() { 153 `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) 154 155 controller.showDialog(launchExpandable) 156 157 verify(dialog) 158 .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) 159 160 clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) 161 162 verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) 163 } 164 165 private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> { matchesnull166 override fun matches(argument: Intent?): Boolean { 167 return argument?.action == action 168 } 169 } 170 } 171