1 /*
2  * Copyright (C) 2022 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.settings.brightness
18 
19 import android.content.Intent
20 import android.graphics.Rect
21 import android.testing.AndroidTestingRunner
22 import android.testing.TestableLooper
23 import android.view.View
24 import android.view.ViewGroup
25 import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
26 import androidx.test.filters.SmallTest
27 import androidx.test.rule.ActivityTestRule
28 import com.android.systemui.R
29 import com.android.systemui.SysuiTestCase
30 import com.android.systemui.activity.SingleActivityFactory
31 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
32 import com.android.systemui.util.concurrency.DelayableExecutor
33 import com.android.systemui.util.concurrency.FakeExecutor
34 import com.android.systemui.util.mockito.any
35 import com.android.systemui.util.time.FakeSystemClock
36 import com.google.common.truth.Truth.assertThat
37 import org.junit.After
38 import org.junit.Before
39 import org.junit.Rule
40 import org.junit.Test
41 import org.junit.runner.RunWith
42 import org.mockito.Mock
43 import org.mockito.Mockito.anyInt
44 import org.mockito.Mockito.eq
45 import org.mockito.Mockito.`when`
46 import org.mockito.MockitoAnnotations
47 
48 @SmallTest
49 @RunWith(AndroidTestingRunner::class)
50 @TestableLooper.RunWithLooper
51 class BrightnessDialogTest : SysuiTestCase() {
52 
53     @Mock private lateinit var brightnessSliderControllerFactory: BrightnessSliderController.Factory
54     @Mock private lateinit var brightnessSliderController: BrightnessSliderController
55     @Mock private lateinit var brightnessControllerFactory: BrightnessController.Factory
56     @Mock private lateinit var brightnessController: BrightnessController
57     @Mock private lateinit var accessibilityMgr: AccessibilityManagerWrapper
58 
59     private val clock = FakeSystemClock()
60     private val mainExecutor = FakeExecutor(clock)
61 
62     @Rule
63     @JvmField
64     var activityRule =
65         ActivityTestRule(
66             /* activityFactory= */ SingleActivityFactory {
67                 TestDialog(
68                     brightnessSliderControllerFactory,
69                     brightnessControllerFactory,
70                     mainExecutor,
71                     accessibilityMgr
72                 )
73             },
74             /* initialTouchMode= */ false,
75             /* launchActivity= */ false,
76         )
77 
78     @Before
79     fun setUp() {
80         MockitoAnnotations.initMocks(this)
81         `when`(brightnessSliderControllerFactory.create(any(), any()))
82             .thenReturn(brightnessSliderController)
83         `when`(brightnessSliderController.rootView).thenReturn(View(context))
84         `when`(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
85     }
86 
87     @After
88     fun tearDown() {
89         activityRule.finishActivity()
90     }
91 
92     @Test
93     fun testGestureExclusion() {
94         activityRule.launchActivity(Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG))
95         val frame = activityRule.activity.requireViewById<View>(R.id.brightness_mirror_container)
96 
97         val lp = frame.layoutParams as ViewGroup.MarginLayoutParams
98         val horizontalMargin =
99             activityRule.activity.resources.getDimensionPixelSize(
100                 R.dimen.notification_side_paddings
101             )
102         assertThat(lp.leftMargin).isEqualTo(horizontalMargin)
103         assertThat(lp.rightMargin).isEqualTo(horizontalMargin)
104 
105         assertThat(frame.systemGestureExclusionRects.size).isEqualTo(1)
106         val exclusion = frame.systemGestureExclusionRects[0]
107         assertThat(exclusion)
108             .isEqualTo(Rect(-horizontalMargin, 0, frame.width + horizontalMargin, frame.height))
109     }
110 
111     @Test
112     fun testTimeout() {
113         `when`(
114                 accessibilityMgr.getRecommendedTimeoutMillis(
115                     eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
116                     anyInt()
117                 )
118             )
119             .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
120         val intent = Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)
121         intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true)
122         activityRule.launchActivity(intent)
123 
124         assertThat(activityRule.activity.isFinishing()).isFalse()
125 
126         clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong())
127         assertThat(activityRule.activity.isFinishing()).isTrue()
128     }
129 
130     @Test
131     fun testRestartTimeout() {
132         `when`(
133                 accessibilityMgr.getRecommendedTimeoutMillis(
134                     eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
135                     anyInt()
136                 )
137             )
138             .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
139         val intent = Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)
140         intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true)
141         activityRule.launchActivity(intent)
142 
143         assertThat(activityRule.activity.isFinishing()).isFalse()
144 
145         clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
146         // Restart the timeout
147         activityRule.activity.onResume()
148 
149         clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
150         // The dialog should not have disappeared yet
151         assertThat(activityRule.activity.isFinishing()).isFalse()
152 
153         clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
154         assertThat(activityRule.activity.isFinishing()).isTrue()
155     }
156 
157     @Test
158     fun testNoTimeoutIfNotStartedByBrightnessKey() {
159         `when`(
160                 accessibilityMgr.getRecommendedTimeoutMillis(
161                     eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
162                     anyInt()
163                 )
164             )
165             .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
166         activityRule.launchActivity(Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG))
167 
168         assertThat(activityRule.activity.isFinishing()).isFalse()
169 
170         clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong())
171         assertThat(activityRule.activity.isFinishing()).isFalse()
172     }
173 
174     class TestDialog(
175         brightnessSliderControllerFactory: BrightnessSliderController.Factory,
176         brightnessControllerFactory: BrightnessController.Factory,
177         mainExecutor: DelayableExecutor,
178         accessibilityMgr: AccessibilityManagerWrapper
179     ) :
180         BrightnessDialog(
181             brightnessSliderControllerFactory,
182             brightnessControllerFactory,
183             mainExecutor,
184             accessibilityMgr
185         )
186 }
187