Merge "Dont dispatch a11y events that have no subscribers"
This commit is contained in:
committed by
Android (Google) Code Review
commit
67916b86e9
@@ -18,6 +18,8 @@ package android.os;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Takes care of the grunt work of maintaining a list of remote interfaces,
|
||||
* typically for the use of performing callbacks from a
|
||||
@@ -307,6 +309,23 @@ public class RemoteCallbackList<E extends IInterface> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@code action} on each callback, calling
|
||||
* {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void broadcast(Consumer<E> action) {
|
||||
int itemCount = beginBroadcast();
|
||||
try {
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
action.accept(getBroadcastItem(i));
|
||||
}
|
||||
} finally {
|
||||
finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of registered callbacks. Note that the number of registered
|
||||
* callbacks may differ from the value returned by {@link #beginBroadcast()} since
|
||||
|
||||
@@ -40,6 +40,8 @@ import android.util.Log;
|
||||
import android.view.IWindow;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.util.IntPair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -109,6 +111,8 @@ public final class AccessibilityManager {
|
||||
|
||||
boolean mIsEnabled;
|
||||
|
||||
int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
|
||||
|
||||
boolean mIsTouchExplorationEnabled;
|
||||
|
||||
boolean mIsHighTextContrastEnabled;
|
||||
@@ -203,6 +207,11 @@ public final class AccessibilityManager {
|
||||
public void notifyServicesStateChanged() {
|
||||
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_SERVICES_STATE_CHANGED).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRelevantEventTypes(int eventTypes) {
|
||||
mRelevantEventTypes = eventTypes;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -362,6 +371,14 @@ public final class AccessibilityManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((event.getEventType() & mRelevantEventTypes) == 0) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Not dispatching irrelevant event: " + event
|
||||
+ " that is not among "
|
||||
+ AccessibilityEvent.eventTypeToString(mRelevantEventTypes));
|
||||
}
|
||||
return;
|
||||
}
|
||||
userId = mUserId;
|
||||
}
|
||||
try {
|
||||
@@ -865,8 +882,9 @@ public final class AccessibilityManager {
|
||||
}
|
||||
|
||||
try {
|
||||
final int stateFlags = service.addClient(mClient, mUserId);
|
||||
setStateLocked(stateFlags);
|
||||
final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
|
||||
setStateLocked(IntPair.first(userStateAndRelevantEvents));
|
||||
mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
|
||||
mService = service;
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
|
||||
|
||||
@@ -38,7 +38,7 @@ interface IAccessibilityManager {
|
||||
|
||||
oneway void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
|
||||
|
||||
int addClient(IAccessibilityManagerClient client, int userId);
|
||||
long addClient(IAccessibilityManagerClient client, int userId);
|
||||
|
||||
List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
|
||||
|
||||
|
||||
@@ -25,5 +25,8 @@ package android.view.accessibility;
|
||||
oneway interface IAccessibilityManagerClient {
|
||||
|
||||
void setState(int stateFlags);
|
||||
|
||||
void notifyServicesStateChanged();
|
||||
|
||||
void setRelevantEventTypes(int eventTypes);
|
||||
}
|
||||
|
||||
38
core/java/com/android/internal/util/IntPair.java
Normal file
38
core/java/com/android/internal/util/IntPair.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 com.android.internal.util;
|
||||
|
||||
/**
|
||||
* Utilities for treating a {@code long} as a pair of {@code int}s
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class IntPair {
|
||||
private IntPair() {}
|
||||
|
||||
public static long of(int first, int second) {
|
||||
return (((long)first) << 32) | ((long)second & 0xffffffffL);
|
||||
}
|
||||
|
||||
public static int first(long intPair) {
|
||||
return (int)(intPair >> 32);
|
||||
}
|
||||
|
||||
public static int second(long intPair) {
|
||||
return (int)intPair;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.fingerprint.IFingerprintService;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
@@ -69,7 +70,6 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.UserManagerInternal;
|
||||
import android.provider.Settings;
|
||||
import android.hardware.fingerprint.IFingerprintService;
|
||||
import android.provider.SettingsStringUtil.ComponentNameSet;
|
||||
import android.provider.SettingsStringUtil.SettingStringHelper;
|
||||
import android.text.TextUtils;
|
||||
@@ -100,7 +100,9 @@ import android.view.accessibility.IAccessibilityManagerClient;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.os.HandlerCaller;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.util.IntPair;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.policy.AccessibilityShortcutController;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
@@ -120,6 +122,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class is instantiated by the system as a system level service and can be
|
||||
@@ -434,7 +437,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addClient(IAccessibilityManagerClient client, int userId) {
|
||||
public long addClient(IAccessibilityManagerClient client, int userId) {
|
||||
synchronized (mLock) {
|
||||
// We treat calls from a profile as if made by its parent as profiles
|
||||
// share the accessibility state of the parent. The call below
|
||||
@@ -450,7 +453,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
|
||||
}
|
||||
return userState.getClientState();
|
||||
return IntPair.of(
|
||||
userState.getClientState(), userState.mLastSentRelevantEventTypes);
|
||||
} else {
|
||||
userState.mUserClients.register(client);
|
||||
// If this client is not for the current user we do not
|
||||
@@ -460,7 +464,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
|
||||
+ " and userId:" + mCurrentUserId);
|
||||
}
|
||||
return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
|
||||
return IntPair.of(
|
||||
(resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0,
|
||||
userState.mLastSentRelevantEventTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1323,6 +1329,35 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
scheduleNotifyClientsOfServicesStateChange(userState);
|
||||
}
|
||||
|
||||
private void updateRelevantEventsLocked(UserState userState) {
|
||||
int relevantEventTypes = AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK;
|
||||
for (Service service : userState.mBoundServices) {
|
||||
relevantEventTypes |= service.mEventTypes;
|
||||
}
|
||||
int finalRelevantEventTypes = relevantEventTypes;
|
||||
|
||||
if (userState.mLastSentRelevantEventTypes != finalRelevantEventTypes) {
|
||||
userState.mLastSentRelevantEventTypes = finalRelevantEventTypes;
|
||||
mMainHandler.obtainMessage(MainHandler.MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS,
|
||||
userState.mUserId, finalRelevantEventTypes);
|
||||
mMainHandler.post(() -> {
|
||||
broadcastToClients(userState, (client) -> {
|
||||
try {
|
||||
client.setRelevantEventTypes(finalRelevantEventTypes);
|
||||
} catch (RemoteException re) {
|
||||
/* ignore */
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastToClients(
|
||||
UserState userState, Consumer<IAccessibilityManagerClient> clientAction) {
|
||||
mGlobalClients.broadcast(clientAction);
|
||||
userState.mUserClients.broadcast(clientAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if given event can be dispatched to a service based on the package of the
|
||||
* event source. Specifically, a service is notified if it is interested in events from the
|
||||
@@ -1633,6 +1668,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
scheduleUpdateFingerprintGestureHandling(userState);
|
||||
scheduleUpdateInputFilter(userState);
|
||||
scheduleUpdateClientsIfNeededLocked(userState);
|
||||
updateRelevantEventsLocked(userState);
|
||||
}
|
||||
|
||||
private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
|
||||
@@ -2281,6 +2317,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
|
||||
public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
|
||||
public static final int MSG_UPDATE_FINGERPRINT = 11;
|
||||
public static final int MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS = 12;
|
||||
|
||||
public MainHandler(Looper looper) {
|
||||
super(looper);
|
||||
@@ -2351,6 +2388,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
case MSG_UPDATE_FINGERPRINT: {
|
||||
updateFingerprintGestureHandling((UserState) msg.obj);
|
||||
} break;
|
||||
|
||||
case MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS: {
|
||||
final int userId = msg.arg1;
|
||||
final int relevantEventTypes = msg.arg2;
|
||||
final UserState userState;
|
||||
synchronized (mLock) {
|
||||
userState = getUserStateLocked(userId);
|
||||
}
|
||||
broadcastToClients(userState, (client) -> {
|
||||
try {
|
||||
client.setRelevantEventTypes(relevantEventTypes);
|
||||
} catch (RemoteException re) {
|
||||
/* ignore */
|
||||
}
|
||||
});
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2380,19 +2433,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
|
||||
private void sendStateToClients(int clientState,
|
||||
RemoteCallbackList<IAccessibilityManagerClient> clients) {
|
||||
try {
|
||||
final int userClientCount = clients.beginBroadcast();
|
||||
for (int i = 0; i < userClientCount; i++) {
|
||||
IAccessibilityManagerClient client = clients.getBroadcastItem(i);
|
||||
try {
|
||||
client.setState(clientState);
|
||||
} catch (RemoteException re) {
|
||||
/* ignore */
|
||||
}
|
||||
clients.broadcast((client) -> {
|
||||
try {
|
||||
client.setState(clientState);
|
||||
} catch (RemoteException re) {
|
||||
/* ignore */
|
||||
}
|
||||
} finally {
|
||||
clients.finishBroadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void notifyClientsOfServicesStateChange(
|
||||
@@ -4710,6 +4757,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
public final CopyOnWriteArrayList<Service> mBoundServices =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
public int mLastSentRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
|
||||
|
||||
public final Map<ComponentName, Service> mComponentNameToServiceMap =
|
||||
new HashMap<>();
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.IAccessibilityManager;
|
||||
import android.view.accessibility.IAccessibilityManagerClient;
|
||||
|
||||
import com.android.internal.util.IntPair;
|
||||
|
||||
/**
|
||||
* This test exercises the
|
||||
* {@link com.android.server.accessibility.AccessibilityManagerService} by mocking the
|
||||
@@ -109,7 +111,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
|
||||
|
||||
// invoke the method under test
|
||||
final int stateFlagsDisabled =
|
||||
mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
|
||||
IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
|
||||
boolean enabledAccessibilityDisabled =
|
||||
(stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
|
||||
|
||||
@@ -122,7 +124,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
|
||||
|
||||
// invoke the method under test
|
||||
final int stateFlagsEnabled =
|
||||
mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
|
||||
IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
|
||||
boolean enabledAccessibilityEnabled =
|
||||
(stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
|
||||
|
||||
@@ -144,7 +146,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
|
||||
|
||||
// invoke the method under test
|
||||
final int stateFlagsEnabled =
|
||||
mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
|
||||
IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
|
||||
boolean enabledAccessibilityEnabled =
|
||||
(stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
|
||||
|
||||
@@ -157,7 +159,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
|
||||
|
||||
// invoke the method under test
|
||||
final int stateFlagsDisabled =
|
||||
mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
|
||||
IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
|
||||
boolean enabledAccessibilityDisabled =
|
||||
(stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
|
||||
|
||||
@@ -572,8 +574,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
|
||||
|
||||
public void notifyServicesStateChanged() {}
|
||||
|
||||
public void setTouchExplorationEnabled(boolean enabled) {
|
||||
}
|
||||
public void setRelevantEventTypes(int eventTypes) {}
|
||||
|
||||
public void setTouchExplorationEnabled(boolean enabled) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.server;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -32,6 +31,8 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.IAccessibilityManager;
|
||||
import android.view.accessibility.IAccessibilityManagerClient;
|
||||
|
||||
import com.android.internal.util.IntPair;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -60,10 +61,12 @@ public class AccessibilityManagerTest extends AndroidTestCase {
|
||||
private AccessibilityManager createManager(boolean enabled) throws Exception {
|
||||
if (enabled) {
|
||||
when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
|
||||
.thenReturn(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
|
||||
.thenReturn(
|
||||
IntPair.of(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
|
||||
AccessibilityEvent.TYPES_ALL_MASK));
|
||||
} else {
|
||||
when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
|
||||
.thenReturn(0);
|
||||
.thenReturn(IntPair.of(0, AccessibilityEvent.TYPES_ALL_MASK));
|
||||
}
|
||||
|
||||
AccessibilityManager manager =
|
||||
|
||||
@@ -95,6 +95,9 @@ public final class AccessibilityManager {
|
||||
|
||||
public void notifyServicesStateChanged() {
|
||||
}
|
||||
|
||||
public void setRelevantEventTypes(int eventTypes) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user