Merge "Dont dispatch a11y events that have no subscribers"

This commit is contained in:
TreeHugger Robot
2017-03-14 04:35:34 +00:00
committed by Android (Google) Code Review
9 changed files with 164 additions and 28 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -25,5 +25,8 @@ package android.view.accessibility;
oneway interface IAccessibilityManagerClient {
void setState(int stateFlags);
void notifyServicesStateChanged();
void setRelevantEventTypes(int eventTypes);
}

View 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;
}
}

View File

@@ -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<>();

View File

@@ -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) {}
}
/**

View File

@@ -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 =

View File

@@ -95,6 +95,9 @@ public final class AccessibilityManager {
public void notifyServicesStateChanged() {
}
public void setRelevantEventTypes(int eventTypes) {
}
};
/**