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