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