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 58ff66c09d8348ca5fb86e39c65c6ffe30f28198..476478bcb5a7f9eed96297090da22d17fa83b6c5 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.BrowserAccessibilityManager; |
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. |
*/ |
@@ -353,6 +365,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 BrowserAccessibilityManager 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; |
@@ -374,6 +392,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. |
@@ -393,6 +412,8 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
mStartHandlePoint = mRenderCoordinates.createNormalizedPoint(); |
mEndHandlePoint = mRenderCoordinates.createNormalizedPoint(); |
mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint(); |
+ mAccessibilityManager = (AccessibilityManager) |
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); |
bulach
2013/06/20 09:18:42
nit: indent another 4 (like line 411 above)
dmazzoni
2013/06/21 05:38:55
Done.
|
} |
/** |
@@ -638,8 +659,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 ACCESSIBILITY_SCRIPT_INJECTION = (String) field.get(null); |
David Trainor- moved to gerrit
2013/06/20 16:57:11
No all caps.
dmazzoni
2013/06/21 05:38:55
Done.
|
+ getContext().getContentResolver().registerContentObserver( |
+ Settings.Secure.getUriFor(ACCESSIBILITY_SCRIPT_INJECTION), |
+ 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) { |
@@ -1293,7 +1330,6 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
TraceEvent.begin(); |
hidePopupDialog(); |
nativeOnHide(mNativeContentViewCore); |
- setAccessibilityState(false); |
TraceEvent.end(); |
} |
@@ -1302,7 +1338,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
*/ |
public void onActivityResume() { |
nativeOnShow(mNativeContentViewCore); |
- setAccessibilityState(true); |
+ setAccessibilityState(mAccessibilityManager.isEnabled()); |
} |
/** |
@@ -1310,7 +1346,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
*/ |
public void onShow() { |
nativeOnShow(mNativeContentViewCore); |
- setAccessibilityState(true); |
+ setAccessibilityState(mAccessibilityManager.isEnabled()); |
} |
/** |
@@ -1318,7 +1354,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
*/ |
public void onHide() { |
hidePopupDialog(); |
- setAccessibilityState(false); |
+ setInjectedAccessibility(false); |
nativeOnHide(mNativeContentViewCore); |
} |
@@ -1371,7 +1407,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
ChildProcessLauncher.bindAsHighPriority(pid); |
} |
} |
- setAccessibilityState(true); |
+ setAccessibilityState(mAccessibilityManager.isEnabled()); |
} |
/** |
@@ -1386,7 +1422,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
ChildProcessLauncher.unbindAsHighPriority(pid); |
} |
} |
- setAccessibilityState(false); |
+ setInjectedAccessibility(false); |
hidePopupDialog(); |
mZoomControlsDelegate.dismissZoomPicker(); |
} |
@@ -1651,6 +1687,18 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
} |
/** |
+ * @see View#dispatchHoverEvent(MotionEvent) |
+ */ |
+ public boolean dispatchHoverEvent(MotionEvent event) { |
+ if (mBrowserAccessibilityManager != null) { |
+ return mBrowserAccessibilityManager.dispatchHoverEvent(event); |
+ } else { |
+ // ContentView.dispatchHoverEvent will call super. |
+ 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() |
@@ -2184,6 +2232,8 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix); |
mPendingRendererFrame = true; |
+ if (mBrowserAccessibilityManager != null) |
+ mBrowserAccessibilityManager.notifyFrameInfoInitialized(); |
David Trainor- moved to gerrit
2013/06/20 16:57:11
{} around this
dmazzoni
2013/06/21 05:38:55
Done.
|
} |
@SuppressWarnings("unused") |
@@ -2566,6 +2616,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. |
@@ -2594,9 +2649,39 @@ 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(BrowserAccessibilityManager 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 BrowserAccessibilityManager getBrowserAccessibilityManager() { |
+ return mBrowserAccessibilityManager; |
+ } |
+ |
+ /** |
+ * @see View#getAccessibilityNodeProvider(View host) |
+ */ |
+ public AccessibilityNodeProvider getAccessibilityNodeProvider() { |
+ // Note: this is only used for native accessibility, i.e. without |
+ // script injection. |
+ 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); |
} |
@@ -2604,6 +2689,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. |
@@ -2625,6 +2711,30 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
} |
/** |
+ * Returns whether accessibility script injection is enabled on the device |
+ */ |
+ public boolean isDeviceAccessibilityScriptInjectionEnabled() { |
+ try { |
+ int result = getContext().checkCallingOrSelfPermission( |
+ android.Manifest.permission.INTERNET); |
+ if (result != PackageManager.PERMISSION_GRANTED) |
+ return false; |
David Trainor- moved to gerrit
2013/06/20 16:57:11
{}
dmazzoni
2013/06/21 05:38:55
Done.
|
+ |
+ Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION"); |
+ field.setAccessible(true); |
+ String ACCESSIBILITY_SCRIPT_INJECTION = (String) field.get(null); |
David Trainor- moved to gerrit
2013/06/20 16:57:11
No all caps.
dmazzoni
2013/06/21 05:38:55
Done.
|
+ |
+ boolean onDeviceScriptInjectionEnabled = |
+ Settings.Secure.getInt(getContext().getContentResolver(), |
+ ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1; |
+ return onDeviceScriptInjectionEnabled; |
+ } catch (NoSuchFieldException e) { |
+ } catch (IllegalAccessException e) { |
+ } |
+ return false; |
benm (inactive)
2013/06/20 10:00:42
We should also check whether javascript is enabled
dmazzoni
2013/06/21 05:38:55
Good idea, done.
|
+ } |
+ |
+ /** |
* Returns whether or not accessibility injection is being used. |
*/ |
public boolean isInjectingAccessibilityScript() { |
@@ -2632,10 +2742,37 @@ 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; |
David Trainor- moved to gerrit
2013/06/20 16:57:11
{} {}
dmazzoni
2013/06/21 05:38:55
Done.
|
+ else |
+ nativeAccessibility = true; |
+ } |
+ setInjectedAccessibility(injectedAccessibility); |
+ setNativeAccessibilityState(nativeAccessibility); |
+ } |
+ |
+ /** |
+ * Enable or disable native accessibility features. |
+ */ |
+ public void setNativeAccessibilityState(boolean enabled) { |
+ nativeSetAccessibilityEnabled(mNativeContentViewCore, enabled); |
+ } |
+ |
+ /** |
+ * Enable or disable injected accessibility features |
+ */ |
+ public void setInjectedAccessibility(boolean enabled) { |
+ mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); |
+ mAccessibilityInjector.setScriptEnabled(enabled); |
} |
/** |
@@ -2968,4 +3105,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { |
private native void nativeDetachExternalVideoSurface( |
int nativeContentViewCoreImpl, int playerId); |
+ |
+ private native void nativeSetAccessibilityEnabled( |
+ int nativeContentViewCoreImpl, boolean enabled); |
} |