summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hongming Jin <hongmingjin@google.com> 2020-01-17 19:09:11 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-01-17 19:09:11 +0000
commit60d32dbf5d9b34aeb693b575ea03cadb0b6338dd (patch)
tree95d7a4d4f6024e8842b0032ffb89cb17849b22cd
parent85f8385f42d8ab44f6f873fcc235188077d95178 (diff)
parent8302c6cd858a185868ac14d279e0d6ac4213f564 (diff)
Merge "API on AccessibilityService side to support customized system actions."
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java101
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl2
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl3
-rw-r--r--core/java/android/app/UiAutomation.java5
-rw-r--r--core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java104
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java34
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java66
11 files changed, 325 insertions, 31 deletions
diff --git a/api/current.txt b/api/current.txt
index 0b35d64651ab..0d233713d8f6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2854,6 +2854,7 @@ package android.accessibilityservice {
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method @NonNull public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
+ method @NonNull public final java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getSystemActions();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method @NonNull public final android.util.SparseArray<java.util.List<android.view.accessibility.AccessibilityWindowInfo>> getWindowsOnAllDisplays();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
@@ -2863,6 +2864,7 @@ package android.accessibilityservice {
method public abstract void onInterrupt();
method protected boolean onKeyEvent(android.view.KeyEvent);
method protected void onServiceConnected();
+ method public void onSystemActionsChanged();
method public final boolean performGlobalAction(int);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 0bd8ce692884..ee6ccc2f5cd7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -48,6 +48,7 @@ import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.os.HandlerCaller;
@@ -56,6 +57,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -392,7 +394,8 @@ public abstract class AccessibilityService extends Service {
private static final String LOG_TAG = "AccessibilityService";
/**
- * Interface used by IAccessibilityServiceWrapper to call the service from its main thread.
+ * Interface used by IAccessibilityServiceClientWrapper to call the service from its main
+ * thread.
* @hide
*/
public interface Callbacks {
@@ -413,6 +416,8 @@ public abstract class AccessibilityService extends Service {
/** Accessbility button clicked callbacks for different displays */
void onAccessibilityButtonClicked(int displayId);
void onAccessibilityButtonAvailabilityChanged(boolean available);
+ /** This is called when the system action list is changed. */
+ void onSystemActionsChanged();
}
/**
@@ -1643,6 +1648,29 @@ public abstract class AccessibilityService extends Service {
available);
}
+ /** This is called when the system action list is changed. */
+ public void onSystemActionsChanged() {
+ }
+
+ /**
+ * Returns a list of system actions available in the system right now.
+ *
+ * @return A list of available system actions.
+ */
+ public final @NonNull List<AccessibilityAction> getSystemActions() {
+ IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+ if (connection != null) {
+ try {
+ return connection.getSystemActions();
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while calling getSystemActions", re);
+ re.rethrowFromSystemServer();
+ }
+ }
+ return Collections.emptyList();
+ }
+
/**
* Performs a global action. Such an action can be performed
* at any moment regardless of the current application or user
@@ -1894,6 +1922,11 @@ public abstract class AccessibilityService extends Service {
public void onAccessibilityButtonAvailabilityChanged(boolean available) {
AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
}
+
+ @Override
+ public void onSystemActionsChanged() {
+ AccessibilityService.this.onSystemActionsChanged();
+ }
});
}
@@ -1918,6 +1951,7 @@ public abstract class AccessibilityService extends Service {
private static final int DO_ON_FINGERPRINT_GESTURE = 11;
private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
+ private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14;
private final HandlerCaller mCaller;
@@ -2014,6 +2048,11 @@ public abstract class AccessibilityService extends Service {
mCaller.sendMessage(message);
}
+ /** This is called when the system action list is changed. */
+ public void onSystemActionsChanged() {
+ mCaller.sendMessage(mCaller.obtainMessage(DO_ON_SYSTEM_ACTIONS_CHANGED));
+ }
+
@Override
public void executeMessage(Message message) {
switch (message.what) {
@@ -2035,14 +2074,14 @@ public abstract class AccessibilityService extends Service {
/* ignore - best effort */
}
}
- } return;
-
+ return;
+ }
case DO_ON_INTERRUPT: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
mCallback.onInterrupt();
}
- } return;
-
+ return;
+ }
case DO_INIT: {
mConnectionId = message.arg1;
SomeArgs args = (SomeArgs) message.obj;
@@ -2062,18 +2101,18 @@ public abstract class AccessibilityService extends Service {
AccessibilityInteractionClient.getInstance().clearCache();
mCallback.init(AccessibilityInteractionClient.NO_ID, null);
}
- } return;
-
+ return;
+ }
case DO_ON_GESTURE: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
mCallback.onGesture((AccessibilityGestureEvent) message.obj);
}
- } return;
-
+ return;
+ }
case DO_CLEAR_ACCESSIBILITY_CACHE: {
AccessibilityInteractionClient.getInstance().clearCache();
- } return;
-
+ return;
+ }
case DO_ON_KEY_EVENT: {
KeyEvent event = (KeyEvent) message.obj;
try {
@@ -2096,8 +2135,8 @@ public abstract class AccessibilityService extends Service {
/* ignore - best effort */
}
}
- } return;
-
+ return;
+ }
case DO_ON_MAGNIFICATION_CHANGED: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
final SomeArgs args = (SomeArgs) message.obj;
@@ -2110,45 +2149,53 @@ public abstract class AccessibilityService extends Service {
mCallback.onMagnificationChanged(displayId, region, scale,
centerX, centerY);
}
- } return;
-
+ return;
+ }
case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
final int showMode = (int) message.arg1;
mCallback.onSoftKeyboardShowModeChanged(showMode);
}
- } return;
-
+ return;
+ }
case DO_GESTURE_COMPLETE: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
final boolean successfully = message.arg2 == 1;
mCallback.onPerformGestureResult(message.arg1, successfully);
}
- } return;
+ return;
+ }
case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
}
- } return;
+ return;
+ }
case DO_ON_FINGERPRINT_GESTURE: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
mCallback.onFingerprintGesture(message.arg1);
}
- } return;
-
- case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
+ return;
+ }
+ case DO_ACCESSIBILITY_BUTTON_CLICKED: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
mCallback.onAccessibilityButtonClicked(message.arg1);
}
- } return;
-
- case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
+ return;
+ }
+ case DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
final boolean available = (message.arg1 != 0);
mCallback.onAccessibilityButtonAvailabilityChanged(available);
}
- } return;
-
+ return;
+ }
+ case DO_ON_SYSTEM_ACTIONS_CHANGED: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ mCallback.onSystemActionsChanged();
+ }
+ return;
+ }
default :
Log.w(LOG_TAG, "Unknown message type " + message.what);
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 8ec3aea2728f..58b0d19f605a 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -55,4 +55,6 @@ import android.view.KeyEvent;
void onAccessibilityButtonClicked(int displayId);
void onAccessibilityButtonAvailabilityChanged(boolean available);
+
+ void onSystemActionsChanged();
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 4ea5c62bf05b..5db4dd7470d8 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -25,8 +25,10 @@ import android.os.RemoteCallback;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.accessibility.AccessibilityWindowInfo;
+import java.util.List;
/**
* Interface given to an AccessibilitySerivce to talk to the AccessibilityManagerService.
@@ -67,6 +69,7 @@ interface IAccessibilityServiceConnection {
AccessibilityServiceInfo getServiceInfo();
boolean performGlobalAction(int action);
+ List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions();
void disableSelf();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 2579bd1abbfd..35cf68737ccc 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1254,6 +1254,11 @@ public final class UiAutomation {
}
@Override
+ public void onSystemActionsChanged() {
+ /* do nothing */
+ }
+
+ @Override
public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
/* do nothing */
return false;
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java
new file mode 100644
index 000000000000..c65ef9a56cd8
--- /dev/null
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.accessibility.AccessibilityEvent;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for AccessibilityService.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityServiceTest {
+ private static final String TAG = "AccessibilityServiceTest";
+ private static final int CONNECTION_ID = 1;
+
+ private static class AccessibilityServiceTestClass extends AccessibilityService {
+ private IAccessibilityServiceClient mCallback;
+ private Looper mLooper;
+
+ AccessibilityServiceTestClass() {
+ super();
+ attachBaseContext(InstrumentationRegistry.getContext());
+ mLooper = InstrumentationRegistry.getContext().getMainLooper();
+ }
+
+ public void setupCallback(IAccessibilityServiceClient callback) {
+ mCallback = callback;
+ }
+
+ public Looper getMainLooper() {
+ return mLooper;
+ }
+
+ public void onAccessibilityEvent(AccessibilityEvent event) { }
+ public void onInterrupt() { }
+
+ @Override
+ public void onSystemActionsChanged() {
+ try {
+ if (mCallback != null) mCallback.onSystemActionsChanged();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private @Mock IAccessibilityServiceClient mMockClientForCallback;
+ private @Mock IAccessibilityServiceConnection mMockConnection;
+ private @Mock IBinder mMockIBinder;
+ private IAccessibilityServiceClient mServiceInterface;
+ private AccessibilityServiceTestClass mService;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+ mService = new AccessibilityServiceTestClass();
+ mService.setupCallback(mMockClientForCallback);
+ mServiceInterface = (IAccessibilityServiceClient) mService.onBind(new Intent());
+ mServiceInterface.init(mMockConnection, CONNECTION_ID, mMockIBinder);
+ }
+
+ @Test
+ public void testOnSystemActionsChanged() throws RemoteException {
+ mServiceInterface.onSystemActionsChanged();
+
+ verify(mMockClientForCallback).onSystemActionsChanged();
+ }
+
+ @Test
+ public void testGetSystemActions() throws RemoteException {
+ mService.getSystemActions();
+
+ verify(mMockConnection).getSystemActions();
+ }
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index f151b810eea3..8b8e9ea4c6ee 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -25,6 +25,9 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
+import java.util.Collections;
+import java.util.List;
+
/**
* Stub implementation of IAccessibilityServiceConnection so each test doesn't need to implement
* all of the methods
@@ -85,6 +88,10 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
return false;
}
+ public List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
+ return Collections.emptyList();
+ }
+
public void disableSelf() {}
public void setOnKeyEventResult(boolean handled, int sequence) {}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index c3965c44d4c0..3e74b7a92f5d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -80,6 +80,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -775,6 +776,16 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Override
+ public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
+ synchronized (mLock) {
+ if (!hasRightsToCurrentUserLocked()) {
+ return Collections.emptyList();
+ }
+ }
+ return mSystemActionPerformer.getSystemActions();
+ }
+
+ @Override
public boolean isFingerprintGestureDetectionAvailable() {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
return false;
@@ -1252,6 +1263,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
gestureEvent).sendToTarget();
}
+ public void notifySystemActionsChangedLocked() {
+ mInvocationHandler.sendEmptyMessage(
+ InvocationHandler.MSG_ON_SYSTEM_ACTIONS_CHANGED);
+ }
+
public void notifyClearAccessibilityNodeInfoCache() {
mInvocationHandler.sendEmptyMessage(
InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
@@ -1350,6 +1366,18 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
+ private void notifySystemActionsChangedInternal() {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ listener.onSystemActionsChanged();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
+ re);
+ }
+ }
+ }
+
private void notifyClearAccessibilityCacheInternal() {
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
if (listener != null) {
@@ -1544,6 +1572,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
+ private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9;
/** List of magnification callback states, mapping from displayId -> Boolean */
@GuardedBy("mlock")
@@ -1591,7 +1620,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final boolean available = (message.arg1 != 0);
notifyAccessibilityButtonAvailabilityChangedInternal(available);
} break;
-
+ case MSG_ON_SYSTEM_ACTIONS_CHANGED: {
+ notifySystemActionsChangedInternal();
+ break;
+ }
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index f3a415ef4cb5..bcaecea4c388 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -137,7 +137,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
implements AbstractAccessibilityServiceConnection.SystemSupport,
AccessibilityUserState.ServiceInfoChangeListener,
AccessibilityWindowManager.AccessibilityEventSender,
- AccessibilitySecurityPolicy.AccessibilityUserManager {
+ AccessibilitySecurityPolicy.AccessibilityUserManager,
+ SystemActionPerformer.SystemActionsChangedListener {
private static final boolean DEBUG = false;
@@ -294,7 +295,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
mPackageManager = mContext.getPackageManager();
mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
- mSystemActionPerformer = new SystemActionPerformer(mContext, mWindowManagerService);
+ mSystemActionPerformer =
+ new SystemActionPerformer(mContext, mWindowManagerService, null, this);
mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
mWindowManagerService, this, mSecurityPolicy, this);
mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
@@ -904,6 +906,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ /**
+ * Called when the system action list is changed.
+ */
+ @Override
+ public void onSystemActionsChanged() {
+ synchronized (mLock) {
+ AccessibilityUserState state = getCurrentUserStateLocked();
+ notifySystemActionsChangedLocked(state);
+ }
+ }
+
+ @VisibleForTesting
+ void notifySystemActionsChangedLocked(AccessibilityUserState userState) {
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ service.notifySystemActionsChangedLocked();
+ }
+ }
+
@VisibleForTesting
public boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
synchronized (mLock) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index e1e9b7e7b7cb..cf10559c8198 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -495,6 +495,13 @@ public class AbstractAccessibilityServiceConnectionTest {
}
@Test
+ public void getSystemActions() {
+ List<AccessibilityNodeInfo.AccessibilityAction> actions =
+ mServiceConnection.getSystemActions();
+ verify(mMockSystemActionPerformer).getSystemActions();
+ }
+
+ @Test
public void isFingerprintGestureDetectionAvailable_hasFingerPrintSupport_returnTrue() {
when(mMockFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable())
.thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 75239db92121..ec928fb278be 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -16,16 +16,28 @@
package com.android.server.accessibility;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.Manifest;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceClient;
import android.app.PendingIntent;
import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.graphics.drawable.Icon;
+import android.os.IBinder;
+import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -34,6 +46,7 @@ import androidx.test.InstrumentationRegistry;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -59,6 +72,14 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
new AccessibilityAction(ACTION_ID, LABEL);
+ static final ComponentName COMPONENT_NAME = new ComponentName(
+ "com.android.server.accessibility", "AccessibilityManagerServiceTest");
+ static final int SERVICE_ID = 42;
+
+ @Mock private Context mMockContext;
+ @Mock private AccessibilityServiceInfo mMockServiceInfo;
+ @Mock private ResolveInfo mMockResolveInfo;
+ @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
@Mock private PackageManager mMockPackageManager;
@Mock private WindowManagerInternal mMockWindowManagerService;
@Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@@ -66,7 +87,12 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
@Mock private AccessibilityWindowManager mMockA11yWindowManager;
@Mock private AccessibilityDisplayListener mMockA11yDisplayListener;
@Mock private ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
+ @Mock private IBinder mMockBinder;
+ @Mock private IAccessibilityServiceClient mMockServiceClient;
+ private AccessibilityUserState mUserState;
+ private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+ private AccessibilityServiceConnection mAccessibilityServiceConnection;
private AccessibilityManagerService mA11yms;
@Override
@@ -74,9 +100,11 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
MockitoAnnotations.initMocks(this);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
- LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerService);
+ LocalServices.addService(
+ WindowManagerInternal.class, mMockWindowManagerService);
LocalServices.addService(
ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
+
mA11yms = new AccessibilityManagerService(
InstrumentationRegistry.getContext(),
mMockPackageManager,
@@ -86,6 +114,35 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
mMockA11yDisplayListener);
}
+ private void setupAccessibilityServiceConnection() {
+ when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(
+ InstrumentationRegistry.getContext().getSystemService(
+ Context.DISPLAY_SERVICE));
+ mUserState = new AccessibilityUserState(UserHandle.USER_SYSTEM, mMockContext, mA11yms);
+
+ when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
+ mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
+ mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
+
+ when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+ mAccessibilityServiceConnection = new AccessibilityServiceConnection(
+ mUserState,
+ mMockContext,
+ COMPONENT_NAME,
+ mMockServiceInfo,
+ SERVICE_ID,
+ mHandler,
+ new Object(),
+ mMockSecurityPolicy,
+ mMockSystemSupport,
+ mMockWindowManagerService,
+ mMockSystemActionPerformer,
+ mMockA11yWindowManager,
+ mMockActivityTaskManagerInternal);
+ mAccessibilityServiceConnection.bindLocked();
+ mAccessibilityServiceConnection.onServiceConnected(COMPONENT_NAME, mMockBinder);
+ }
+
@SmallTest
public void testRegisterSystemActionWithoutPermission() throws Exception {
doThrow(SecurityException.class).when(mMockSecurityPolicy).enforceCallingPermission(
@@ -125,4 +182,11 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
mA11yms.unregisterSystemAction(ACTION_ID);
verify(mMockSystemActionPerformer).unregisterSystemAction(ACTION_ID);
}
+
+ @SmallTest
+ public void testOnSystemActionsChanged() throws Exception {
+ setupAccessibilityServiceConnection();
+ mA11yms.notifySystemActionsChangedLocked(mUserState);
+ verify(mMockServiceClient).onSystemActionsChanged();
+ }
}