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.keyguard
18 
19 import android.testing.AndroidTestingRunner
20 import android.view.View
21 import android.view.ViewGroup
22 import androidx.test.filters.SmallTest
23 import com.android.keyguard.KeyguardUnfoldTransition.Companion.LEFT
24 import com.android.keyguard.KeyguardUnfoldTransition.Companion.RIGHT
25 import com.android.systemui.R
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
28 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
29 import com.android.systemui.util.mockito.capture
30 import org.junit.Assert.assertEquals
31 import org.junit.Before
32 import org.junit.Test
33 import org.junit.runner.RunWith
34 import org.mockito.ArgumentCaptor
35 import org.mockito.Captor
36 import org.mockito.Mock
37 import org.mockito.MockitoAnnotations
38 import org.mockito.Mockito.`when`
39 import org.mockito.Mockito.verify
40 
41 /**
42  * Translates items away/towards the hinge when the device is opened/closed. This is controlled by
43  * the set of ids, which also dictact which direction to move and when, via a filter fn.
44  */
45 @SmallTest
46 @RunWith(AndroidTestingRunner::class)
47 class KeyguardUnfoldTransitionTest : SysuiTestCase() {
48 
49     @Mock
50     private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
51 
52     @Captor
53     private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
54 
55     @Mock
56     private lateinit var parent: ViewGroup
57 
58     private lateinit var keyguardUnfoldTransition: KeyguardUnfoldTransition
59     private lateinit var progressListener: TransitionProgressListener
60     private var xTranslationMax = 0f
61 
62     @Before
63     fun setup() {
64         MockitoAnnotations.initMocks(this)
65 
66         xTranslationMax = context.resources.getDimensionPixelSize(
67             R.dimen.keyguard_unfold_translation_x).toFloat()
68 
69         keyguardUnfoldTransition = KeyguardUnfoldTransition(
70             getContext(),
71             progressProvider
72         )
73 
74         verify(progressProvider).addCallback(capture(progressListenerCaptor))
75         progressListener = progressListenerCaptor.value
76 
77         keyguardUnfoldTransition.setup(parent)
78         keyguardUnfoldTransition.statusViewCentered = false
79     }
80 
81     @Test
82     fun onTransition_noMatchingIds() {
83         // GIVEN no views matching any ids
84         // WHEN the transition starts
85         progressListener.onTransitionStarted()
86         progressListener.onTransitionProgress(.1f)
87 
88         // THEN nothing... no exceptions
89     }
90 
91     @Test
92     fun onTransition_oneMovesLeft() {
93         // GIVEN one view with a matching id
94         val view = View(getContext())
95         `when`(parent.findViewById<View>(R.id.keyguard_status_area)).thenReturn(view)
96 
97         moveAndValidate(listOf(view to LEFT))
98     }
99 
100     @Test
101     fun onTransition_oneMovesLeftAndOneMovesRightMultipleTimes() {
102         // GIVEN two views with a matching id
103         val leftView = View(getContext())
104         val rightView = View(getContext())
105         `when`(parent.findViewById<View>(R.id.keyguard_status_area)).thenReturn(leftView)
106         `when`(parent.findViewById<View>(R.id.notification_stack_scroller)).thenReturn(rightView)
107 
108         moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
109         moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
110     }
111 
112     @Test
113     fun onTransition_centeredViewDoesNotMove() {
114         keyguardUnfoldTransition.statusViewCentered = true
115 
116         val view = View(getContext())
117         `when`(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
118 
119         moveAndValidate(listOf(view to 0))
120     }
121 
122     private fun moveAndValidate(list: List<Pair<View, Int>>) {
123         // Compare values as ints because -0f != 0f
124 
125         // WHEN the transition starts
126         progressListener.onTransitionStarted()
127         progressListener.onTransitionProgress(0f)
128 
129         list.forEach { (view, direction) ->
130             assertEquals((-xTranslationMax * direction).toInt(), view.getTranslationX().toInt())
131         }
132 
133         // WHEN the transition progresses, translation is updated
134         progressListener.onTransitionProgress(.5f)
135         list.forEach { (view, direction) ->
136             assertEquals(
137                 (-xTranslationMax / 2f * direction).toInt(),
138                 view.getTranslationX().toInt()
139             )
140         }
141 
142         // WHEN the transition ends, translation is completed
143         progressListener.onTransitionProgress(1f)
144         progressListener.onTransitionFinished()
145         list.forEach { (view, _) ->
146             assertEquals(0, view.getTranslationX().toInt())
147         }
148     }
149 }
150