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