| Index: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| index eeebf036b9d11f23fecddf5bb13100e046585029..64276aa32631f319c0281ebf473f16a78402b061 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| @@ -9,14 +9,18 @@ import android.content.Context;
|
| import android.content.pm.ActivityInfo;
|
| import android.content.pm.PackageManager;
|
| import android.content.res.Configuration;
|
| +import android.database.ContentObserver;
|
| import android.graphics.Bitmap;
|
| import android.graphics.Canvas;
|
| import android.graphics.Color;
|
| import android.graphics.Rect;
|
| +import android.net.Uri;
|
| import android.os.Build;
|
| import android.os.Bundle;
|
| import android.os.Handler;
|
| import android.os.ResultReceiver;
|
| +import android.provider.Settings;
|
| +import android.provider.Settings.Secure;
|
| import android.text.Editable;
|
| import android.util.Log;
|
| import android.util.Pair;
|
| @@ -30,7 +34,10 @@ import android.view.ViewGroup;
|
| import android.view.Window;
|
| import android.view.WindowManager;
|
| import android.view.accessibility.AccessibilityEvent;
|
| +import android.view.accessibility.AccessibilityManager;
|
| +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
|
| import android.view.accessibility.AccessibilityNodeInfo;
|
| +import android.view.accessibility.AccessibilityNodeProvider;
|
| import android.view.inputmethod.EditorInfo;
|
| import android.view.inputmethod.InputConnection;
|
| import android.view.inputmethod.InputMethodManager;
|
| @@ -44,6 +51,7 @@ import org.chromium.base.WeakContext;
|
| import org.chromium.content.R;
|
| import org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate;
|
| import org.chromium.content.browser.accessibility.AccessibilityInjector;
|
| +import org.chromium.content.browser.accessibility.BaseBrowserAccessibilityManager;
|
| import org.chromium.content.browser.input.AdapterInputConnection;
|
| import org.chromium.content.browser.input.HandleView;
|
| import org.chromium.content.browser.input.ImeAdapter;
|
| @@ -58,6 +66,8 @@ import org.chromium.ui.WindowAndroid;
|
| import org.chromium.ui.gfx.DeviceDisplayInfo;
|
|
|
| import java.lang.annotation.Annotation;
|
| +import java.lang.reflect.Field;
|
| +import java.util.Arrays;
|
| import java.util.HashMap;
|
| import java.util.HashSet;
|
| import java.util.Map;
|
| @@ -68,7 +78,9 @@ import java.util.Map;
|
| * being tied to the view system.
|
| */
|
| @JNINamespace("content")
|
| -public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| + public class ContentViewCore implements MotionEventDelegate,
|
| + NavigationClient,
|
| + AccessibilityStateChangeListener {
|
| /**
|
| * Indicates that input events are batched together and delivered just before vsync.
|
| */
|
| @@ -348,6 +360,12 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| // The AccessibilityInjector that handles loading Accessibility scripts into the web page.
|
| private AccessibilityInjector mAccessibilityInjector;
|
|
|
| + // Handles native accessibility, i.e. without any script injection.
|
| + private BaseBrowserAccessibilityManager mBrowserAccessibilityManager;
|
| +
|
| + // System accessibility service.
|
| + private final AccessibilityManager mAccessibilityManager;
|
| +
|
| // Temporary notification to tell onSizeChanged to focus a form element,
|
| // because the OSK was just brought up.
|
| private boolean mUnfocusOnNextSizeChanged = false;
|
| @@ -369,6 +387,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
|
|
| private ViewAndroid mViewAndroid;
|
|
|
| +
|
| /**
|
| * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
|
| * a ContentViewCore and before using it.
|
| @@ -388,6 +407,8 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| mStartHandlePoint = mRenderCoordinates.createNormalizedPoint();
|
| mEndHandlePoint = mRenderCoordinates.createNormalizedPoint();
|
| mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
|
| + mAccessibilityManager = (AccessibilityManager)
|
| + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
|
| }
|
|
|
| /**
|
| @@ -633,8 +654,24 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| mContentSettings = new ContentSettings(this, mNativeContentViewCore);
|
| initializeContainerView(internalDispatcher, inputEventDeliveryMode);
|
|
|
| + try {
|
| + Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
|
| + field.setAccessible(true);
|
| + String accessibilityScriptInjection = (String) field.get(null);
|
| + getContext().getContentResolver().registerContentObserver(
|
| + Settings.Secure.getUriFor(accessibilityScriptInjection),
|
| + false,
|
| + new ContentObserver(new Handler()) {
|
| + public void onChange(boolean selfChange, Uri uri) {
|
| + setAccessibilityState(mAccessibilityManager.isEnabled());
|
| + }
|
| + });
|
| + } catch (Exception e) {
|
| + Log.e("chromium", "Could not add listener for script injection preference. " +
|
| + "Defaulting to native accessibility.\n" + e.toString());
|
| + }
|
| +
|
| mAccessibilityInjector = AccessibilityInjector.newInstance(this);
|
| - mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
|
|
|
| String contentDescription = "Web View";
|
| if (R.string.accessibility_content_view == 0) {
|
| @@ -1288,7 +1325,6 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| TraceEvent.begin();
|
| hidePopupDialog();
|
| nativeOnHide(mNativeContentViewCore);
|
| - setAccessibilityState(false);
|
| TraceEvent.end();
|
| }
|
|
|
| @@ -1297,7 +1333,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| */
|
| public void onActivityResume() {
|
| nativeOnShow(mNativeContentViewCore);
|
| - setAccessibilityState(true);
|
| + setAccessibilityState(mAccessibilityManager.isEnabled());
|
| }
|
|
|
| /**
|
| @@ -1305,7 +1341,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| */
|
| public void onShow() {
|
| nativeOnShow(mNativeContentViewCore);
|
| - setAccessibilityState(true);
|
| + setAccessibilityState(mAccessibilityManager.isEnabled());
|
| }
|
|
|
| /**
|
| @@ -1313,7 +1349,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| */
|
| public void onHide() {
|
| hidePopupDialog();
|
| - setAccessibilityState(false);
|
| + setInjectedAccessibility(false);
|
| nativeOnHide(mNativeContentViewCore);
|
| }
|
|
|
| @@ -1366,7 +1402,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| ChildProcessLauncher.bindAsHighPriority(pid);
|
| }
|
| }
|
| - setAccessibilityState(true);
|
| + setAccessibilityState(mAccessibilityManager.isEnabled());
|
| }
|
|
|
| /**
|
| @@ -1381,7 +1417,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| ChildProcessLauncher.unbindAsHighPriority(pid);
|
| }
|
| }
|
| - setAccessibilityState(false);
|
| + setInjectedAccessibility(false);
|
| hidePopupDialog();
|
| mZoomControlsDelegate.dismissZoomPicker();
|
| }
|
| @@ -1646,6 +1682,23 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| }
|
|
|
| /**
|
| + * Any View that uses ContentViewCore should call override dispatchHoverEvent
|
| + * and call this method first so that all hover events can be intercepted and
|
| + * used for touch exploration if accessibility is on, and then only call the
|
| + * inherited method if this returns false.
|
| + *
|
| + * @see View#dispatchHoverEvent(MotionEvent)
|
| + */
|
| + public boolean dispatchHoverEvent(MotionEvent event) {
|
| + if (mBrowserAccessibilityManager != null) {
|
| + return mBrowserAccessibilityManager.dispatchHoverEvent(event);
|
| + } else {
|
| + // The client view should call super.dispatchHoverEvent.
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + /**
|
| * @see View#scrollBy(int, int)
|
| * Currently the ContentView scrolling happens in the native side. In
|
| * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
|
| @@ -2171,6 +2224,9 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix);
|
|
|
| mPendingRendererFrame = true;
|
| + if (mBrowserAccessibilityManager != null) {
|
| + mBrowserAccessibilityManager.notifyFrameInfoInitialized();
|
| + }
|
| }
|
|
|
| @SuppressWarnings("unused")
|
| @@ -2553,6 +2609,11 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| getContentViewClient().onStartContentIntent(getContext(), contentUrl);
|
| }
|
|
|
| + @Override
|
| + public void onAccessibilityStateChanged(boolean enabled) {
|
| + setAccessibilityState(enabled);
|
| + }
|
| +
|
| /**
|
| * Determines whether or not this ContentViewCore can handle this accessibility action.
|
| * @param action The action to perform.
|
| @@ -2581,9 +2642,30 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| }
|
|
|
| /**
|
| + * Set the BrowserAccessibilityManager, used for native accessibility
|
| + * (not script injection). This is only set when system accessibility
|
| + * has been enabled.
|
| + * @param manager The new BrowserAccessibilityManager.
|
| + */
|
| + public void setBrowserAccessibilityManager(BaseBrowserAccessibilityManager manager) {
|
| + mBrowserAccessibilityManager = manager;
|
| + }
|
| +
|
| + /**
|
| + * Get the BrowserAccessibilityManager, used for native accessibility
|
| + * (not script injection). This will return null when system accessibility
|
| + * is not enabled.
|
| + * @return This view's BrowserAccessibilityManager.
|
| + */
|
| + public BaseBrowserAccessibilityManager getBrowserAccessibilityManager() {
|
| + return mBrowserAccessibilityManager;
|
| + }
|
| +
|
| + /**
|
| * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
|
| */
|
| public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
| + // Note: this is only used by the script-injecting accessibility code.
|
| mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
|
| }
|
|
|
| @@ -2591,6 +2673,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
|
| */
|
| public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
| + // Note: this is only used by the script-injecting accessibility code.
|
| event.setClassName(this.getClass().getName());
|
|
|
| // Identify where the top-left of the screen currently points to.
|
| @@ -2612,6 +2695,35 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| }
|
|
|
| /**
|
| + * Returns whether accessibility script injection is enabled on the device
|
| + */
|
| + public boolean isDeviceAccessibilityScriptInjectionEnabled() {
|
| + try {
|
| + if (!mContentSettings.getJavaScriptEnabled()) {
|
| + return false;
|
| + }
|
| +
|
| + int result = getContext().checkCallingOrSelfPermission(
|
| + android.Manifest.permission.INTERNET);
|
| + if (result != PackageManager.PERMISSION_GRANTED) {
|
| + return false;
|
| + }
|
| +
|
| + Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
|
| + field.setAccessible(true);
|
| + String accessibilityScriptInjection = (String) field.get(null);
|
| +
|
| + boolean onDeviceScriptInjectionEnabled =
|
| + Settings.Secure.getInt(getContext().getContentResolver(),
|
| + accessibilityScriptInjection, 0) == 1;
|
| + return onDeviceScriptInjectionEnabled;
|
| + } catch (NoSuchFieldException e) {
|
| + } catch (IllegalAccessException e) {
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| * Returns whether or not accessibility injection is being used.
|
| */
|
| public boolean isInjectingAccessibilityScript() {
|
| @@ -2619,10 +2731,40 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
| }
|
|
|
| /**
|
| - * Enable or disable accessibility features.
|
| + * Turns browser accessibility on or off.
|
| + * If |state| is |false|, this turns off both native and injected accessibility.
|
| + * Otherwise, if accessibility script injection is enabled, this will enable the injected
|
| + * accessibility scripts, and if it is disabled this will enable the native accessibility.
|
| */
|
| public void setAccessibilityState(boolean state) {
|
| - mAccessibilityInjector.setScriptEnabled(state);
|
| + boolean injectedAccessibility = false;
|
| + boolean nativeAccessibility = false;
|
| + if (state) {
|
| + if (isDeviceAccessibilityScriptInjectionEnabled()) {
|
| + injectedAccessibility = true;
|
| + } else {
|
| + nativeAccessibility = true;
|
| + }
|
| + }
|
| + setInjectedAccessibility(injectedAccessibility);
|
| + setNativeAccessibilityState(nativeAccessibility);
|
| + }
|
| +
|
| + /**
|
| + * Enable or disable native accessibility features.
|
| + */
|
| + public void setNativeAccessibilityState(boolean enabled) {
|
| + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
| + nativeSetAccessibilityEnabled(mNativeContentViewCore, enabled);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Enable or disable injected accessibility features
|
| + */
|
| + public void setInjectedAccessibility(boolean enabled) {
|
| + mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
|
| + mAccessibilityInjector.setScriptEnabled(enabled);
|
| }
|
|
|
| /**
|
| @@ -2955,4 +3097,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
|
|
|
| private native void nativeDetachExternalVideoSurface(
|
| int nativeContentViewCoreImpl, int playerId);
|
| +
|
| + private native void nativeSetAccessibilityEnabled(
|
| + int nativeContentViewCoreImpl, boolean enabled);
|
| }
|
|
|