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