diff --git a/accessible/jsat/AccessFu.jsm b/accessible/jsat/AccessFu.jsm index 7dfcba89492c..a3cf74f0fa52 100644 --- a/accessible/jsat/AccessFu.jsm +++ b/accessible/jsat/AccessFu.jsm @@ -134,6 +134,8 @@ this.AccessFu = { // jshint ignore:line Services.obs.addObserver(this, 'Accessibility:Focus', false); Services.obs.addObserver(this, 'Accessibility:ActivateObject', false); Services.obs.addObserver(this, 'Accessibility:LongPress', false); + Services.obs.addObserver(this, 'Accessibility:ScrollForward', false); + Services.obs.addObserver(this, 'Accessibility:ScrollBackward', false); Services.obs.addObserver(this, 'Accessibility:MoveByGranularity', false); Utils.win.addEventListener('TabOpen', this); Utils.win.addEventListener('TabClose', this); @@ -187,6 +189,8 @@ this.AccessFu = { // jshint ignore:line Services.obs.removeObserver(this, 'Accessibility:Focus'); Services.obs.removeObserver(this, 'Accessibility:ActivateObject'); Services.obs.removeObserver(this, 'Accessibility:LongPress'); + Services.obs.removeObserver(this, 'Accessibility:ScrollForward'); + Services.obs.removeObserver(this, 'Accessibility:ScrollBackward'); Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity'); delete this._quicknavModesPref; @@ -315,6 +319,12 @@ this.AccessFu = { // jshint ignore:line case 'Accessibility:LongPress': this.Input.sendContextMenuMessage(); break; + case 'Accessibility:ScrollForward': + this.Input.androidScroll('forward'); + break; + case 'Accessibility:ScrollBackward': + this.Input.androidScroll('backward'); + break; case 'Accessibility:Focus': this._focused = JSON.parse(aData); if (this._focused) { @@ -837,6 +847,12 @@ var Input = { adjustRange: aAdjustRange }); }, + androidScroll: function androidScroll(aDirection) { + let mm = Utils.getMessageManager(Utils.CurrentBrowser); + mm.sendAsyncMessage('AccessFu:AndroidScroll', + { direction: aDirection, origin: 'top' }); + }, + moveByGranularity: function moveByGranularity(aDetails) { const MOVEMENT_GRANULARITY_PARAGRAPH = 8; diff --git a/accessible/jsat/ContentControl.jsm b/accessible/jsat/ContentControl.jsm index 11b75a0fb306..c726fa52b7a2 100644 --- a/accessible/jsat/ContentControl.jsm +++ b/accessible/jsat/ContentControl.jsm @@ -38,7 +38,8 @@ this.ContentControl.prototype = { 'AccessFu:AutoMove', 'AccessFu:Activate', 'AccessFu:MoveCaret', - 'AccessFu:MoveByGranularity'], + 'AccessFu:MoveByGranularity', + 'AccessFu:AndroidScroll'], start: function cc_start() { let cs = this._contentScope.get(); @@ -91,6 +92,27 @@ this.ContentControl.prototype = { } }, + handleAndroidScroll: function cc_handleAndroidScroll(aMessage) { + let vc = this.vc; + let position = vc.position; + + if (aMessage.json.origin != 'child' && this.sendToChild(vc, aMessage)) { + // Forwarded succesfully to child cursor. + return; + } + + // Counter-intuitive, but scrolling backward (ie. up), actually should + // increase range values. + if (this.adjustRange(position, aMessage.json.direction === 'backward')) { + return; + } + + this._contentScope.get().sendAsyncMessage('AccessFu:DoScroll', + { bounds: Utils.getBounds(position, true), + page: aMessage.json.direction === 'forward' ? 1 : -1, + horizontal: false }); + }, + handleMoveCursor: function cc_handleMoveCursor(aMessage) { let origin = aMessage.json.origin; let action = aMessage.json.action; diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js index f1de7ac8c99e..706e75df7e1a 100644 --- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -391,6 +391,20 @@ var ContentMessages = { } }, + androidScrollForward: function adjustUp() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'forward' } + }; + }, + + androidScrollBackward: function adjustDown() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'backward' } + }; + }, + focusSelector: function focusSelector(aSelector, aBlur) { return { name: 'AccessFuTest:Focus', diff --git a/accessible/tests/mochitest/jsat/test_content_integration.html b/accessible/tests/mochitest/jsat/test_content_integration.html index a21a6bc06072..229102ef976a 100644 --- a/accessible/tests/mochitest/jsat/test_content_integration.html +++ b/accessible/tests/mochitest/jsat/test_content_integration.html @@ -81,6 +81,8 @@ [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', '6', {'string': 'slider'}, 'such app'])], [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')], + [ContentMessages.androidScrollForward(), new ExpectedValueChange('6')], + [ContentMessages.androidScrollBackward(), new ExpectedValueChange('5')], [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', {'string': 'label'}])], [ContentMessages.simpleMovePrevious, diff --git a/mobile/android/base/GeckoAccessibility.java b/mobile/android/base/GeckoAccessibility.java index 5212d4ee89cb..1443dc558b8a 100644 --- a/mobile/android/base/GeckoAccessibility.java +++ b/mobile/android/base/GeckoAccessibility.java @@ -348,6 +348,8 @@ public class GeckoAccessibility { info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); @@ -388,6 +390,14 @@ public class GeckoAccessibility { GeckoAppShell. sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:LongPress", null)); return true; + } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && virtualViewId == VIRTUAL_CURSOR_POSITION) { + GeckoAppShell. + sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ScrollForward", null)); + return true; + } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD && virtualViewId == VIRTUAL_CURSOR_POSITION) { + GeckoAppShell. + sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ScrollBackward", null)); + return true; } else if (action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY && virtualViewId == VIRTUAL_CURSOR_POSITION) { // XXX: Self brailling gives this action with a bogus argument instead of an actual click action;