1 /* 2 * Copyright (C) 2023 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.internal.accessibility.dialog; 18 19 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; 20 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import android.accessibilityservice.AccessibilityServiceInfo; 25 import android.app.AlertDialog; 26 import android.content.Context; 27 import android.os.RemoteException; 28 import android.platform.test.flag.junit.CheckFlagsRule; 29 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 30 import android.testing.AndroidTestingRunner; 31 import android.testing.TestableLooper; 32 import android.view.InputDevice; 33 import android.view.MotionEvent; 34 import android.view.View; 35 import android.view.Window; 36 import android.widget.TextView; 37 38 import androidx.test.platform.app.InstrumentationRegistry; 39 40 import com.android.internal.R; 41 import com.android.internal.accessibility.TestUtils; 42 43 import com.google.common.truth.Expect; 44 45 import org.junit.Before; 46 import org.junit.Rule; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.MockitoAnnotations; 50 51 import java.util.concurrent.atomic.AtomicBoolean; 52 53 /** 54 * Unit Tests for 55 * {@link com.android.internal.accessibility.dialog.AccessibilityServiceWarning} 56 */ 57 @RunWith(AndroidTestingRunner.class) 58 @TestableLooper.RunWithLooper 59 public class AccessibilityServiceWarningTest { 60 private static final String A11Y_SERVICE_PACKAGE_LABEL = "TestA11yService"; 61 private static final String A11Y_SERVICE_SUMMARY = "TestA11yService summary"; 62 private static final String A11Y_SERVICE_COMPONENT_NAME = 63 "fake.package/test.a11yservice.name"; 64 65 private Context mContext; 66 private AccessibilityServiceInfo mAccessibilityServiceInfo; 67 private AtomicBoolean mAllowListener; 68 private AtomicBoolean mDenyListener; 69 private AtomicBoolean mUninstallListener; 70 71 @Rule 72 public final Expect expect = Expect.create(); 73 74 @Rule 75 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 76 77 @Before setUp()78 public void setUp() throws RemoteException { 79 MockitoAnnotations.initMocks(this); 80 mContext = InstrumentationRegistry.getInstrumentation().getContext(); 81 mAccessibilityServiceInfo = TestUtils.createFakeServiceInfo( 82 A11Y_SERVICE_PACKAGE_LABEL, 83 A11Y_SERVICE_SUMMARY, 84 A11Y_SERVICE_COMPONENT_NAME, 85 /* isAlwaysOnService*/ false); 86 mAllowListener = new AtomicBoolean(false); 87 mDenyListener = new AtomicBoolean(false); 88 mUninstallListener = new AtomicBoolean(false); 89 } 90 91 @Test createAccessibilityServiceWarningDialog_hasExpectedWindowParams()92 public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams() { 93 final AlertDialog dialog = 94 AccessibilityServiceWarning.createAccessibilityServiceWarningDialog( 95 mContext, 96 mAccessibilityServiceInfo, 97 null, null, null); 98 final Window dialogWindow = dialog.getWindow(); 99 assertThat(dialogWindow).isNotNull(); 100 101 expect.that(dialogWindow.getAttributes().privateFlags 102 & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo( 103 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 104 expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG); 105 } 106 107 @Test createAccessibilityServiceWarningDialog_hasExpectedServiceName()108 public void createAccessibilityServiceWarningDialog_hasExpectedServiceName() { 109 final TextView title = createDialogContentView().findViewById( 110 R.id.accessibility_permissionDialog_title); 111 assertThat(title).isNotNull(); 112 113 assertThat(title.getText().toString()).contains(A11Y_SERVICE_PACKAGE_LABEL); 114 } 115 116 @Test createAccessibilityServiceWarningDialog_clickAllow()117 public void createAccessibilityServiceWarningDialog_clickAllow() { 118 final View allowButton = createDialogContentView().findViewById( 119 R.id.accessibility_permission_enable_allow_button); 120 assertThat(allowButton).isNotNull(); 121 122 allowButton.performClick(); 123 124 expect.that(mAllowListener.get()).isTrue(); 125 expect.that(mDenyListener.get()).isFalse(); 126 expect.that(mUninstallListener.get()).isFalse(); 127 } 128 129 @Test createAccessibilityServiceWarningDialog_clickDeny()130 public void createAccessibilityServiceWarningDialog_clickDeny() { 131 final View denyButton = createDialogContentView().findViewById( 132 R.id.accessibility_permission_enable_deny_button); 133 assertThat(denyButton).isNotNull(); 134 135 denyButton.performClick(); 136 137 expect.that(mAllowListener.get()).isFalse(); 138 expect.that(mDenyListener.get()).isTrue(); 139 expect.that(mUninstallListener.get()).isFalse(); 140 } 141 142 @Test createAccessibilityServiceWarningDialog_clickUninstall()143 public void createAccessibilityServiceWarningDialog_clickUninstall() { 144 final View uninstallButton = createDialogContentView().findViewById( 145 R.id.accessibility_permission_enable_uninstall_button); 146 assertThat(uninstallButton).isNotNull(); 147 148 uninstallButton.performClick(); 149 150 expect.that(mAllowListener.get()).isFalse(); 151 expect.that(mDenyListener.get()).isFalse(); 152 expect.that(mUninstallListener.get()).isTrue(); 153 } 154 155 @Test getTouchConsumingListener()156 public void getTouchConsumingListener() { 157 final View allowButton = createDialogContentView().findViewById( 158 R.id.accessibility_permission_enable_allow_button); 159 assertThat(allowButton).isNotNull(); 160 final View.OnTouchListener listener = 161 AccessibilityServiceWarning.getTouchConsumingListener(); 162 163 expect.that(listener.onTouch(allowButton, createMotionEvent(0))).isFalse(); 164 expect.that(listener.onTouch(allowButton, 165 createMotionEvent(MotionEvent.FLAG_WINDOW_IS_OBSCURED))).isTrue(); 166 expect.that(listener.onTouch(allowButton, 167 createMotionEvent(MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED))).isTrue(); 168 } 169 createDialogContentView()170 private View createDialogContentView() { 171 return AccessibilityServiceWarning.createAccessibilityServiceWarningDialogContentView( 172 mContext, 173 mAccessibilityServiceInfo, 174 (v) -> mAllowListener.set(true), 175 (v) -> mDenyListener.set(true), 176 (v) -> mUninstallListener.set(true)); 177 } 178 createMotionEvent(int flags)179 private MotionEvent createMotionEvent(int flags) { 180 MotionEvent.PointerProperties[] props = new MotionEvent.PointerProperties[]{ 181 new MotionEvent.PointerProperties() 182 }; 183 MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[]{ 184 new MotionEvent.PointerCoords() 185 }; 186 return MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1, props, coords, 187 0, 0, 0, 0, -1, 0, InputDevice.SOURCE_TOUCHSCREEN, flags); 188 } 189 } 190