diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 3a3e17123d3c6..69892d991ccd0 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -971,14 +971,14 @@ public final class AccessibilityManager { } /** - * Notifies that the availability of the accessibility button in the system's navigation area + * Notifies that the visibility of the accessibility button in the system's navigation area * has changed. * - * @param available {@code true} if the accessibility button is available within the system + * @param shown {@code true} if the accessibility button is visible within the system * navigation area, {@code false} otherwise * @hide */ - public void notifyAccessibilityButtonAvailabilityChanged(boolean available) { + public void notifyAccessibilityButtonVisibilityChanged(boolean shown) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); @@ -987,9 +987,9 @@ public final class AccessibilityManager { } } try { - service.notifyAccessibilityButtonAvailabilityChanged(available); + service.notifyAccessibilityButtonVisibilityChanged(shown); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error while dispatching accessibility button availability change", re); + Log.e(LOG_TAG, "Error while dispatching accessibility button visibility change", re); } } diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 06cb5dca8afa9..3f499abd2e4d1 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -64,7 +64,7 @@ interface IAccessibilityManager { void notifyAccessibilityButtonClicked(); - void notifyAccessibilityButtonAvailabilityChanged(boolean available); + void notifyAccessibilityButtonVisibilityChanged(boolean available); // Requires WRITE_SECURE_SETTINGS void performAccessibilityShortcut(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 9e2f52a875b5c..a58ba09e39374 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -243,6 +243,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private WindowsForAccessibilityCallback mWindowsForAccessibilityCallback; + private boolean mIsAccessibilityButtonShown; + private UserState getCurrentUserStateLocked() { return getUserStateLocked(mCurrentUserId); } @@ -872,21 +874,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } /** - * Invoked remotely over AIDL by SysUi when the availability of the accessibility + * Invoked remotely over AIDL by SysUi when the visibility of the accessibility * button within the system's navigation area has changed. * - * @param available {@code true} if the accessibility button is available to the + * @param shown {@code true} if the accessibility button is shown to the * user, {@code false} otherwise */ @Override - public void notifyAccessibilityButtonAvailabilityChanged(boolean available) { + public void notifyAccessibilityButtonVisibilityChanged(boolean shown) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller does not hold permission " + android.Manifest.permission.STATUS_BAR_SERVICE); } synchronized (mLock) { - notifyAccessibilityButtonAvailabilityChangedLocked(available); + notifyAccessibilityButtonVisibilityChangedLocked(shown); } } @@ -1191,13 +1193,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { + private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) { final UserState state = getCurrentUserStateLocked(); - state.mIsAccessibilityButtonAvailable = available; + mIsAccessibilityButtonShown = available; for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { final Service service = state.mBoundServices.get(i); if (service.mRequestAccessibilityButton) { - service.notifyAccessibilityButtonAvailabilityChangedLocked(available); + service.notifyAccessibilityButtonAvailabilityChangedLocked( + service.isAccessibilityButtonAvailableLocked(state)); } } } @@ -1724,7 +1727,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { scheduleUpdateInputFilter(userState); scheduleUpdateClientsIfNeededLocked(userState); updateRelevantEventsLocked(userState); - updateAccessibilityButtonTargets(userState); + updateAccessibilityButtonTargetsLocked(userState); } private void updateAccessibilityFocusBehaviorLocked(UserState userState) { @@ -2174,18 +2177,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void updateAccessibilityButtonTargets(UserState userState) { - final List services; - synchronized (mLock) { - services = userState.mBoundServices; - int numServices = services.size(); - for (int i = 0; i < numServices; i++) { - final Service service = services.get(i); - if (service.mRequestAccessibilityButton) { - boolean available = service.mComponentName.equals( - userState.mServiceAssignedToAccessibilityButton); - service.notifyAccessibilityButtonAvailabilityChangedLocked(available); - } + private void updateAccessibilityButtonTargetsLocked(UserState userState) { + for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { + final Service service = userState.mBoundServices.get(i); + if (service.mRequestAccessibilityButton) { + service.notifyAccessibilityButtonAvailabilityChangedLocked( + service.isAccessibilityButtonAvailableLocked(userState)); } } } @@ -2492,7 +2489,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER: { showAccessibilityButtonTargetSelection(); - } + } break; } } @@ -2647,6 +2644,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { boolean mRequestAccessibilityButton; + boolean mReceivedAccessibilityButtonCallbackSinceBind; + + boolean mLastAccessibilityButtonCallbackState; + int mFetchFlags; long mNotificationTimeout; @@ -3587,9 +3588,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } userState = getCurrentUserStateLocked(); + return isAccessibilityButtonAvailableLocked(userState); } - - return mRequestAccessibilityButton && userState.mIsAccessibilityButtonAvailable; } @Override @@ -3647,6 +3647,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mService = null; } mServiceInterface = null; + mReceivedAccessibilityButtonCallbackSinceBind = false; } public boolean isConnectedLocked() { @@ -3719,6 +3720,48 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + private boolean isAccessibilityButtonAvailableLocked(UserState userState) { + // If the service does not request the accessibility button, it isn't available + if (!mRequestAccessibilityButton) { + return false; + } + + // If the accessibility button isn't currently shown, it cannot be available to services + if (!mIsAccessibilityButtonShown) { + return false; + } + + // If magnification is on and assigned to the accessibility button, services cannot be + if (userState.mIsNavBarMagnificationEnabled + && userState.mIsNavBarMagnificationAssignedToAccessibilityButton) { + return false; + } + + int requestingServices = 0; + for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { + final Service service = userState.mBoundServices.get(i); + if (service.mRequestAccessibilityButton) { + requestingServices++; + } + } + + if (requestingServices == 1) { + // If only a single service is requesting, it must be this service, and the + // accessibility button is available to it + return true; + } else { + // With more than one active service, we derive the target from the user's settings + if (userState.mServiceAssignedToAccessibilityButton == null) { + // If the user has not made an assignment, we treat the button as available to + // all services until the user interacts with the button to make an assignment + return true; + } else { + // If an assignment was made, it defines availability + return mComponentName.equals(userState.mServiceAssignedToAccessibilityButton); + } + } + } + /** * Notifies an accessibility service client for a scheduled event given the event type. * @@ -3866,6 +3909,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) { + // Only notify the service if it's not been notified or the state has changed + if (mReceivedAccessibilityButtonCallbackSinceBind + && (mLastAccessibilityButtonCallbackState == available)) { + return; + } + mReceivedAccessibilityButtonCallbackSinceBind = true; + mLastAccessibilityButtonCallbackState = available; final IAccessibilityServiceClient listener; synchronized (mLock) { listener = mServiceInterface; @@ -4865,7 +4915,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public int mSoftKeyboardShowMode = 0; - public boolean mIsAccessibilityButtonAvailable; public boolean mIsNavBarMagnificationAssignedToAccessibilityButton; public ComponentName mServiceAssignedToAccessibilityButton; @@ -4945,9 +4994,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mIsNavBarMagnificationAssignedToAccessibilityButton = false; mIsAutoclickEnabled = false; mSoftKeyboardShowMode = 0; - - // Clear state tracked from system UI - mIsAccessibilityButtonAvailable = false; } public void destroyUiAutomationService() { diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java index 7a2808146f62d..b1792358be538 100644 --- a/services/core/java/com/android/server/policy/BarController.java +++ b/services/core/java/com/android/server/policy/BarController.java @@ -166,8 +166,14 @@ public class BarController { return change || stateChanged; } - void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener) { + void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener, + boolean invokeWithState) { mVisibilityChangeListener = listener; + if (invokeWithState) { + // Optionally report the initial window state for initialization purposes + mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED, + (mState == StatusBarManager.WINDOW_STATE_SHOWING) ? 1 : 0, 0).sendToTarget(); + } } protected boolean skipAnimation() { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 126e3ec302893..a032844a81b79 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1033,7 +1033,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new BarController.OnBarVisibilityChangedListener() { @Override public void onBarVisibilityChanged(boolean visible) { - mAccessibilityManager.notifyAccessibilityButtonAvailabilityChanged(visible); + mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible); } }; @@ -3017,7 +3017,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mNavigationBar = win; mNavigationBarController.setWindow(win); mNavigationBarController.setOnBarVisibilityChangedListener( - mNavBarVisibilityListener); + mNavBarVisibilityListener, true); if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_NAVIGATION_BAR_PANEL: