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.statusbar.phone
18 
19 import android.view.LayoutInflater
20 import android.view.MotionEvent
21 import android.view.ViewGroup
22 import android.view.ViewTreeObserver
23 import android.view.ViewTreeObserver.OnPreDrawListener
24 import android.widget.FrameLayout
25 import androidx.test.filters.SmallTest
26 import androidx.test.platform.app.InstrumentationRegistry
27 import com.android.systemui.R
28 import com.android.systemui.SysuiTestCase
29 import com.android.systemui.unfold.SysUIUnfoldComponent
30 import com.android.systemui.unfold.config.UnfoldTransitionConfig
31 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
32 import com.android.systemui.util.mockito.any
33 import com.google.common.truth.Truth.assertThat
34 import org.junit.Before
35 import org.junit.Test
36 import org.mockito.ArgumentCaptor
37 import org.mockito.Mock
38 import org.mockito.Mockito.spy
39 import org.mockito.Mockito.mock
40 import org.mockito.Mockito.`when`
41 import org.mockito.Mockito.verify
42 import org.mockito.MockitoAnnotations
43 import java.util.Optional
44 
45 @SmallTest
46 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
47 
48     private val touchEventHandler = TestTouchEventHandler()
49 
50     @Mock
51     private lateinit var panelViewController: PanelViewController
52     @Mock
53     private lateinit var panelView: ViewGroup
54     @Mock
55     private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
56     @Mock
57     private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
58     @Mock
59     private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
60 
61     private lateinit var view: PhoneStatusBarView
62     private lateinit var controller: PhoneStatusBarViewController
63 
64     private val unfoldConfig = UnfoldConfig()
65 
66     @Before
67     fun setUp() {
68         MockitoAnnotations.initMocks(this)
69         `when`(panelViewController.view).thenReturn(panelView)
70         `when`(sysuiUnfoldComponent.getStatusBarMoveFromCenterAnimationController())
71             .thenReturn(moveFromCenterAnimation)
72         // create the view on main thread as it requires main looper
73         InstrumentationRegistry.getInstrumentation().runOnMainSync {
74             val parent = FrameLayout(mContext) // add parent to keep layout params
75             view = LayoutInflater.from(mContext)
76                 .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
77         }
78 
79         controller = createController(view)
80     }
81 
82     @Test
83     fun constructor_setsTouchHandlerOnView() {
84         val interceptEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 10f, 10f, 0)
85         val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
86 
87         view.onInterceptTouchEvent(interceptEvent)
88         view.onTouchEvent(event)
89 
90         assertThat(touchEventHandler.lastInterceptEvent).isEqualTo(interceptEvent)
91         assertThat(touchEventHandler.lastEvent).isEqualTo(event)
92     }
93 
94     @Test
95     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
96         val view = createViewMock()
97         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
98         unfoldConfig.isEnabled = true
99         controller = createController(view)
100         controller.init()
101 
102         verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
103         argumentCaptor.value.onPreDraw()
104 
105         verify(moveFromCenterAnimation).onViewsReady(any())
106     }
107 
108     private fun createViewMock(): PhoneStatusBarView {
109         val view = spy(view)
110         val viewTreeObserver = mock(ViewTreeObserver::class.java)
111         `when`(view.viewTreeObserver).thenReturn(viewTreeObserver)
112         `when`(view.isAttachedToWindow).thenReturn(true)
113         return view
114     }
115 
116     private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController {
117         return PhoneStatusBarViewController.Factory(
118             Optional.of(sysuiUnfoldComponent),
119             Optional.of(progressProvider)
120         ).create(view, touchEventHandler)
121     }
122 
123     private class UnfoldConfig : UnfoldTransitionConfig {
124         override var isEnabled: Boolean = false
125         override var isHingeAngleEnabled: Boolean = false
126     }
127 
128     private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
129         var lastEvent: MotionEvent? = null
130         var lastInterceptEvent: MotionEvent? = null
131 
132         override fun onInterceptTouchEvent(event: MotionEvent?) {
133             lastInterceptEvent = event
134         }
135         override fun handleTouchEvent(event: MotionEvent?): Boolean {
136             lastEvent = event
137             return false
138         }
139     }
140 }
141