1 /*
2  * Copyright (C) 2020 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 static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.AdditionalAnswers.answerVoid;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyLong;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Mockito.doAnswer;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31 
32 import android.app.admin.IKeyguardCallback;
33 import android.app.admin.IKeyguardClient;
34 import android.content.ComponentName;
35 import android.content.Intent;
36 import android.hardware.display.DisplayManager;
37 import android.os.Binder;
38 import android.os.Handler;
39 import android.os.RemoteException;
40 import android.testing.AndroidTestingRunner;
41 import android.testing.TestableLooper;
42 import android.testing.TestableLooper.RunWithLooper;
43 import android.testing.ViewUtils;
44 import android.view.Display;
45 import android.view.SurfaceControlViewHost;
46 import android.view.SurfaceView;
47 import android.view.View;
48 
49 import androidx.test.filters.SmallTest;
50 
51 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
52 import com.android.systemui.SysuiTestCase;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.ArgumentCaptor;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 
62 @RunWithLooper
63 @RunWith(AndroidTestingRunner.class)
64 @SmallTest
65 public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
66 
67     private static final int TARGET_USER_ID = KeyguardUpdateMonitor.getCurrentUser();
68 
69     private AdminSecondaryLockScreenController mTestController;
70     private ComponentName mComponentName;
71     private Intent mServiceIntent;
72     private TestableLooper mTestableLooper;
73     private KeyguardSecurityContainer mKeyguardSecurityContainer;
74 
75     @Mock
76     private Handler mHandler;
77     @Mock
78     private IKeyguardClient.Stub mKeyguardClient;
79     @Mock
80     private KeyguardSecurityCallback mKeyguardCallback;
81     @Mock
82     private KeyguardUpdateMonitor mUpdateMonitor;
83 
84     private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
85 
86     @Before
setUp()87     public void setUp() {
88         MockitoAnnotations.initMocks(this);
89 
90         mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
91         mKeyguardSecurityContainer.setId(View.generateViewId());
92         ViewUtils.attachView(mKeyguardSecurityContainer);
93 
94         mTestableLooper = TestableLooper.get(this);
95         mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class");
96         mServiceIntent = new Intent().setComponent(mComponentName);
97 
98         mContext.addMockService(mComponentName, mKeyguardClient);
99         // Have Stub.asInterface return the mocked interface.
100         when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
101         when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
102 
103         Display display = mContext.getSystemService(DisplayManager.class).getDisplay(
104                 Display.DEFAULT_DISPLAY);
105         mSurfacePackage = (new SurfaceControlViewHost(mContext, display,
106                 new Binder())).getSurfacePackage();
107 
108         mTestController = new AdminSecondaryLockScreenController.Factory(
109                 mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler)
110                 .create(mKeyguardCallback);
111     }
112 
113     @After
tearDown()114     public void tearDown() {
115         ViewUtils.detachView(mKeyguardSecurityContainer);
116     }
117 
118     @Test
testShow()119     public void testShow() throws Exception {
120         doAnswer(invocation -> {
121             IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
122             callback.onRemoteContentReady(mSurfacePackage);
123             return null;
124         }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
125 
126         mTestController.show(mServiceIntent);
127 
128         verifySurfaceReady();
129         assertThat(mContext.isBound(mComponentName)).isTrue();
130     }
131 
132     @Test
testShow_dismissedByCallback()133     public void testShow_dismissedByCallback() throws Exception {
134         doAnswer(answerVoid(Runnable::run)).when(mHandler).post(any(Runnable.class));
135         doAnswer(invocation -> {
136             IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
137             callback.onDismiss();
138             return null;
139         }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
140 
141         mTestController.show(mServiceIntent);
142 
143         verifyViewDismissed(verifySurfaceReady());
144     }
145 
146     @Test
testHide()147     public void testHide() throws Exception {
148         // Show the view first, then hide.
149         doAnswer(invocation -> {
150             IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
151             callback.onRemoteContentReady(mSurfacePackage);
152             return null;
153         }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
154 
155         mTestController.show(mServiceIntent);
156         SurfaceView v = verifySurfaceReady();
157 
158         mTestController.hide();
159         verify(mKeyguardSecurityContainer).removeView(v);
160         assertThat(mContext.isBound(mComponentName)).isFalse();
161     }
162 
163     @Test
testHide_notShown()164     public void testHide_notShown() throws Exception {
165         mTestController.hide();
166         // Nothing should happen if trying to hide when the view isn't attached yet.
167         verify(mKeyguardSecurityContainer, never()).removeView(any(SurfaceView.class));
168     }
169 
170     @Test
testDismissed_onCreateKeyguardSurface_RemoteException()171     public void testDismissed_onCreateKeyguardSurface_RemoteException() throws Exception {
172         doThrow(new RemoteException()).when(mKeyguardClient)
173                 .onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
174 
175         mTestController.show(mServiceIntent);
176 
177         verifyViewDismissed(verifySurfaceReady());
178     }
179 
180     @Test
testDismissed_onCreateKeyguardSurface_timeout()181     public void testDismissed_onCreateKeyguardSurface_timeout() throws Exception {
182         // Mocked KeyguardClient never handles the onCreateKeyguardSurface, so the operation
183         // times out, resulting in the view being dismissed.
184         doAnswer(answerVoid(Runnable::run)).when(mHandler)
185                 .postDelayed(any(Runnable.class), anyLong());
186 
187         mTestController.show(mServiceIntent);
188 
189         verifyViewDismissed(verifySurfaceReady());
190     }
191 
verifySurfaceReady()192     private SurfaceView verifySurfaceReady() throws Exception {
193         mTestableLooper.processAllMessages();
194         ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class);
195         verify(mKeyguardSecurityContainer).addView(captor.capture());
196 
197         mTestableLooper.processAllMessages();
198         verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
199         return captor.getValue();
200     }
201 
verifyViewDismissed(SurfaceView v)202     private void verifyViewDismissed(SurfaceView v) throws Exception {
203         verify(mKeyguardSecurityContainer).removeView(v);
204         verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true, SecurityMode.Invalid);
205         assertThat(mContext.isBound(mComponentName)).isFalse();
206     }
207 }
208