diff --git a/core/api/current.txt b/core/api/current.txt index f748c24e91818..0ecf95d043599 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -2883,6 +2883,7 @@ package android.accessibilityservice { method protected void onServiceConnected(); method public void onSystemActionsChanged(); method public final boolean performGlobalAction(int); + method public void setAccessibilityFocusAppearance(int, @ColorInt int); method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region); method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region); @@ -54611,6 +54612,8 @@ package android.view.accessibility { method public void addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, @Nullable android.os.Handler); method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener); method public void addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, @Nullable android.os.Handler); + method @ColorInt public int getAccessibilityFocusColor(); + method public int getAccessibilityFocusStrokeWidth(); method @Deprecated public java.util.List getAccessibilityServiceList(); method public java.util.List getEnabledAccessibilityServiceList(int); method public java.util.List getInstalledAccessibilityServiceList(); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 0ad9e446dfc77..8e50184c96e0b 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -18,6 +18,7 @@ package android.accessibilityservice; import android.accessibilityservice.GestureDescription.MotionEventGenerator; import android.annotation.CallbackExecutor; +import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -2117,6 +2118,27 @@ public abstract class AccessibilityService extends Service { } } + /** + * Sets the strokeWidth and color of the accessibility focus rectangle. + * + * @param strokeWidth The stroke width of the rectangle in pixels. + * Setting this value to zero results in no focus rectangle being drawn. + * @param color The color of the rectangle. + */ + public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (connection != null) { + try { + connection.setFocusAppearance(strokeWidth, color); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the " + + "accessibility focus rectangle", re); + re.rethrowFromSystemServer(); + } + } + } + /** * Implement to return the implementation of the internal accessibility * service interface. diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 0b3b9b2ecae19..ab21dc9f14ade 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -115,4 +115,6 @@ interface IAccessibilityServiceConnection { void setGestureDetectionPassthroughRegion(int displayId, in Region region); void setTouchExplorationPassthroughRegion(int displayId, in Region region); + + void setFocusAppearance(int strokeWidth, int color); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 349b84899f9da..2d633cbeb3537 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -119,6 +119,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.graphics.RenderNode; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.input.InputManager; @@ -4414,6 +4415,14 @@ public final class ViewRootImpl implements ViewParent, mView.mContext.getDrawable(value.resourceId); } } + // Sets the focus appearance data into the accessibility focus drawable. + if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) { + final GradientDrawable drawable = + (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable; + drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(), + mAccessibilityManager.getAccessibilityFocusColor()); + } + return mAttachInfo.mAccessibilityFocusDrawable; } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index a8534faf43e5d..56dcd5951e5e0 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -19,9 +19,11 @@ package android.view.accessibility; import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME; import android.Manifest; +import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType; import android.accessibilityservice.AccessibilityShortcutInfo; +import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -59,6 +61,7 @@ import android.view.IWindow; import android.view.View; import android.view.accessibility.AccessibilityEvent.EventType; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IntPair; @@ -233,6 +236,11 @@ public final class AccessibilityManager { private int mPerformingAction = 0; + /** The stroke width of the focus rectangle in pixels */ + private int mFocusStrokeWidth; + /** The color of the focus rectangle */ + private int mFocusColor; + @UnsupportedAppUsage private final ArrayMap mAccessibilityStateChangeListeners = new ArrayMap<>(); @@ -410,6 +418,13 @@ public final class AccessibilityManager { public void setRelevantEventTypes(int eventTypes) { mRelevantEventTypes = eventTypes; } + + @Override + public void setFocusAppearance(int strokeWidth, int color) { + synchronized (mLock) { + updateFocusAppearanceLocked(strokeWidth, color); + } + } }; /** @@ -457,6 +472,7 @@ public final class AccessibilityManager { mHandler = new Handler(context.getMainLooper(), mCallback); mUserId = userId; synchronized (mLock) { + initialFocusAppearanceLocked(context.getResources()); tryConnectToServiceLocked(service); } } @@ -464,18 +480,26 @@ public final class AccessibilityManager { /** * Create an instance. * + * @param context A {@link Context}. * @param handler The handler to use * @param service An interface to the backing service. * @param userId User id under which to run. + * @param serviceConnect {@code true} to connect the service or + * {@code false} not to connect the service. * * @hide */ - public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) { + @VisibleForTesting + public AccessibilityManager(Context context, Handler handler, IAccessibilityManager service, + int userId, boolean serviceConnect) { mCallback = new MyCallback(); mHandler = handler; mUserId = userId; synchronized (mLock) { - tryConnectToServiceLocked(service); + initialFocusAppearanceLocked(context.getResources()); + if (serviceConnect) { + tryConnectToServiceLocked(service); + } } } @@ -953,6 +977,32 @@ public final class AccessibilityManager { return recommendedTimeout; } + /** + * Gets the strokeWidth of the focus rectangle. This value can be set by + * {@link AccessibilityService}. + * + * @return The strokeWidth of the focus rectangle in pixels. + * + */ + public int getAccessibilityFocusStrokeWidth() { + synchronized (mLock) { + return mFocusStrokeWidth; + } + } + + /** + * Gets the color of the focus rectangle. This value can be set by + * {@link AccessibilityService}. + * + * @return The color of the focus rectangle. + * + */ + public @ColorInt int getAccessibilityFocusColor() { + synchronized (mLock) { + return mFocusColor; + } + } + /** * Get the preparers that are registered for an accessibility ID * @@ -1551,6 +1601,7 @@ public final class AccessibilityManager { setStateLocked(IntPair.first(userStateAndRelevantEvents)); mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents); updateUiTimeout(service.getRecommendedTimeoutMillis()); + updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor()); mService = service; } catch (RemoteException re) { Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); @@ -1634,6 +1685,40 @@ public final class AccessibilityManager { mNonInteractiveUiTimeout = IntPair.second(uiTimeout); } + /** + * Updates the stroke width and color of the focus rectangle. + * + * @param strokeWidth The strokeWidth of the focus rectangle. + * @param color The color of the focus rectangle. + */ + private void updateFocusAppearanceLocked(int strokeWidth, int color) { + if (mFocusStrokeWidth == strokeWidth && mFocusColor == color) { + return; + } + mFocusStrokeWidth = strokeWidth; + mFocusColor = color; + } + + /** + * Sets the stroke width and color of the focus rectangle to default value. + * + * @param resource The resources. + */ + private void initialFocusAppearanceLocked(Resources resource) { + try { + mFocusStrokeWidth = resource.getDimensionPixelSize( + R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColor = resource.getColor(R.color.accessibility_focus_highlight_color); + } catch (Resources.NotFoundException re) { + // Sets the stroke width and color to default value by hardcoded for making + // the Talkback can work normally. + mFocusStrokeWidth = (int) (4 * resource.getDisplayMetrics().density); + mFocusColor = 0xbf39b500; + Log.e(LOG_TAG, "Error while initialing the focus appearance data then setting to" + + " default value by hardcoded", re); + } + } + /** * Determines if the accessibility button within the system navigation area is supported. * diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 5d3c72015ee3b..c71ea53c414d9 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -92,4 +92,8 @@ interface IAccessibilityManager { void associateEmbeddedHierarchy(IBinder host, IBinder embedded); void disassociateEmbeddedHierarchy(IBinder token); + + int getFocusStrokeWidth(); + + int getFocusColor(); } diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl index 94b9ad1c32790..041399ccb8ec4 100644 --- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl @@ -29,4 +29,6 @@ oneway interface IAccessibilityManagerClient { void notifyServicesStateChanged(long updatedUiTimeout); void setRelevantEventTypes(int eventTypes); + + void setFocusAppearance(int strokeWidth, int color); } diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml index 025916b35f402..aa3031e5cf26b 100644 --- a/core/res/res/drawable/view_accessibility_focused.xml +++ b/core/res/res/drawable/view_accessibility_focused.xml @@ -17,8 +17,8 @@ + android:width="@dimen/accessibility_focus_highlight_stroke_width" + android:color="@color/accessibility_focus_highlight_color" /> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 0079d8cd02766..110e77a8aa053 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -159,7 +159,7 @@ #ffffffff #ff35b5e5 - #bf39b500 + #bf39b500 #4dffeb3b #ff607D8B diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 4bcabff109ea3..05db741643e8c 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -553,6 +553,9 @@ 4dip + + 4dp + 8dp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index cd00fbf204cfb..8e4e9af8f4ad9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4115,4 +4115,9 @@ + + + + + diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java index 8e2490789a6f0..75116d8c6df26 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java @@ -38,6 +38,7 @@ import android.os.UserHandle; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; import com.android.internal.util.IntPair; import com.android.server.accessibility.test.MessageCapturingHandler; @@ -73,12 +74,18 @@ public class AccessibilityManagerTest { @Mock private IAccessibilityManager mMockService; private MessageCapturingHandler mHandler; private Instrumentation mInstrumentation; + private int mFocusStrokeWidthDefaultValue; + private int mFocusColorDefaultValue; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mHandler = new MessageCapturingHandler(null); mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mFocusStrokeWidthDefaultValue = mInstrumentation.getContext().getResources() + .getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColorDefaultValue = mInstrumentation.getContext().getResources().getColor( + R.color.accessibility_focus_highlight_color); } @After @@ -94,8 +101,12 @@ public class AccessibilityManagerTest { when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt())) .thenReturn(serviceReturnValue); + when(mMockService.getFocusStrokeWidth()).thenReturn(mFocusStrokeWidthDefaultValue); + when(mMockService.getFocusColor()).thenReturn(mFocusColorDefaultValue); + AccessibilityManager manager = - new AccessibilityManager(mHandler, mMockService, UserHandle.USER_CURRENT); + new AccessibilityManager(mInstrumentation.getContext(), mHandler, mMockService, + UserHandle.USER_CURRENT, true); verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt()); mHandler.setCallback(manager.getCallback()); @@ -205,4 +216,16 @@ public class AccessibilityManagerTest { verify(mMockService).setWindowMagnificationConnection(connection); } + + @Test + public void testGetDefaultValueOfFocusAppearanceData() { + AccessibilityManager manager = + new AccessibilityManager(mInstrumentation.getContext(), mHandler, null, + UserHandle.USER_CURRENT, false); + + assertEquals(mFocusStrokeWidthDefaultValue, + manager.getAccessibilityFocusStrokeWidth()); + assertEquals(mFocusColorDefaultValue, + manager.getAccessibilityFocusColor()); + } } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java index 75a7504cac2fc..cfdb2b769a08e 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java @@ -161,4 +161,6 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon public void setTouchExplorationPassthroughRegion(int displayId, Region region) {} public void setGestureDetectionPassthroughRegion(int displayId, Region region) {} + + public void setFocusAppearance(int strokeWidth, int color) {} } diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index c17c36eba2dc5..6baf3056be320 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -68,6 +68,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; import android.widget.Toast; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; @@ -148,7 +149,8 @@ public class AccessibilityShortcutControllerTest { // Use the extra level of indirection in the object to mock framework objects AccessibilityManager accessibilityManager = - new AccessibilityManager(mHandler, mAccessibilityManagerService, 0); + new AccessibilityManager(InstrumentationRegistry.getContext(), mHandler, + mAccessibilityManagerService, 0, true); when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)) .thenReturn(accessibilityManager); when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE)) diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index d6d4e4f6c746c..8f093c7e66746 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1797,4 +1797,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ public void setTouchExplorationPassthroughRegion(int displayId, Region region) { mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region); } + + @Override + public void setFocusAppearance(int strokeWidth, int color) { } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index be2f8f16a4120..c6919ad245723 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1968,6 +1968,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Update the capabilities before the mode. updateMagnificationCapabilitiesSettingsChangeLocked(userState); updateMagnificationModeChangeSettingsLocked(userState); + updateFocusAppearanceDataLocked(userState); } private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) { @@ -3012,6 +3013,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * Gets the stroke width of the focus rectangle. + * @return The stroke width. + */ + public int getFocusStrokeWidth() { + synchronized (mLock) { + final AccessibilityUserState userState = getCurrentUserStateLocked(); + + return userState.getFocusStrokeWidthLocked(); + } + } + + /** + * Gets the color of the focus rectangle. + * @return The color. + */ + public int getFocusColor() { + synchronized (mLock) { + final AccessibilityUserState userState = getCurrentUserStateLocked(); + + return userState.getFocusColorLocked(); + } + } + @Override public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; @@ -3623,4 +3648,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } } + + private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) { + if (userState.mUserId != mCurrentUserId) { + return; + } + + mMainHandler.post(() -> { + broadcastToClients(userState, ignoreRemoteException(client -> { + client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(), + userState.getFocusColorLocked()); + })); + }); + + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index e48d11d17f40d..5d67992316a24 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -120,6 +120,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect AccessibilityUserState userState = mUserStateWeakReference.get(); if (userState == null) return; userState.removeServiceLocked(this); + userState.resetFocusAppearanceLocked(); + mSystemSupport.onClientChangeLocked(false); mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId); mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1, userState.mUserId); @@ -144,6 +146,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect } finally { Binder.restoreCallingIdentity(identity); } + userState.resetFocusAppearanceLocked(); mSystemSupport.onClientChangeLocked(false); } } @@ -310,6 +313,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect AccessibilityUserState userState = mUserStateWeakReference.get(); if (userState != null) { userState.serviceDisconnectedLocked(this); + userState.resetFocusAppearanceLocked(); } resetLocked(); mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId); @@ -391,4 +395,32 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect } } } + + @Override + public void setFocusAppearance(int strokeWidth, int color) { + AccessibilityUserState userState = mUserStateWeakReference.get(); + if (userState == null) { + return; + } + + synchronized (mLock) { + if (!hasRightsToCurrentUserLocked()) { + return; + } + + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return; + } + + if (userState.getFocusStrokeWidthLocked() == strokeWidth + && userState.getFocusColorLocked() == color) { + return; + } + + // Sets the appearance data in the A11yUserState. + userState.setFocusAppearanceLocked(strokeWidth, color); + // Updates the appearance data in the A11yManager. + mSystemSupport.onClientChangeLocked(false); + } + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 240c7ff061c83..90e2fdfa2f033 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -45,6 +45,7 @@ import android.util.Slog; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManagerClient; +import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import java.io.FileDescriptor; @@ -122,6 +123,15 @@ class AccessibilityUserState { // The magnification capabilities used to know magnification mode could be switched. private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; + /** The stroke width of the focus rectangle in pixels */ + private int mFocusStrokeWidth; + /** The color of the focus rectangle */ + private int mFocusColor; + // The default value of the focus stroke width. + private final int mFocusStrokeWidthDefaultValue; + // The default value of the focus color. + private final int mFocusColorDefaultValue; + private Context mContext; @SoftKeyboardShowMode @@ -140,6 +150,12 @@ class AccessibilityUserState { mUserId = userId; mContext = context; mServiceInfoChangeListener = serviceInfoChangeListener; + mFocusStrokeWidthDefaultValue = mContext.getResources().getDimensionPixelSize( + R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColorDefaultValue = mContext.getResources().getColor( + R.color.accessibility_focus_highlight_color); + mFocusStrokeWidth = mFocusStrokeWidthDefaultValue; + mFocusColor = mFocusColorDefaultValue; } boolean isHandlingAccessibilityEventsLocked() { @@ -178,6 +194,7 @@ class AccessibilityUserState { mUserNonInteractiveUiTimeout = 0; mUserInteractiveUiTimeout = 0; mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; + resetFocusAppearanceLocked(); } void addServiceLocked(AccessibilityServiceConnection serviceConnection) { @@ -880,4 +897,40 @@ class AccessibilityUserState { } return false; } + + /** + * Gets the stroke width of the focus rectangle. + * @return The stroke width. + */ + public int getFocusStrokeWidthLocked() { + return mFocusStrokeWidth; + } + + /** + * Gets the color of the focus rectangle. + * @return The color. + */ + public int getFocusColorLocked() { + return mFocusColor; + } + + /** + * Sets the stroke width and color of the focus rectangle. + * + * @param strokeWidth The strokeWidth of the focus rectangle. + * @param color The color of the focus rectangle. + */ + public void setFocusAppearanceLocked(int strokeWidth, int color) { + mFocusStrokeWidth = strokeWidth; + mFocusColor = color; + } + + /** + * Resets the stroke width and color of the focus rectangle to the default value. + * + */ + public void resetFocusAppearanceLocked() { + mFocusStrokeWidth = mFocusStrokeWidthDefaultValue; + mFocusColor = mFocusColorDefaultValue; + } } 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 3f3d5e5106c58..839bc93ba00f4 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -35,6 +35,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.graphics.drawable.Icon; import android.os.IBinder; import android.os.UserHandle; @@ -94,6 +95,8 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { @Mock private IAccessibilityServiceClient mMockServiceClient; @Mock private WindowMagnificationManager mMockWindowMagnificationMgr; @Mock private MagnificationController mMockMagnificationController; + @Mock private Resources mMockResources; + private AccessibilityUserState mUserState; private MessageCapturingHandler mHandler = new MessageCapturingHandler(null); @@ -121,6 +124,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { mMockA11yDisplayListener, mMockMagnificationController); + mMockResources = mock(Resources.class); + when(mMockContext.getResources()).thenReturn(mMockResources); + final AccessibilityUserState userState = new AccessibilityUserState( mA11yms.getCurrentUserIdLocked(), mMockContext, mA11yms); mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java index fbfb0455bd460..81ca92cc3c8cf 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java @@ -42,11 +42,16 @@ import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.ComponentName; import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.testing.DexmakerShareClassLoaderRule; import android.util.ArraySet; +import androidx.test.InstrumentationRegistry; + +import com.android.internal.R; import com.android.internal.util.test.FakeSettingsProvider; import org.junit.After; @@ -90,8 +95,13 @@ public class AccessibilityUserStateTest { private AccessibilityUserState mUserState; + private int mFocusStrokeWidthDefaultValue; + private int mFocusColorDefaultValue; + @Before public void setUp() { + final Resources resources = InstrumentationRegistry.getContext().getResources(); + MockitoAnnotations.initMocks(this); FakeSettingsProvider.clearSettingsProvider(); mMockResolver = new MockContentResolver(); @@ -99,6 +109,11 @@ public class AccessibilityUserStateTest { when(mMockContext.getContentResolver()).thenReturn(mMockResolver); when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME); when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo); + when(mMockContext.getResources()).thenReturn(resources); + + mFocusStrokeWidthDefaultValue = + resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color); mUserState = new AccessibilityUserState(USER_ID, mMockContext, mMockListener); } @@ -129,6 +144,7 @@ public class AccessibilityUserStateTest { mUserState.setUserNonInteractiveUiTimeoutLocked(30); mUserState.setUserInteractiveUiTimeoutLocked(30); mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + mUserState.setFocusAppearanceLocked(20, Color.BLUE); mUserState.onSwitchToAnotherUserLocked(); @@ -150,6 +166,8 @@ public class AccessibilityUserStateTest { assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked()); assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, mUserState.getMagnificationModeLocked()); + assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked()); + assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked()); } @Test @@ -350,6 +368,21 @@ public class AccessibilityUserStateTest { mUserState.getMagnificationModeLocked()); } + @Test + public void setFocusAppearanceData_returnExpectedFocusAppearanceData() { + final int focusStrokeWidthValue = 100; + final int focusColorValue = Color.BLUE; + + assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked()); + assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked()); + + mUserState.setFocusAppearanceLocked(focusStrokeWidthValue, focusColorValue); + + assertEquals(focusStrokeWidthValue, mUserState.getFocusStrokeWidthLocked()); + assertEquals(focusColorValue, mUserState.getFocusColorLocked()); + + } + private int getSecureIntForUser(String key, int userId) { return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 00f706b13c586..32cb2a3a25403 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -153,7 +153,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { AccessibilityEvent.TYPES_ALL_MASK); when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue); AccessibilityManager accessibilityManager = - new AccessibilityManager(Handler.getMain(), mAccessibilityService, 0); + new AccessibilityManager(getContext(), Handler.getMain(), mAccessibilityService, + 0, true); verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt()); assertTrue(accessibilityManager.isEnabled());