1 package com.android.launcher3.taskbar.navbutton
2 
3 import android.content.res.Configuration
4 import android.content.res.Resources
5 import android.view.Surface
6 import android.view.Surface.ROTATION_270
7 import android.view.Surface.Rotation
8 import android.view.View
9 import android.view.ViewGroup
10 import android.widget.ImageView
11 import android.widget.LinearLayout
12 import android.widget.Space
13 import androidx.test.runner.AndroidJUnit4
14 import com.android.launcher3.DeviceProfile
15 import com.android.launcher3.R
16 import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
17 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
18 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
19 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
20 import org.junit.Assume.assumeTrue
21 import org.junit.Before
22 import org.junit.Test
23 import org.junit.runner.RunWith
24 import org.mockito.kotlin.mock
25 import org.mockito.kotlin.whenever
26 
27 @RunWith(AndroidJUnit4::class)
28 class NavButtonLayoutFactoryTest {
29 
30     private val mockDeviceProfile: DeviceProfile = mock()
31     private val mockParentButtonContainer: NearestTouchFrame = mock()
32     private val mockNavLayout: LinearLayout = mock()
33     private val mockStartContextualLayout: ViewGroup = mock()
34     private val mockEndContextualLayout: ViewGroup = mock()
35     private val mockResources: Resources = mock()
36     private val mockBackButton: ImageView = mock()
37     private val mockRecentsButton: ImageView = mock()
38     private val mockHomeButton: ImageView = mock()
39     private val mockImeSwitcher: ImageView = mock()
40     private val mockA11yButton: ImageView = mock()
41     private val mockSpace: Space = mock()
42     private val mockConfiguration: Configuration = mock()
43 
44     private var surfaceRotation = Surface.ROTATION_0
45 
46     @Before
setupnull47     fun setup() {
48         // Init end nav buttons
49         whenever(mockNavLayout.childCount).thenReturn(3)
50         whenever(mockNavLayout.findViewById<View>(R.id.back)).thenReturn(mockBackButton)
51         whenever(mockNavLayout.findViewById<View>(R.id.home)).thenReturn(mockHomeButton)
52         whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
53 
54         // Init top level layout
55         whenever(mockParentButtonContainer.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS))
56             .thenReturn(mockNavLayout)
57         whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS))
58             .thenReturn(mockEndContextualLayout)
59         whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS))
60             .thenReturn(mockStartContextualLayout)
61         whenever(mockBackButton.resources).thenReturn(mockResources)
62         whenever(mockResources.configuration).thenReturn(mockConfiguration)
63         whenever(mockConfiguration.layoutDirection).thenReturn(0)
64     }
65 
66     @Test
getKidsLayoutternull67     fun getKidsLayoutter() {
68         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
69         mockDeviceProfile.isTaskbarPresent = true
70         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
71             getLayoutter(
72                 isKidsMode = true,
73                 isInSetup = false,
74                 isThreeButtonNav = false,
75                 phoneMode = false,
76                 surfaceRotation = surfaceRotation
77             )
78         assert(layoutter is KidsNavLayoutter)
79     }
80 
81     @Test
getSetupLayoutternull82     fun getSetupLayoutter() {
83         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
84         mockDeviceProfile.isTaskbarPresent = true
85         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
86             getLayoutter(
87                 isKidsMode = false,
88                 isInSetup = true,
89                 isThreeButtonNav = false,
90                 phoneMode = false,
91                 surfaceRotation = surfaceRotation
92             )
93         assert(layoutter is SetupNavLayoutter)
94     }
95 
96     @Test
getTaskbarNavLayoutternull97     fun getTaskbarNavLayoutter() {
98         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
99         mockDeviceProfile.isTaskbarPresent = true
100         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
101             getLayoutter(
102                 isKidsMode = false,
103                 isInSetup = false,
104                 isThreeButtonNav = false,
105                 phoneMode = false,
106                 surfaceRotation = surfaceRotation
107             )
108         assert(layoutter is TaskbarNavLayoutter)
109     }
110 
111     @Test(expected = IllegalStateException::class)
noValidLayoutForLargeScreenTaskbarNotPresentnull112     fun noValidLayoutForLargeScreenTaskbarNotPresent() {
113         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
114         mockDeviceProfile.isTaskbarPresent = false
115         getLayoutter(
116             isKidsMode = false,
117             isInSetup = false,
118             isThreeButtonNav = false,
119             phoneMode = false,
120             surfaceRotation = surfaceRotation
121         )
122     }
123 
124     @Test
getTaskbarPortraitLayoutternull125     fun getTaskbarPortraitLayoutter() {
126         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
127         mockDeviceProfile.isTaskbarPresent = false
128         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
129             getLayoutter(
130                 isKidsMode = false,
131                 isInSetup = false,
132                 isThreeButtonNav = true,
133                 phoneMode = true,
134                 surfaceRotation = surfaceRotation
135             )
136         assert(layoutter is PhonePortraitNavLayoutter)
137     }
138 
139     @Test
getTaskbarLandscapeLayoutternull140     fun getTaskbarLandscapeLayoutter() {
141         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
142         mockDeviceProfile.isTaskbarPresent = false
143         setDeviceProfileLandscape()
144         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
145             getLayoutter(
146                 isKidsMode = false,
147                 isInSetup = false,
148                 isThreeButtonNav = true,
149                 phoneMode = true,
150                 surfaceRotation = surfaceRotation
151             )
152         assert(layoutter is PhoneLandscapeNavLayoutter)
153     }
154 
155     @Test
getTaskbarSeascapeLayoutternull156     fun getTaskbarSeascapeLayoutter() {
157         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
158         mockDeviceProfile.isTaskbarPresent = false
159         setDeviceProfileLandscape()
160         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
161             getLayoutter(
162                 isKidsMode = false,
163                 isInSetup = false,
164                 isThreeButtonNav = true,
165                 phoneMode = true,
166                 surfaceRotation = ROTATION_270
167             )
168         assert(layoutter is PhoneSeascapeNavLayoutter)
169     }
170 
171     @Test
getTaskbarPhoneGestureNavLayoutternull172     fun getTaskbarPhoneGestureNavLayoutter() {
173         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
174         mockDeviceProfile.isTaskbarPresent = false
175         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
176             getLayoutter(
177                 isKidsMode = false,
178                 isInSetup = false,
179                 isThreeButtonNav = false,
180                 phoneMode = true,
181                 surfaceRotation = surfaceRotation
182             )
183         assert(layoutter is PhoneGestureLayoutter)
184     }
185 
setDeviceProfileLandscapenull186     private fun setDeviceProfileLandscape() {
187         // Use reflection to modify landscape field
188         val landscapeField = mockDeviceProfile.javaClass.getDeclaredField("isLandscape")
189         landscapeField.isAccessible = true
190         landscapeField.set(mockDeviceProfile, true)
191     }
192 
getLayoutternull193     private fun getLayoutter(
194         isKidsMode: Boolean,
195         isInSetup: Boolean,
196         isThreeButtonNav: Boolean,
197         phoneMode: Boolean,
198         @Rotation surfaceRotation: Int
199     ): NavButtonLayoutFactory.NavButtonLayoutter {
200         return NavButtonLayoutFactory.getUiLayoutter(
201             deviceProfile = mockDeviceProfile,
202             navButtonsView = mockParentButtonContainer,
203             resources = mockResources,
204             isKidsMode = isKidsMode,
205             isInSetup = isInSetup,
206             isThreeButtonNav = isThreeButtonNav,
207             phoneMode = phoneMode,
208             surfaceRotation = surfaceRotation,
209             imeSwitcher = mockImeSwitcher,
210             a11yButton = mockA11yButton,
211             space = mockSpace,
212         )
213     }
214 }
215