Bug 1479037 - Remove virtual content node, js autofill, and event support 2/4. r=jchen,yzen
authorEitan Isaacson <eitan@monotonous.org>
Thu, 11 Oct 2018 16:21:01 +0000
changeset 440732 dab75afa1e1e7e10abb5f7c7931d3fd889778fe8
parent 440731 7f44f29dc7ae52fbfe50aa8adad1ce9aae2fdc29
child 440733 97b5d09ed65af9bfa5eb287f4a5c0f7e5e4ae4a6
push id34832
push usernbeleuzu@mozilla.com
push dateFri, 12 Oct 2018 03:43:40 +0000
treeherdermozilla-central@a19bd92250b6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjchen, yzen
bugs1479037
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1479037 - Remove virtual content node, js autofill, and event support 2/4. r=jchen,yzen Disabled most jsunit tests temporarily in this patch. Will modify and bring them back up in later patches, as stuff is reimplemented. Disabled most jsat mochitests. Will have a followup for but re├źnabling or porting, depending on the test. Depends on D6681 Differential Revision: https://phabricator.services.mozilla.com/D6682
accessible/jsat/AccessFu.jsm
accessible/jsat/ContentControl.jsm
accessible/jsat/EventManager.jsm
accessible/jsat/OutputGenerator.jsm
accessible/jsat/Presentation.jsm
accessible/jsat/moz.build
accessible/tests/mochitest/jsat/a11y.ini
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -26,17 +26,16 @@ const GECKOVIEW_MESSAGE = {
   SCROLL_BACKWARD: "GeckoView:AccessibilityScrollBackward",
   SCROLL_FORWARD: "GeckoView:AccessibilityScrollForward",
   SELECT: "GeckoView:AccessibilitySelect",
   SET_SELECTION: "GeckoView:AccessibilitySetSelection",
   VIEW_FOCUSED: "GeckoView:AccessibilityViewFocused",
 };
 
 const ACCESSFU_MESSAGE = {
-  PRESENT: "AccessFu:Present",
   DOSCROLL: "AccessFu:DoScroll",
 };
 
 const FRAME_SCRIPT = "chrome://global/content/accessibility/content-script.js";
 
 var AccessFu = {
   /**
    * A lazy getter for event handler that binds the scope to AccessFu object.
@@ -52,21 +51,16 @@ var AccessFu = {
    */
   enable: function enable() {
     if (this._enabled) {
       return;
     }
     this._enabled = true;
 
     ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
-    ChromeUtils.import("resource://gre/modules/accessibility/Presentation.jsm");
-
-    // Check for output notification
-    this._notifyOutputPref =
-      new PrefCache("accessibility.accessfu.notify_output");
 
     Services.obs.addObserver(this, "remote-browser-shown");
     Services.obs.addObserver(this, "inprocess-browser-shown");
     Services.ww.registerNotification(this);
 
     for (let win of Services.wm.getEnumerator(null)) {
       this._attachWindow(win);
     }
@@ -87,35 +81,30 @@ var AccessFu = {
     Services.obs.removeObserver(this, "remote-browser-shown");
     Services.obs.removeObserver(this, "inprocess-browser-shown");
     Services.ww.unregisterNotification(this);
 
     for (let win of Services.wm.getEnumerator(null)) {
       this._detachWindow(win);
     }
 
-    delete this._notifyOutputPref;
-
     if (this.doneCallback) {
       this.doneCallback();
       delete this.doneCallback;
     }
 
     Logger.info("AccessFu:Disabled");
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     Logger.debug(() => {
       return ["Recieved", aMessage.name, JSON.stringify(aMessage.json)];
     });
 
     switch (aMessage.name) {
-      case ACCESSFU_MESSAGE.PRESENT:
-        this._output(aMessage.json, aMessage.target);
-        break;
       case ACCESSFU_MESSAGE.DOSCROLL:
         this.Input.doScroll(aMessage.json, aMessage.target);
         break;
     }
   },
 
   _attachWindow: function _attachWindow(win) {
     let wtype = win.document.documentElement.getAttribute("windowtype");
@@ -150,48 +139,16 @@ var AccessFu = {
     win.removeEventListener("TabSelect", this);
     if (win.WindowEventDispatcher) {
       // desktop mochitests don't have this.
       win.WindowEventDispatcher.unregisterListener(this,
         Object.values(GECKOVIEW_MESSAGE));
     }
   },
 
-  _output: function _output(aPresentationData, aBrowser) {
-    if (!aPresentationData) {
-      // Either no android events to send or a string used for testing only.
-      return;
-    }
-
-    if (!Utils.isAliveAndVisible(Utils.AccService.getAccessibleFor(aBrowser))) {
-      return;
-    }
-
-    let win = aBrowser.ownerGlobal;
-
-    for (let evt of aPresentationData) {
-      if (typeof evt == "string") {
-        continue;
-      }
-
-      if (win.WindowEventDispatcher) {
-        // desktop mochitests don't have this.
-        win.WindowEventDispatcher.sendRequest({
-          ...evt,
-          type: "GeckoView:AccessibilityEvent"
-        });
-      }
-    }
-
-    if (this._notifyOutputPref.value) {
-      Services.obs.notifyObservers(null, "accessibility-output",
-                                   JSON.stringify(aPresentationData));
-    }
-  },
-
   onEvent(event, data, callback) {
     switch (event) {
       case GECKOVIEW_MESSAGE.SETTINGS:
         if (data.enabled) {
           this._enable();
         } else {
           this._disable();
         }
@@ -214,22 +171,16 @@ var AccessFu = {
         // XXX: Advertize long press on supported objects and implement action
         break;
       case GECKOVIEW_MESSAGE.SCROLL_FORWARD:
         this.Input.androidScroll("forward");
         break;
       case GECKOVIEW_MESSAGE.SCROLL_BACKWARD:
         this.Input.androidScroll("backward");
         break;
-      case GECKOVIEW_MESSAGE.VIEW_FOCUSED:
-        this._focused = data.gainFocus;
-        if (this._focused) {
-          this.autoMove({ forcePresent: true, noOpIfOnScreen: true });
-        }
-        break;
       case GECKOVIEW_MESSAGE.BY_GRANULARITY:
         this.Input.moveByGranularity(data);
         break;
       case GECKOVIEW_MESSAGE.EXPLORE_BY_TOUCH:
         this.Input.moveToPoint("Simple", ...data.coordinates);
         break;
       case GECKOVIEW_MESSAGE.SET_SELECTION:
         this.Input.setSelection(data);
@@ -276,20 +227,16 @@ var AccessFu = {
     }
   },
 
   autoMove: function autoMove(aOptions) {
     const mm = Utils.getMessageManager();
     mm.sendAsyncMessage("AccessFu:AutoMove", aOptions);
   },
 
-  announce: function announce(aAnnouncement) {
-    this._output(Presentation.announce(aAnnouncement), Utils.getCurrentBrowser());
-  },
-
   // So we don't enable/disable twice
   _enabled: false,
 
   // Layerview is focused
   _focused: false,
 
   /**
    * Adjusts the given bounds that are defined in device display pixels
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -9,18 +9,16 @@ ChromeUtils.defineModuleGetter(this, "Lo
 ChromeUtils.defineModuleGetter(this, "Roles",
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "States",
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "TraversalRules",
   "resource://gre/modules/accessibility/Traversal.jsm");
 ChromeUtils.defineModuleGetter(this, "TraversalHelper",
   "resource://gre/modules/accessibility/Traversal.jsm");
-ChromeUtils.defineModuleGetter(this, "Presentation",
-  "resource://gre/modules/accessibility/Presentation.jsm");
 
 var EXPORTED_SYMBOLS = ["ContentControl"];
 
 const MOVEMENT_GRANULARITY_CHARACTER = 1;
 const MOVEMENT_GRANULARITY_WORD = 2;
 const MOVEMENT_GRANULARITY_LINE = 4;
 
 const CLIPBOARD_COPY = 0x4000;
@@ -150,19 +148,16 @@ this.ContentControl.prototype = {
         // new position.
         this.sendToChild(vc, aMessage, { action: childAction }, true);
       }
     } else if (!this._childMessageSenders.has(aMessage.target) &&
                origin !== "top") {
       // We failed to move, and the message is not from a parent, so forward
       // to it.
       this.sendToParent(aMessage);
-    } else {
-      this._contentScope.get().sendAsyncMessage("AccessFu:Present",
-        Presentation.noMove(action));
     }
   },
 
   handleMoveToPoint: function cc_handleMoveToPoint(aMessage) {
     let [x, y] = [aMessage.json.x, aMessage.json.y];
     let rule = TraversalRules[aMessage.json.rule];
 
     this.vc.moveToPoint(rule, x, y, true);
@@ -223,39 +218,28 @@ this.ContentControl.prototype = {
 
         for (let eventType of ["mousedown", "mouseup"]) {
           let evt = this.document.createEvent("MouseEvents");
           evt.initMouseEvent(eventType, true, true, this.window,
             x, y, 0, 0, 0, false, false, false, false, 0, null);
           node.dispatchEvent(evt);
         }
       }
-
-      // Action invoked will be presented on checked/selected state change.
-      if (!Utils.getState(aAccessible).contains(States.CHECKABLE) &&
-          !Utils.getState(aAccessible).contains(States.SELECTABLE)) {
-        this._contentScope.get().sendAsyncMessage("AccessFu:Present",
-          Presentation.actionInvoked());
-      }
     };
 
     let focusedAcc = Utils.AccService.getAccessibleFor(
       this.document.activeElement);
     if (focusedAcc && this.vc.position === focusedAcc
         && focusedAcc.role === Roles.ENTRY) {
       let accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
-      let oldOffset = accText.caretOffset;
       let newOffset = aMessage.json.offset;
-      let text = accText.getText(0, accText.characterCount);
-
       if (newOffset >= 0 && newOffset <= accText.characterCount) {
         accText.caretOffset = newOffset;
       }
 
-      this.presentCaretChange(text, oldOffset, accText.caretOffset);
       return;
     }
 
     // recursively find a descendant that is activatable.
     let getActivatableDescendant = (aAccessible) => {
       if (aAccessible.actionCount > 0) {
         return aAccessible;
       }
@@ -394,25 +378,16 @@ this.ContentControl.prototype = {
           if (startSel != endSel) {
             editText.cutText(startSel, endSel);
           }
           break;
       }
     }
   },
 
-  presentCaretChange: function cc_presentCaretChange(
-    aText, aOldOffset, aNewOffset) {
-    if (aOldOffset !== aNewOffset) {
-      let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
-        aOldOffset, aOldOffset, true);
-      this._contentScope.get().sendAsyncMessage("AccessFu:Present", msg);
-    }
-  },
-
   getChildCursor: function cc_getChildCursor(aAccessible) {
     let acc = aAccessible || this.vc.position;
     if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
       let domNode = acc.DOMNode;
       let mm = this._childMessageSenders.get(domNode, null);
       if (!mm) {
         mm = Utils.getMessageManager(domNode);
         mm.addWeakMessageListener("AccessFu:MoveCursor", this);
@@ -451,48 +426,37 @@ this.ContentControl.prototype = {
   sendToParent: function cc_sendToParent(aMessage) {
     // XXX: This is a silly way to make a deep copy
     let newJSON = JSON.parse(JSON.stringify(aMessage.json));
     newJSON.origin = "child";
     aMessage.target.sendAsyncMessage(aMessage.name, newJSON);
   },
 
   /**
-   * Move cursor and/or present its location.
+   * Move cursor.
    * aOptions could have any of these fields:
    * - delay: in ms, before actual move is performed. Another autoMove call
    *    would cancel it. Useful if we want to wait for a possible trailing
    *    focus move. Default 0.
    * - noOpIfOnScreen: if accessible is alive and visible, don't do anything.
-   * - forcePresent: present cursor location, whether we move or don't.
    * - moveToFocused: if there is a focused accessible move to that. This takes
    *    precedence over given anchor.
    * - moveMethod: pivot move method to use, default is 'moveNext',
    */
   autoMove: function cc_autoMove(aAnchor, aOptions = {}) {
     this.cancelAutoMove();
 
     let moveFunc = () => {
       let vc = this.vc;
       let acc = aAnchor;
       let rule = aOptions.onScreenOnly ?
         TraversalRules.SimpleOnScreen : TraversalRules.Simple;
-      let forcePresentFunc = () => {
-        if (aOptions.forcePresent) {
-          this._contentScope.get().sendAsyncMessage(
-            "AccessFu:Present", Presentation.pivotChanged(
-              vc.position, null, vc.startOffset, vc.endOffset,
-              Ci.nsIAccessiblePivot.REASON_NONE,
-              Ci.nsIAccessiblePivot.NO_BOUNDARY));
-        }
-      };
 
       if (aOptions.noOpIfOnScreen &&
         Utils.isAliveAndVisible(vc.position, true)) {
-        forcePresentFunc();
         return;
       }
 
       if (aOptions.moveToFocused) {
         acc = Utils.AccService.getAccessibleFor(
           this.document.activeElement) || acc;
       }
 
@@ -504,29 +468,24 @@ this.ContentControl.prototype = {
         moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](rule, acc, true,
                                                               true);
       }
       if (moveFirstOrLast && !moved) {
         // We move to first/last after no anchor move happened or succeeded.
         moved = vc[moveMethod](rule, true);
       }
 
-      let sentToChild = this.sendToChild(vc, {
+      this.sendToChild(vc, {
         name: "AccessFu:AutoMove",
         json: {
           moveMethod: aOptions.moveMethod,
           moveToFocused: aOptions.moveToFocused,
           noOpIfOnScreen: true,
-          forcePresent: true
         }
       }, null, true);
-
-      if (!moved && !sentToChild) {
-        forcePresentFunc();
-      }
     };
 
     if (aOptions.delay) {
       this._autoMove = this.window.setTimeout(moveFunc, aOptions.delay);
     } else {
       moveFunc();
     }
   },
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -5,125 +5,73 @@
 "use strict";
 
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "Logger",
   "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "Presentation",
-  "resource://gre/modules/accessibility/Presentation.jsm");
 ChromeUtils.defineModuleGetter(this, "Roles",
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "Events",
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "States",
   "resource://gre/modules/accessibility/Constants.jsm");
-ChromeUtils.defineModuleGetter(this, "clearTimeout",
-  "resource://gre/modules/Timer.jsm");
-ChromeUtils.defineModuleGetter(this, "setTimeout",
-  "resource://gre/modules/Timer.jsm");
 
 var EXPORTED_SYMBOLS = ["EventManager"];
 
 function EventManager(aContentScope) {
   this.contentScope = aContentScope;
   this.addEventListener = this.contentScope.addEventListener.bind(
     this.contentScope);
   this.removeEventListener = this.contentScope.removeEventListener.bind(
     this.contentScope);
   this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(
     this.contentScope);
-  this.webProgress = this.contentScope.docShell.
-    QueryInterface(Ci.nsIInterfaceRequestor).
-    getInterface(Ci.nsIWebProgress);
 }
 
 this.EventManager.prototype = {
   start: function start() {
     try {
       if (!this._started) {
         Logger.debug("EventManager.start");
 
         this._started = true;
 
         AccessibilityEventObserver.addListener(this);
 
-        this.webProgress.addProgressListener(this,
-          (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
-           Ci.nsIWebProgress.NOTIFY_LOCATION));
-        this.addEventListener("wheel", this, true);
-        this.addEventListener("scroll", this, true);
-        this.addEventListener("resize", this, true);
         this._preDialogPosition = new WeakMap();
       }
-      this.present(Presentation.tabStateChanged(null, "newtab"));
-
     } catch (x) {
       Logger.logException(x, "Failed to start EventManager");
     }
   },
 
   // XXX: Stop is not called when the tab is closed (|TabClose| event is too
   // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
     Logger.debug("EventManager.stop");
     AccessibilityEventObserver.removeListener(this);
     try {
       this._preDialogPosition = new WeakMap();
-      this.webProgress.removeProgressListener(this);
-      this.removeEventListener("wheel", this, true);
-      this.removeEventListener("scroll", this, true);
-      this.removeEventListener("resize", this, true);
     } catch (x) {
       // contentScope is dead.
     } finally {
       this._started = false;
     }
   },
 
   get contentControl() {
     return this.contentScope._jsat_contentControl;
   },
 
-  handleEvent: function handleEvent(aEvent) {
-    Logger.debug(() => {
-      return ["DOMEvent", aEvent.type];
-    });
-
-    // The target could be an element, document or window
-    const win = aEvent.target.ownerGlobal;
-    try {
-      switch (aEvent.type) {
-        case "wheel":
-        {
-          let delta = aEvent.deltaX || aEvent.deltaY;
-          this.contentControl.autoMove(
-           null,
-           { moveMethod: delta > 0 ? "moveNext" : "movePrevious",
-             onScreenOnly: true, noOpIfOnScreen: true, delay: 500 });
-          break;
-        }
-        case "scroll":
-          this.present(Presentation.viewportScrolled(win));
-        case "resize":
-        {
-          this.present(Presentation.viewportChanged(win));
-          break;
-        }
-      }
-    } catch (x) {
-      Logger.logException(x, "Error handling DOM event");
-    }
-  },
-
   handleAccEvent: function handleAccEvent(aEvent) {
     Logger.debug(() => {
       return ["A11yEvent", Logger.eventToString(aEvent),
               Logger.accessibleToString(aEvent.accessible)];
     });
 
     // Don't bother with non-content events in firefox.
     if (Utils.MozBuildApp == "browser" &&
@@ -151,358 +99,47 @@ this.EventManager.prototype = {
         if (position && position.role == Roles.INTERNAL_FRAME) {
           break;
         }
 
         // Blur to document if new position is not explicitly focused.
         if (!position || !Utils.getState(position).contains(States.FOCUSED)) {
           aEvent.accessibleDocument.takeFocus();
         }
-
-        this.present(
-          Presentation.pivotChanged(position, event.oldAccessible,
-                                    event.newStartOffset, event.newEndOffset,
-                                    event.reason, event.boundaryType));
-
-        break;
-      }
-      case Events.STATE_CHANGE:
-      {
-        const event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
-        const state = Utils.getState(event);
-        if (state.contains(States.CHECKED)) {
-          this.present(Presentation.checked(aEvent.accessible));
-        } else if (state.contains(States.SELECTED)) {
-          this.present(Presentation.selected(aEvent.accessible));
-        }
         break;
       }
       case Events.NAME_CHANGE:
       {
-        let acc = aEvent.accessible;
-        if (acc === this.contentControl.vc.position) {
-          this.present(Presentation.nameChanged(acc));
-        } else {
-          let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
-            ["text", "all"]);
-          if (liveRegion) {
-            this.present(Presentation.nameChanged(acc, isPolite));
-          }
-        }
+        // XXX: Port to Android
         break;
       }
       case Events.SCROLLING_START:
       {
         this.contentControl.autoMove(aEvent.accessible);
         break;
       }
-      case Events.TEXT_CARET_MOVED:
-      {
-        let acc = aEvent.accessible.QueryInterface(Ci.nsIAccessibleText);
-        let caretOffset = aEvent.
-          QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset;
-
-        // We could get a caret move in an accessible that is not focused,
-        // it doesn't mean we are not on any editable accessible. just not
-        // on this one..
-        let state = Utils.getState(acc);
-        if (state.contains(States.FOCUSED) && state.contains(States.EDITABLE)) {
-          let fromIndex = caretOffset;
-          if (acc.selectionCount) {
-            const [startSel, endSel] = Utils.getTextSelection(acc);
-            fromIndex = startSel == caretOffset ? endSel : startSel;
-          }
-          this.present(Presentation.textSelectionChanged(
-            acc.getText(0, -1), fromIndex, caretOffset, 0, 0,
-            aEvent.isFromUserInput));
-        }
-        break;
-      }
       case Events.SHOW:
       {
-        this._handleShow(aEvent);
+        // XXX: Port to Android
         break;
       }
       case Events.HIDE:
       {
-        let evt = aEvent.QueryInterface(Ci.nsIAccessibleHideEvent);
-        this._handleHide(evt);
-        break;
-      }
-      case Events.TEXT_INSERTED:
-      case Events.TEXT_REMOVED:
-      {
-        let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
-          ["text", "all"]);
-        if (aEvent.isFromUserInput || liveRegion) {
-          // Handle all text mutations coming from the user or if they happen
-          // on a live region.
-          this._handleText(aEvent, liveRegion, isPolite);
-        }
+        // XXX: Port to Android
         break;
       }
-      case Events.FOCUS:
-      {
-        // Put vc where the focus is at
-        let acc = aEvent.accessible;
-        if (![Roles.CHROME_WINDOW,
-             Roles.DOCUMENT,
-             Roles.APPLICATION].includes(acc.role)) {
-          this.contentControl.autoMove(acc);
-        }
-
-        this.present(Presentation.focused(acc));
-
-       if (Utils.inTest) {
-        this.sendMsgFunc("AccessFu:Focused");
-       }
-       break;
-      }
-      case Events.DOCUMENT_LOAD_COMPLETE:
-      {
-        let position = this.contentControl.vc.position;
-        // Check if position is in the subtree of the DOCUMENT_LOAD_COMPLETE
-        // event's dialog accessible or accessible document
-        let subtreeRoot = aEvent.accessible.role === Roles.DIALOG ?
-          aEvent.accessible : aEvent.accessibleDocument;
-        if (aEvent.accessible === aEvent.accessibleDocument ||
-            (position && Utils.isInSubtree(position, subtreeRoot))) {
-          // Do not automove into the document if the virtual cursor is already
-          // positioned inside it.
-          break;
-        }
-        this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
-        this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
-        break;
-      }
-      case Events.TEXT_VALUE_CHANGE:
-        // We handle this events in TEXT_INSERTED/TEXT_REMOVED.
-        break;
       case Events.VALUE_CHANGE:
       {
-        let position = this.contentControl.vc.position;
-        let target = aEvent.accessible;
-        if (position === target ||
-            Utils.getEmbeddedControl(position) === target) {
-          this.present(Presentation.valueChanged(target));
-        } else {
-          let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
-            ["text", "all"]);
-          if (liveRegion) {
-            this.present(Presentation.valueChanged(target, isPolite));
-          }
-        }
-      }
-    }
-  },
-
-  _handleShow: function _handleShow(aEvent) {
-    let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
-      ["additions", "all"]);
-    // Only handle show if it is a relevant live region.
-    if (!liveRegion) {
-      return;
-    }
-    // Show for text is handled by the EVENT_TEXT_INSERTED handler.
-    if (aEvent.accessible.role === Roles.TEXT_LEAF) {
-      return;
-    }
-    this._dequeueLiveEvent(Events.HIDE, liveRegion);
-    this.present(Presentation.liveRegion(liveRegion, isPolite, false));
-  },
-
-  _handleHide: function _handleHide(aEvent) {
-    let {liveRegion, isPolite} = this._handleLiveRegion(
-      aEvent, ["removals", "all"]);
-    let acc = aEvent.accessible;
-    if (liveRegion) {
-      // Hide for text is handled by the EVENT_TEXT_REMOVED handler.
-      if (acc.role === Roles.TEXT_LEAF) {
-        return;
-      }
-      this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
-    } else {
-      let vc = Utils.getVirtualCursor(this.contentScope.content.document);
-      if (vc.position &&
-        (Utils.getState(vc.position).contains(States.DEFUNCT) ||
-          Utils.isInSubtree(vc.position, acc))) {
-        let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) ||
-          aEvent.targetPrevSibling || aEvent.targetParent;
-        if (!position) {
-          try {
-            position = acc.previousSibling;
-          } catch (x) {
-            // Accessible is unattached from the accessible tree.
-            position = acc.parent;
-          }
-        }
-        this.contentControl.autoMove(position,
-          { moveToFocused: true, delay: 500 });
+        // XXX: Port to Android
+        break;
       }
     }
   },
 
-  _handleText: function _handleText(aEvent, aLiveRegion, aIsPolite) {
-    let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent);
-    let isInserted = event.isInserted;
-    let txtIface = aEvent.accessible.QueryInterface(Ci.nsIAccessibleText);
-
-    let text = "";
-    try {
-      text = txtIface.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
-    } catch (x) {
-      // XXX we might have gotten an exception with of a
-      // zero-length text. If we did, ignore it (bug #749810).
-      if (txtIface.characterCount) {
-        throw x;
-      }
-    }
-    // If there are embedded objects in the text, ignore them.
-    // Assuming changes to the descendants would already be handled by the
-    // show/hide event.
-    let modifiedText = event.modifiedText.replace(/\uFFFC/g, "");
-    if (modifiedText != event.modifiedText && !modifiedText.trim()) {
-      return;
-    }
-
-    if (aLiveRegion) {
-      if (aEvent.eventType === Events.TEXT_REMOVED) {
-        this._queueLiveEvent(Events.TEXT_REMOVED, aLiveRegion, aIsPolite,
-          modifiedText);
-      } else {
-        this._dequeueLiveEvent(Events.TEXT_REMOVED, aLiveRegion);
-        this.present(Presentation.liveRegion(aLiveRegion, aIsPolite, false,
-          modifiedText));
-      }
-    } else {
-      this.present(Presentation.textChanged(aEvent.accessible, isInserted,
-        event.start, event.length, text, modifiedText));
-    }
-  },
-
-  _handleLiveRegion: function _handleLiveRegion(aEvent, aRelevant) {
-    if (aEvent.isFromUserInput) {
-      return {};
-    }
-    let parseLiveAttrs = function parseLiveAttrs(aAccessible) {
-      let attrs = Utils.getAttributes(aAccessible);
-      if (attrs["container-live"]) {
-        return {
-          live: attrs["container-live"],
-          relevant: attrs["container-relevant"] || "additions text",
-          busy: attrs["container-busy"],
-          atomic: attrs["container-atomic"],
-          memberOf: attrs["member-of"]
-        };
-      }
-      return null;
-    };
-    // XXX live attributes are not set for hidden accessibles yet. Need to
-    // climb up the tree to check for them.
-    let getLiveAttributes = function getLiveAttributes(aEvent) {
-      let liveAttrs = parseLiveAttrs(aEvent.accessible);
-      if (liveAttrs) {
-        return liveAttrs;
-      }
-      let parent = aEvent.targetParent;
-      while (parent) {
-        liveAttrs = parseLiveAttrs(parent);
-        if (liveAttrs) {
-          return liveAttrs;
-        }
-        parent = parent.parent;
-      }
-      return {};
-    };
-    let {live, relevant, /* busy, atomic, memberOf */ } = getLiveAttributes(aEvent);
-    // If container-live is not present or is set to |off| ignore the event.
-    if (!live || live === "off") {
-      return {};
-    }
-    // XXX: support busy and atomic.
-
-    // Determine if the type of the mutation is relevant. Default is additions
-    // and text.
-    let isRelevant = Utils.matchAttributeValue(relevant, aRelevant);
-    if (!isRelevant) {
-      return {};
-    }
-    return {
-      liveRegion: aEvent.accessible,
-      isPolite: live === "polite"
-    };
-  },
-
-  _dequeueLiveEvent: function _dequeueLiveEvent(aEventType, aLiveRegion) {
-    let domNode = aLiveRegion.DOMNode;
-    if (this._liveEventQueue && this._liveEventQueue.has(domNode)) {
-      let queue = this._liveEventQueue.get(domNode);
-      let nextEvent = queue[0];
-      if (nextEvent.eventType === aEventType) {
-        clearTimeout(nextEvent.timeoutID);
-        queue.shift();
-        if (queue.length === 0) {
-          this._liveEventQueue.delete(domNode);
-        }
-      }
-    }
-  },
-
-  _queueLiveEvent: function _queueLiveEvent(aEventType, aLiveRegion, aIsPolite, aModifiedText) {
-    if (!this._liveEventQueue) {
-      this._liveEventQueue = new WeakMap();
-    }
-    let eventHandler = {
-      eventType: aEventType,
-      timeoutID: setTimeout(this.present.bind(this),
-        20, // Wait for a possible EVENT_SHOW or EVENT_TEXT_INSERTED event.
-        Presentation.liveRegion(aLiveRegion, aIsPolite, true, aModifiedText))
-    };
-
-    let domNode = aLiveRegion.DOMNode;
-    if (this._liveEventQueue.has(domNode)) {
-      this._liveEventQueue.get(domNode).push(eventHandler);
-    } else {
-      this._liveEventQueue.set(domNode, [eventHandler]);
-    }
-  },
-
-  present: function present(aPresentationData) {
-    if (aPresentationData && aPresentationData.length > 0) {
-      this.sendMsgFunc("AccessFu:Present", aPresentationData);
-    }
-  },
-
-  onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
-    let tabstate = "";
-
-    let loadingState = Ci.nsIWebProgressListener.STATE_TRANSFERRING |
-      Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
-    let loadedState = Ci.nsIWebProgressListener.STATE_STOP |
-      Ci.nsIWebProgressListener.STATE_IS_NETWORK;
-
-    if ((aStateFlags & loadingState) == loadingState) {
-      tabstate = "loading";
-    } else if ((aStateFlags & loadedState) == loadedState &&
-               !aWebProgress.isLoadingDocument) {
-      tabstate = "loaded";
-    }
-
-    if (tabstate) {
-      let docAcc = Utils.AccService.getAccessibleFor(aWebProgress.DOMWindow.document);
-      this.present(Presentation.tabStateChanged(docAcc, tabstate));
-    }
-  },
-
-  onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
-    let docAcc = Utils.AccService.getAccessibleFor(aWebProgress.DOMWindow.document);
-    this.present(Presentation.tabStateChanged(docAcc, "newdoc"));
-  },
-
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference, Ci.nsIObserver])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
 };
 
 const AccessibilityEventObserver = {
 
   /**
    * A WeakMap containing [content, EventManager] pairs.
    */
   eventManagers: new WeakMap(),
deleted file mode 100644
--- a/accessible/jsat/OutputGenerator.jsm
+++ /dev/null
@@ -1,824 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* exported UtteranceGenerator */
-
-"use strict";
-
-const INCLUDE_DESC = 0x01;
-const INCLUDE_NAME = 0x02;
-const INCLUDE_VALUE = 0x04;
-const NAME_FROM_SUBTREE_RULE = 0x10;
-const IGNORE_EXPLICIT_NAME = 0x20;
-
-const OUTPUT_DESC_FIRST = 0;
-const OUTPUT_DESC_LAST = 1;
-
-ChromeUtils.defineModuleGetter(this, "Utils", // jshint ignore:line
-  "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "PrefCache", // jshint ignore:line
-  "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "Logger", // jshint ignore:line
-  "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
-  "resource://gre/modules/accessibility/Constants.jsm");
-ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
-  "resource://gre/modules/accessibility/Constants.jsm");
-
-var EXPORTED_SYMBOLS = ["UtteranceGenerator"]; // jshint ignore:line
-
-var OutputGenerator = {
-
-  defaultOutputOrder: OUTPUT_DESC_LAST,
-
-  /**
-   * Generates output for a PivotContext.
-   * @param {PivotContext} aContext object that generates and caches
-   *    context information for a given accessible and its relationship with
-   *    another accessible.
-   * @return {Object} An array of speech data. Depending on the utterance order,
-   *    the data describes the context for an accessible object either
-   *    starting from the accessible's ancestry or accessible's subtree.
-   */
-  genForContext: function genForContext(aContext) {
-    let output = [];
-    let self = this;
-    let addOutput = function addOutput(aAccessible) {
-      output.push.apply(output, self.genForObject(aAccessible, aContext));
-    };
-    let ignoreSubtree = function ignoreSubtree(aAccessible) {
-      let roleString = Utils.AccService.getStringRole(aAccessible.role);
-      let nameRule = self.roleRuleMap[roleString] || 0;
-      // Ignore subtree if the name is explicit and the role's name rule is the
-      // NAME_FROM_SUBTREE_RULE.
-      return (((nameRule & INCLUDE_VALUE) && aAccessible.value) ||
-              ((nameRule & NAME_FROM_SUBTREE_RULE) &&
-               (Utils.getAttributes(aAccessible)["explicit-name"] === "true" &&
-               !(nameRule & IGNORE_EXPLICIT_NAME))));
-    };
-
-    let contextStart = this._getContextStart(aContext);
-
-    if (this.outputOrder === OUTPUT_DESC_FIRST) {
-      contextStart.forEach(addOutput);
-      addOutput(aContext.accessible);
-      for (let node of aContext.subtreeGenerator(true, ignoreSubtree)) {
-        addOutput(node);
-      }
-    } else {
-      for (let node of aContext.subtreeGenerator(false, ignoreSubtree)) {
-        addOutput(node);
-      }
-      addOutput(aContext.accessible);
-
-      // If there are any documents in new ancestry, find a first one and place
-      // it in the beginning of the utterance.
-      let doc, docIndex = contextStart.findIndex(
-        ancestor => ancestor.role === Roles.DOCUMENT);
-
-      if (docIndex > -1) {
-        doc = contextStart.splice(docIndex, 1)[0];
-      }
-
-      contextStart.reverse().forEach(addOutput);
-      if (doc) {
-        output.unshift.apply(output, self.genForObject(doc, aContext));
-      }
-    }
-
-    return output;
-  },
-
-
-  /**
-   * Generates output for an object.
-   * @param {nsIAccessible} aAccessible accessible object to generate output
-   *    for.
-   * @param {PivotContext} aContext object that generates and caches
-   *    context information for a given accessible and its relationship with
-   *    another accessible.
-   * @return {Array} A 2 element array of speech data. The first element
-   *    describes the object and its state. The second element is the object's
-   *    name. Whether the object's description or it's role is included is
-   *    determined by {@link roleRuleMap}.
-   */
-  genForObject: function genForObject(aAccessible, aContext) {
-    let roleString = Utils.AccService.getStringRole(aAccessible.role);
-    let func = this.objectOutputFunctions[
-      OutputGenerator._getOutputName(roleString)] ||
-      this.objectOutputFunctions.defaultFunc;
-
-    let flags = this.roleRuleMap[roleString] || 0;
-
-    if (aAccessible.childCount === 0) {
-      flags |= INCLUDE_NAME;
-    }
-
-    return func.apply(this, [aAccessible, roleString,
-                             Utils.getState(aAccessible), flags, aContext]);
-  },
-
-  /**
-   * Generates output for an action performed.
-   * @param {nsIAccessible} aAccessible accessible object that the action was
-   *    invoked in.
-   * @param {string} aActionName the name of the action, one of the keys in
-   *    {@link gActionMap}.
-   * @return {Array} A one element array with action data.
-   */
-  genForAction: function genForAction(aObject, aActionName) {}, // jshint ignore:line
-
-  /**
-   * Generates output for an announcement.
-   * @param {string} aAnnouncement unlocalized announcement.
-   * @return {Array} An announcement speech data to be localized.
-   */
-  genForAnnouncement: function genForAnnouncement(aAnnouncement) {}, // jshint ignore:line
-
-  /**
-   * Generates output for a tab state change.
-   * @param {nsIAccessible} aAccessible accessible object of the tab's attached
-   *    document.
-   * @param {string} aTabState the tab state name, see
-   *    {@link Presenter.tabStateChanged}.
-   * @return {Array} The tab state utterace.
-   */
-  genForTabStateChange: function genForTabStateChange(aObject, aTabState) {}, // jshint ignore:line
-
-  /**
-   * Generates output for announcing entering and leaving editing mode.
-   * @param {aIsEditing} boolean true if we are in editing mode
-   * @return {Array} The mode utterance
-   */
-  genForEditingMode: function genForEditingMode(aIsEditing) {}, // jshint ignore:line
-
-  _getContextStart: function getContextStart(aContext) {}, // jshint ignore:line
-
-  /**
-   * Adds an accessible name and description to the output if available.
-   * @param {Array} aOutput Output array.
-   * @param {nsIAccessible} aAccessible current accessible object.
-   * @param {Number} aFlags output flags.
-   */
-  _addName: function _addName(aOutput, aAccessible, aFlags) {
-    let name;
-    if ((Utils.getAttributes(aAccessible)["explicit-name"] === "true" &&
-         !(aFlags & IGNORE_EXPLICIT_NAME)) || (aFlags & INCLUDE_NAME)) {
-      name = aAccessible.name;
-    }
-
-    let description = aAccessible.description;
-    if (description) {
-      // Compare against the calculated name unconditionally, regardless of name rule,
-      // so we can make sure we don't speak duplicated descriptions
-      let tmpName = name || aAccessible.name;
-      if (tmpName && (description !== tmpName)) {
-        if (name) {
-          name = this.outputOrder === OUTPUT_DESC_FIRST ?
-            description + " - " + name :
-            name + " - " + description;
-        } else {
-          name = description;
-        }
-      }
-    }
-
-    if (!name || !name.trim()) {
-      return;
-    }
-    aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? "push" : "unshift"](name);
-  },
-
-  /**
-   * Adds a landmark role to the output if available.
-   * @param {Array} aOutput Output array.
-   * @param {nsIAccessible} aAccessible current accessible object.
-   */
-  _addLandmark: function _addLandmark(aOutput, aAccessible) {
-    let landmarkName = Utils.getLandmarkName(aAccessible);
-    if (!landmarkName) {
-      return;
-    }
-    aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? "unshift" : "push"]({
-      string: landmarkName
-    });
-  },
-
-  /**
-   * Adds math roles to the output, for a MathML accessible.
-   * @param {Array} aOutput Output array.
-   * @param {nsIAccessible} aAccessible current accessible object.
-   * @param {String} aRoleStr aAccessible's role string.
-   */
-  _addMathRoles: function _addMathRoles(aOutput, aAccessible, aRoleStr) {
-    // First, determine the actual role to use (e.g. mathmlfraction).
-    let roleStr = aRoleStr;
-    switch (aAccessible.role) {
-      case Roles.MATHML_CELL:
-      case Roles.MATHML_ENCLOSED:
-      case Roles.MATHML_LABELED_ROW:
-      case Roles.MATHML_ROOT:
-      case Roles.MATHML_SQUARE_ROOT:
-      case Roles.MATHML_TABLE:
-      case Roles.MATHML_TABLE_ROW:
-        // Use the default role string.
-        break;
-      case Roles.MATHML_MULTISCRIPTS:
-      case Roles.MATHML_OVER:
-      case Roles.MATHML_SUB:
-      case Roles.MATHML_SUB_SUP:
-      case Roles.MATHML_SUP:
-      case Roles.MATHML_UNDER:
-      case Roles.MATHML_UNDER_OVER:
-        // For scripted accessibles, use the string 'mathmlscripted'.
-        roleStr = "mathmlscripted";
-        break;
-      case Roles.MATHML_FRACTION:
-        // From a semantic point of view, the only important point is to
-        // distinguish between fractions that have a bar and those that do not.
-        // Per the MathML 3 spec, the latter happens iff the linethickness
-        // attribute is of the form [zero-float][optional-unit]. In that case,
-        // we use the string 'mathmlfractionwithoutbar'.
-        let linethickness = Utils.getAttributes(aAccessible).linethickness;
-        if (linethickness) {
-            let numberMatch = linethickness.match(/^(?:\d|\.)+/);
-            if (numberMatch && !parseFloat(numberMatch[0])) {
-                roleStr += "withoutbar";
-            }
-        }
-        break;
-      default:
-        // Otherwise, do not output the actual role.
-        roleStr = null;
-        break;
-    }
-
-    // Get the math role based on the position in the parent accessible
-    // (e.g. numerator for the first child of a mathmlfraction).
-    let mathRole = Utils.getMathRole(aAccessible);
-    if (mathRole) {
-      aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? "push" : "unshift"]({
-        string: this._getOutputName(mathRole)});
-    }
-    if (roleStr) {
-      aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? "push" : "unshift"]({
-        string: this._getOutputName(roleStr)});
-    }
-  },
-
-  /**
-   * Adds MathML menclose notations to the output.
-   * @param {Array} aOutput Output array.
-   * @param {nsIAccessible} aAccessible current accessible object.
-   */
-  _addMencloseNotations: function _addMencloseNotations(aOutput, aAccessible) {
-    let notations = Utils.getAttributes(aAccessible).notation || "longdiv";
-    aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? "push" : "unshift"].apply(
-      aOutput, notations.split(" ").map(notation => {
-        return { string: this._getOutputName("notation-" + notation) };
-      }));
-  },
-
-  /**
-   * Adds an entry type attribute to the description if available.
-   * @param {Array} aOutput Output array.
-   * @param {nsIAccessible} aAccessible current accessible object.
-   * @param {String} aRoleStr aAccessible's role string.
-   */
-  _addType: function _addType(aOutput, aAccessible, aRoleStr) {
-    if (aRoleStr !== "entry") {
-      return;
-    }
-
-    let typeName = Utils.getAttributes(aAccessible)["text-input-type"];
-    // Ignore the the input type="text" case.
-    if (!typeName || typeName === "text") {
-      return;
-    }
-    aOutput.push({string: "textInputType_" + typeName});
-  },
-
-  _addState: function _addState(aOutput, aState, aRoleStr) {}, // jshint ignore:line
-
-  _addRole: function _addRole(aOutput, aAccessible, aRoleStr) {}, // jshint ignore:line
-
-  get outputOrder() {
-    if (!this._utteranceOrder) {
-      this._utteranceOrder = new PrefCache("accessibility.accessfu.utterance");
-    }
-    return typeof this._utteranceOrder.value === "number" ?
-      this._utteranceOrder.value : this.defaultOutputOrder;
-  },
-
-  _getOutputName: function _getOutputName(aName) {
-    return aName.replace(/\s/g, "");
-  },
-
-  roleRuleMap: {
-    "menubar": INCLUDE_DESC,
-    "scrollbar": INCLUDE_DESC,
-    "grip": INCLUDE_DESC,
-    "alert": INCLUDE_DESC | INCLUDE_NAME,
-    "menupopup": INCLUDE_DESC,
-    "menuitem": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "tooltip": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "columnheader": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "rowheader": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "column": NAME_FROM_SUBTREE_RULE,
-    "row": NAME_FROM_SUBTREE_RULE,
-    "cell": INCLUDE_DESC | INCLUDE_NAME,
-    "application": INCLUDE_NAME,
-    "document": INCLUDE_NAME | NAME_FROM_SUBTREE_RULE, // don't use the subtree of entire document
-    "grouping": INCLUDE_DESC | INCLUDE_NAME,
-    "toolbar": INCLUDE_DESC,
-    "table": INCLUDE_DESC | INCLUDE_NAME,
-    "link": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "helpballoon": NAME_FROM_SUBTREE_RULE,
-    "list": INCLUDE_DESC | INCLUDE_NAME,
-    "listitem": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "outline": INCLUDE_DESC,
-    "outlineitem": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "pagetab": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "graphic": INCLUDE_DESC,
-    "switch": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "pushbutton": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "checkbutton": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "radiobutton": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "buttondropdown": NAME_FROM_SUBTREE_RULE,
-    "combobox": INCLUDE_DESC | INCLUDE_VALUE,
-    "droplist": INCLUDE_DESC,
-    "progressbar": INCLUDE_DESC | INCLUDE_VALUE,
-    "slider": INCLUDE_DESC | INCLUDE_VALUE,
-    "spinbutton": INCLUDE_DESC | INCLUDE_VALUE,
-    "diagram": INCLUDE_DESC,
-    "animation": INCLUDE_DESC,
-    "equation": INCLUDE_DESC,
-    "buttonmenu": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "buttondropdowngrid": NAME_FROM_SUBTREE_RULE,
-    "pagetablist": INCLUDE_DESC,
-    "canvas": INCLUDE_DESC,
-    "check menu item": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "label": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "password text": INCLUDE_DESC,
-    "popup menu": INCLUDE_DESC,
-    "radio menu item": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "table column header": NAME_FROM_SUBTREE_RULE,
-    "table row header": NAME_FROM_SUBTREE_RULE,
-    "tear off menu item": NAME_FROM_SUBTREE_RULE,
-    "toggle button": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "parent menuitem": NAME_FROM_SUBTREE_RULE,
-    "header": INCLUDE_DESC,
-    "footer": INCLUDE_DESC,
-    "entry": INCLUDE_DESC | INCLUDE_NAME | INCLUDE_VALUE,
-    "caption": INCLUDE_DESC,
-    "document frame": INCLUDE_DESC,
-    "heading": INCLUDE_DESC,
-    "calendar": INCLUDE_DESC | INCLUDE_NAME,
-    "combobox option": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "listbox option": INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
-    "listbox rich option": NAME_FROM_SUBTREE_RULE,
-    "gridcell": NAME_FROM_SUBTREE_RULE,
-    "check rich option": NAME_FROM_SUBTREE_RULE,
-    "term": NAME_FROM_SUBTREE_RULE,
-    "definition": NAME_FROM_SUBTREE_RULE,
-    "key": NAME_FROM_SUBTREE_RULE,
-    "image map": INCLUDE_DESC,
-    "option": INCLUDE_DESC,
-    "listbox": INCLUDE_DESC,
-    "definitionlist": INCLUDE_DESC | INCLUDE_NAME,
-    "dialog": INCLUDE_DESC | INCLUDE_NAME,
-    "chrome window": IGNORE_EXPLICIT_NAME,
-    "app root": IGNORE_EXPLICIT_NAME,
-    "statusbar": NAME_FROM_SUBTREE_RULE,
-    "mathml table": INCLUDE_DESC | INCLUDE_NAME,
-    "mathml labeled row": NAME_FROM_SUBTREE_RULE,
-    "mathml table row": NAME_FROM_SUBTREE_RULE,
-    "mathml cell": INCLUDE_DESC | INCLUDE_NAME,
-    "mathml fraction": INCLUDE_DESC,
-    "mathml square root": INCLUDE_DESC,
-    "mathml root": INCLUDE_DESC,
-    "mathml enclosed": INCLUDE_DESC,
-    "mathml sub": INCLUDE_DESC,
-    "mathml sup": INCLUDE_DESC,
-    "mathml sub sup": INCLUDE_DESC,
-    "mathml under": INCLUDE_DESC,
-    "mathml over": INCLUDE_DESC,
-    "mathml under over": INCLUDE_DESC,
-    "mathml multiscripts": INCLUDE_DESC,
-    "mathml identifier": INCLUDE_DESC,
-    "mathml number": INCLUDE_DESC,
-    "mathml operator": INCLUDE_DESC,
-    "mathml text": INCLUDE_DESC,
-    "mathml string literal": INCLUDE_DESC,
-    "mathml row": INCLUDE_DESC,
-    "mathml style": INCLUDE_DESC,
-    "mathml error": INCLUDE_DESC },
-
-  mathmlRolesSet: new Set([
-    Roles.MATHML_MATH,
-    Roles.MATHML_IDENTIFIER,
-    Roles.MATHML_NUMBER,
-    Roles.MATHML_OPERATOR,
-    Roles.MATHML_TEXT,
-    Roles.MATHML_STRING_LITERAL,
-    Roles.MATHML_GLYPH,
-    Roles.MATHML_ROW,
-    Roles.MATHML_FRACTION,
-    Roles.MATHML_SQUARE_ROOT,
-    Roles.MATHML_ROOT,
-    Roles.MATHML_FENCED,
-    Roles.MATHML_ENCLOSED,
-    Roles.MATHML_STYLE,
-    Roles.MATHML_SUB,
-    Roles.MATHML_SUP,
-    Roles.MATHML_SUB_SUP,
-    Roles.MATHML_UNDER,
-    Roles.MATHML_OVER,
-    Roles.MATHML_UNDER_OVER,
-    Roles.MATHML_MULTISCRIPTS,
-    Roles.MATHML_TABLE,
-    Roles.LABELED_ROW,
-    Roles.MATHML_TABLE_ROW,
-    Roles.MATHML_CELL,
-    Roles.MATHML_ACTION,
-    Roles.MATHML_ERROR,
-    Roles.MATHML_STACK,
-    Roles.MATHML_LONG_DIVISION,
-    Roles.MATHML_STACK_GROUP,
-    Roles.MATHML_STACK_ROW,
-    Roles.MATHML_STACK_CARRIES,
-    Roles.MATHML_STACK_CARRY,
-    Roles.MATHML_STACK_LINE
-  ]),
-
-  objectOutputFunctions: {
-    _generateBaseOutput:
-      function _generateBaseOutput(aAccessible, aRoleStr, aState, aFlags) {
-        let output = [];
-
-        if (aFlags & INCLUDE_DESC) {
-          this._addState(output, aState, aRoleStr);
-          this._addType(output, aAccessible, aRoleStr);
-          this._addRole(output, aAccessible, aRoleStr);
-        }
-
-        if (aFlags & INCLUDE_VALUE && aAccessible.value.trim()) {
-          output[this.outputOrder === OUTPUT_DESC_FIRST ? "push" : "unshift"](
-            aAccessible.value);
-        }
-
-        this._addName(output, aAccessible, aFlags);
-        this._addLandmark(output, aAccessible);
-
-        return output;
-      },
-
-    label: function label(aAccessible, aRoleStr, aState, aFlags, aContext) {
-      if (aContext.isNestedControl ||
-          aContext.accessible == Utils.getEmbeddedControl(aAccessible)) {
-        // If we are on a nested control, or a nesting label,
-        // we don't need the context.
-        return [];
-      }
-
-      return this.objectOutputFunctions.defaultFunc.apply(this, arguments);
-    },
-
-    entry: function entry(aAccessible, aRoleStr, aState, aFlags) {
-      let rolestr = aState.contains(States.MULTI_LINE) ? "textarea" : "entry";
-      return this.objectOutputFunctions.defaultFunc.apply(
-        this, [aAccessible, rolestr, aState, aFlags]);
-    },
-
-    pagetab: function pagetab(aAccessible, aRoleStr, aState, aFlags) {
-      let itemno = {};
-      let itemof = {};
-      aAccessible.groupPosition({}, itemof, itemno);
-      let output = [];
-      this._addState(output, aState);
-      this._addRole(output, aAccessible, aRoleStr);
-      output.push({
-        string: "objItemOfN",
-        args: [itemno.value, itemof.value]
-      });
-
-      this._addName(output, aAccessible, aFlags);
-      this._addLandmark(output, aAccessible);
-
-      return output;
-    },
-
-    table: function table(aAccessible, aRoleStr, aState, aFlags) {
-      let output = [];
-      let table;
-      try {
-        table = aAccessible.QueryInterface(Ci.nsIAccessibleTable);
-      } catch (x) {
-        Logger.logException(x);
-        return output;
-      } finally {
-        // Check if it's a layout table, and bail out if true.
-        // We don't want to speak any table information for layout tables.
-        if (table.isProbablyForLayout()) {
-          return output;
-        }
-        this._addRole(output, aAccessible, aRoleStr);
-        output.push.call(output, {
-          string: this._getOutputName("tblColumnInfo"),
-          count: table.columnCount
-        }, {
-          string: this._getOutputName("tblRowInfo"),
-          count: table.rowCount
-        });
-        this._addName(output, aAccessible, aFlags);
-        this._addLandmark(output, aAccessible);
-        return output;
-      }
-    },
-
-    gridcell: function gridcell(aAccessible, aRoleStr, aState, aFlags) {
-      let output = [];
-      this._addState(output, aState);
-      this._addName(output, aAccessible, aFlags);
-      this._addLandmark(output, aAccessible);
-      return output;
-    },
-
-    // Use the table output functions for MathML tabular elements.
-    mathmltable: function mathmltable() {
-      return this.objectOutputFunctions.table.apply(this, arguments);
-    },
-
-    mathmlcell: function mathmlcell() {
-      return this.objectOutputFunctions.cell.apply(this, arguments);
-    },
-
-    mathmlenclosed: function mathmlenclosed(aAccessible, aRoleStr, aState,
-                                            aFlags, aContext) {
-      let output = this.objectOutputFunctions.defaultFunc.
-        apply(this, [aAccessible, aRoleStr, aState, aFlags, aContext]);
-      this._addMencloseNotations(output, aAccessible);
-      return output;
-    }
-  }
-};
-
-/**
- * Generates speech utterances from objects, actions and state changes.
- * An utterance is an array of speech data.
- *
- * It should not be assumed that flattening an utterance array would create a
- * gramatically correct sentence. For example, {@link genForObject} might
- * return: ['graphic', 'Welcome to my home page'].
- * Each string element in an utterance should be gramatically correct in itself.
- * Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
- *
- * An utterance is ordered from the least to the most important. Speaking the
- * last string usually makes sense, but speaking the first often won't.
- * For example {@link genForAction} might return ['button', 'clicked'] for a
- * clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
- * not.
- */
-var UtteranceGenerator = {  // jshint ignore:line
-  __proto__: OutputGenerator, // jshint ignore:line
-
-  gActionMap: {
-    jump: "jumpAction",
-    press: "pressAction",
-    check: "checkAction",
-    uncheck: "uncheckAction",
-    on: "onAction",
-    off: "offAction",
-    select: "selectAction",
-    unselect: "unselectAction",
-    open: "openAction",
-    close: "closeAction",
-    switch: "switchAction",
-    click: "clickAction",
-    collapse: "collapseAction",
-    expand: "expandAction",
-    activate: "activateAction",
-    cycle: "cycleAction"
-  },
-
-  // TODO: May become more verbose in the future.
-  genForAction: function genForAction(aObject, aActionName) {
-    return [{string: this.gActionMap[aActionName]}];
-  },
-
-  genForLiveRegion:
-    function genForLiveRegion(aContext, aIsHide, aModifiedText) {
-      let utterance = [];
-      if (aIsHide) {
-        utterance.push({string: "hidden"});
-      }
-      return utterance.concat(aModifiedText || this.genForContext(aContext));
-    },
-
-  genForAnnouncement: function genForAnnouncement(aAnnouncement) {
-    return [{
-      string: aAnnouncement
-    }];
-  },
-
-  genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
-    switch (aTabState) {
-      case "newtab":
-        return [{string: "tabNew"}];
-      case "loading":
-        return [{string: "tabLoading"}];
-      case "loaded":
-        return [aObject.name, {string: "tabLoaded"}];
-      case "loadstopped":
-        return [{string: "tabLoadStopped"}];
-      case "reload":
-        return [{string: "tabReload"}];
-      default:
-        return [];
-    }
-  },
-
-  genForEditingMode: function genForEditingMode(aIsEditing) {
-    return [{string: aIsEditing ? "editingMode" : "navigationMode"}];
-  },
-
-  objectOutputFunctions: {
-
-    __proto__: OutputGenerator.objectOutputFunctions, // jshint ignore:line
-
-    defaultFunc: function defaultFunc() {
-      return this.objectOutputFunctions._generateBaseOutput.apply(
-        this, arguments);
-    },
-
-    heading: function heading(aAccessible, aRoleStr, aState, aFlags) {
-      let level = {};
-      aAccessible.groupPosition(level, {}, {});
-      let utterance = [{string: "headingLevel", args: [level.value]}];
-
-      this._addName(utterance, aAccessible, aFlags);
-      this._addLandmark(utterance, aAccessible);
-
-      return utterance;
-    },
-
-    listitem: function listitem(aAccessible, aRoleStr, aState, aFlags) {
-      let itemno = {};
-      let itemof = {};
-      aAccessible.groupPosition({}, itemof, itemno);
-      let utterance = [];
-      if (itemno.value == 1) {
-        // Start of list
-        utterance.push({string: "listStart"});
-      } else if (itemno.value == itemof.value) {
-        // last item
-        utterance.push({string: "listEnd"});
-      }
-
-      this._addName(utterance, aAccessible, aFlags);
-      this._addLandmark(utterance, aAccessible);
-
-      return utterance;
-    },
-
-    list: function list(aAccessible, aRoleStr, aState, aFlags) {
-      return this._getListUtterance(aAccessible, aRoleStr, aFlags,
-        aAccessible.childCount);
-    },
-
-    definitionlist:
-      function definitionlist(aAccessible, aRoleStr, aState, aFlags) {
-        return this._getListUtterance(aAccessible, aRoleStr, aFlags,
-          aAccessible.childCount / 2);
-      },
-
-    application: function application(aAccessible, aRoleStr, aState, aFlags) {
-      // Don't utter location of applications, it gets tiring.
-      if (aAccessible.name != aAccessible.DOMNode.location) {
-        return this.objectOutputFunctions.defaultFunc.apply(this,
-          [aAccessible, aRoleStr, aState, aFlags]);
-      }
-
-      return [];
-    },
-
-    cell: function cell(aAccessible, aRoleStr, aState, aFlags, aContext) {
-      let utterance = [];
-      let cell = aContext.getCellInfo(aAccessible);
-      if (cell) {
-        let addCellChanged =
-          function addCellChanged(aUtterance, aChanged, aString, aIndex) {
-            if (aChanged) {
-              aUtterance.push({string: aString, args: [aIndex + 1]});
-            }
-          };
-        let addExtent = function addExtent(aUtterance, aExtent, aString) {
-          if (aExtent > 1) {
-            aUtterance.push({string: aString, args: [aExtent]});
-          }
-        };
-        let addHeaders = function addHeaders(aUtterance, aHeaders) {
-          if (aHeaders.length > 0) {
-            aUtterance.push.apply(aUtterance, aHeaders);
-          }
-        };
-
-        addCellChanged(utterance, cell.columnChanged, "columnInfo",
-          cell.columnIndex);
-        addCellChanged(utterance, cell.rowChanged, "rowInfo", cell.rowIndex);
-
-        addExtent(utterance, cell.columnExtent, "spansColumns");
-        addExtent(utterance, cell.rowExtent, "spansRows");
-
-        addHeaders(utterance, cell.columnHeaders);
-        addHeaders(utterance, cell.rowHeaders);
-      }
-
-      this._addName(utterance, aAccessible, aFlags);
-      this._addLandmark(utterance, aAccessible);
-
-      return utterance;
-    },
-
-    columnheader: function columnheader() {
-      return this.objectOutputFunctions.cell.apply(this, arguments);
-    },
-
-    rowheader: function rowheader() {
-      return this.objectOutputFunctions.cell.apply(this, arguments);
-    },
-
-    statictext: function statictext(aAccessible) {
-      if (Utils.isListItemDecorator(aAccessible, true)) {
-        return [];
-      }
-
-      return this.objectOutputFunctions.defaultFunc.apply(this, arguments);
-    }
-  },
-
-  _getContextStart: function _getContextStart(aContext) {
-    return aContext.newAncestry;
-  },
-
-  _addRole: function _addRole(aOutput, aAccessible, aRoleStr) {
-    if (this.mathmlRolesSet.has(aAccessible.role)) {
-      this._addMathRoles(aOutput, aAccessible, aRoleStr);
-    } else {
-      aOutput.push({string: this._getOutputName(aRoleStr)});
-    }
-  },
-
-  /**
-   * Add localized state information to output data.
-   * Note: We do not expose checked and selected states, we let TalkBack do it for us
-   * there. This is because we expose the checked information on the node info itself.
-   */
-  _addState: function _addState(aOutput, aState, aRoleStr) {
-    if (aState.contains(States.UNAVAILABLE)) {
-      aOutput.push({string: "stateUnavailable"});
-    }
-
-    if (aState.contains(States.READONLY)) {
-      aOutput.push({string: "stateReadonly"});
-    }
-
-    if (aState.contains(States.PRESSED)) {
-      aOutput.push({string: "statePressed"});
-    }
-
-    if (aState.contains(States.EXPANDABLE)) {
-      let statetr = aState.contains(States.EXPANDED) ?
-        "stateExpanded" : "stateCollapsed";
-      aOutput.push({string: statetr});
-    }
-
-    if (aState.contains(States.REQUIRED)) {
-      aOutput.push({string: "stateRequired"});
-    }
-
-    if (aState.contains(States.TRAVERSED)) {
-      aOutput.push({string: "stateTraversed"});
-    }
-
-    if (aState.contains(States.HASPOPUP)) {
-      aOutput.push({string: "stateHasPopup"});
-    }
-  },
-
-  _getListUtterance:
-    function _getListUtterance(aAccessible, aRoleStr, aFlags, aItemCount) {
-      let utterance = [];
-      this._addRole(utterance, aAccessible, aRoleStr);
-      utterance.push({
-        string: this._getOutputName("listItemsCount"),
-        count: aItemCount
-      });
-
-      this._addName(utterance, aAccessible, aFlags);
-      this._addLandmark(utterance, aAccessible);
-
-      return utterance;
-    }
-};
deleted file mode 100644
--- a/accessible/jsat/Presentation.jsm
+++ /dev/null
@@ -1,332 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* exported Presentation */
-
-"use strict";
-
-ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "PivotContext", // jshint ignore:line
-  "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "UtteranceGenerator", // jshint ignore:line
-  "resource://gre/modules/accessibility/OutputGenerator.jsm");
-ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
-  "resource://gre/modules/accessibility/Constants.jsm");
-ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
-  "resource://gre/modules/accessibility/Constants.jsm");
-ChromeUtils.defineModuleGetter(this, "AndroidEvents", // jshint ignore:line
-  "resource://gre/modules/accessibility/Constants.jsm");
-
-var EXPORTED_SYMBOLS = ["Presentation"]; // jshint ignore:line
-
-const EDIT_TEXT_ROLES = new Set([
-  Roles.SPINBUTTON, Roles.PASSWORD_TEXT,
-  Roles.AUTOCOMPLETE, Roles.ENTRY, Roles.EDITCOMBOBOX]);
-
-class AndroidPresentor {
-  constructor() {
-    this.type = "Android";
-    this.displayedAccessibles = new WeakMap();
-  }
-
-  /**
-   * The virtual cursor's position changed.
-   * @param {PivotContext} aContext the context object for the new pivot
-   *   position.
-   * @param {int} aReason the reason for the pivot change.
-   *   See nsIAccessiblePivot.
-   * @param {bool} aBoundaryType the boundary type for the text movement
-   * or NO_BOUNDARY if it was not a text movement. See nsIAccessiblePivot.
-   */
-  pivotChanged(aPosition, aOldPosition, aStartOffset, aEndOffset, aReason, aBoundaryType) {
-    let context = new PivotContext(
-      aPosition, aOldPosition, aStartOffset, aEndOffset);
-    if (!context.accessible) {
-      return null;
-    }
-
-    let androidEvents = [];
-
-    const isExploreByTouch = aReason == Ci.nsIAccessiblePivot.REASON_POINT;
-
-    if (isExploreByTouch) {
-      // This isn't really used by TalkBack so this is a half-hearted attempt
-      // for now.
-      androidEvents.push({eventType: AndroidEvents.VIEW_HOVER_EXIT, text: []});
-    }
-
-    if (aPosition != aOldPosition) {
-      let info = this._infoFromContext(context);
-      let eventType = isExploreByTouch ?
-        AndroidEvents.VIEW_HOVER_ENTER :
-        AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED;
-      androidEvents.push({...info, eventType});
-
-      try {
-        context.accessibleForBounds.scrollTo(
-          Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
-      } catch (e) {}
-    }
-
-    if (aBoundaryType != Ci.nsIAccessiblePivot.NO_BOUNDARY) {
-      const adjustedText = context.textAndAdjustedOffsets;
-
-      androidEvents.push({
-        eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
-        text: [adjustedText.text],
-        fromIndex: adjustedText.startOffset,
-        toIndex: adjustedText.endOffset
-      });
-
-      aPosition.QueryInterface(Ci.nsIAccessibleText).scrollSubstringTo(
-        aStartOffset, aEndOffset,
-        Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
-    }
-
-    if (context.accessible) {
-      this.displayedAccessibles.set(context.accessible.document.window, context);
-    }
-
-    return androidEvents;
-  }
-
-  focused(aObject) {
-    let info = this._infoFromContext(
-      new PivotContext(aObject, null, -1, -1, true, false));
-    return [{ eventType: AndroidEvents.VIEW_FOCUSED, ...info }];
-  }
-
-  /**
-   * An object's check action has been invoked.
-   * Note: Checkable objects use TalkBack's text derived from the event state, so we don't
-   * populate the text here.
-   * @param {nsIAccessible} aAccessible the object that has been invoked.
-   */
-  checked(aAccessible) {
-    return [{
-      eventType: AndroidEvents.VIEW_CLICKED,
-      checked: Utils.getState(aAccessible).contains(States.CHECKED)
-    }];
-  }
-
-  /**
-   * An object's select action has been invoked.
-   * @param {nsIAccessible} aAccessible the object that has been invoked.
-   */
-  selected(aAccessible) {
-    return [{
-      eventType: AndroidEvents.VIEW_SELECTED,
-      selected: Utils.getState(aAccessible).contains(States.SELECTED)
-    }];
-  }
-
-  /**
-   * An object's action has been invoked.
-   */
-  actionInvoked() {
-    return [{ eventType: AndroidEvents.VIEW_CLICKED }];
-  }
-
-  /**
-   * Text has changed, either by the user or by the system. TODO.
-   */
-  textChanged(aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
-    let androidEvent = {
-      eventType: AndroidEvents.VIEW_TEXT_CHANGED,
-      text: [aText],
-      fromIndex: aStart,
-      removedCount: 0,
-      addedCount: 0
-    };
-
-    if (aIsInserted) {
-      androidEvent.addedCount = aLength;
-      androidEvent.beforeText =
-        aText.substring(0, aStart) + aText.substring(aStart + aLength);
-    } else {
-      androidEvent.removedCount = aLength;
-      androidEvent.beforeText =
-        aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
-    }
-
-    return [androidEvent];
-  }
-
-  /**
-   * Text selection has changed. TODO.
-   */
-  textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {
-    let androidEvents = [];
-
-    if (aIsFromUserInput) {
-      let [from, to] = aOldStart < aStart ?
-        [aOldStart, aStart] : [aStart, aOldStart];
-      androidEvents.push({
-        eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
-        text: [aText],
-        fromIndex: from,
-        toIndex: to
-      });
-    } else {
-      androidEvents.push({
-        eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
-        text: [aText],
-        fromIndex: aStart,
-        toIndex: aEnd,
-        itemCount: aText.length
-      });
-    }
-
-    return androidEvents;
-  }
-
-  /**
-   * Selection has changed.
-   * XXX: Implement android event?
-   * @param {nsIAccessible} aObject the object that has been selected.
-   */
-  selectionChanged(aObject) {
-    return ["todo.selection-changed"];
-  }
-
-  /**
-   * Name has changed.
-   * XXX: Implement android event?
-   * @param {nsIAccessible} aAccessible the object whose value has changed.
-   */
-  nameChanged(aAccessible) {
-    return ["todo.name-changed"];
-  }
-
-  /**
-   * Value has changed.
-   * XXX: Implement android event?
-   * @param {nsIAccessible} aAccessible the object whose value has changed.
-   */
-  valueChanged(aAccessible) {
-    return ["todo.value-changed"];
-  }
-
-  /**
-   * The tab, or the tab's document state has changed.
-   * @param {nsIAccessible} aDocObj the tab document accessible that has had its
-   *    state changed, or null if the tab has no associated document yet.
-   * @param {string} aPageState the state name for the tab, valid states are:
-   *    'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
-   */
-  tabStateChanged(aDocObj, aPageState) {
-    return this.announce(
-      UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
-  }
-
-  /**
-   * The viewport has changed because of scroll.
-   * @param {Window} aWindow window of viewport that changed.
-   */
-  viewportScrolled(aWindow) {
-    const { windowUtils, devicePixelRatio } = aWindow;
-    const resolution = { value: 1 };
-    windowUtils.getResolution(resolution);
-    const scale = devicePixelRatio * resolution.value;
-    return [{
-      eventType: AndroidEvents.VIEW_SCROLLED,
-      scrollX: aWindow.scrollX * scale,
-      scrollY: aWindow.scrollY * scale,
-      maxScrollX: aWindow.scrollMaxX * scale,
-      maxScrollY: aWindow.scrollMaxY * scale,
-    }];
-  }
-
-  /**
-   * The viewport has changed, either a pan, zoom, or landscape/portrait toggle.
-   * @param {Window} aWindow window of viewport that changed.
-   */
-  viewportChanged(aWindow) {
-    const currentContext = this.displayedAccessibles.get(aWindow);
-    if (!currentContext) {
-      return;
-    }
-
-    const currentAcc = currentContext.accessibleForBounds;
-    if (Utils.isAliveAndVisible(currentAcc)) {
-      return [{
-        eventType: AndroidEvents.WINDOW_CONTENT_CHANGED,
-        bounds: Utils.getBounds(currentAcc)
-      }];
-    }
-  }
-
-  /**
-   * Announce something. Typically an app state change.
-   */
-  announce(aAnnouncement) {
-    let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
-    return [{
-      eventType: AndroidEvents.ANNOUNCEMENT,
-      text: [localizedAnnouncement],
-      addedCount: localizedAnnouncement.length,
-      removedCount: 0,
-      fromIndex: 0
-    }];
-  }
-
-
-  /**
-   * User tried to move cursor forward or backward with no success.
-   * @param {string} aMoveMethod move method that was used (eg. 'moveNext').
-   */
-  noMove(aMoveMethod) {
-    return [{
-      eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
-      exitView: aMoveMethod,
-      text: [""]
-    }];
-  }
-
-  /**
-   * Announce a live region.
-   * @param  {PivotContext} aContext context object for an accessible.
-   * @param  {boolean} aIsPolite A politeness level for a live region.
-   * @param  {boolean} aIsHide An indicator of hide/remove event.
-   * @param  {string} aModifiedText Optional modified text.
-   */
-  liveRegion(aAccessible, aIsPolite, aIsHide, aModifiedText) {
-    let context = !aModifiedText ?
-      new PivotContext(aAccessible, null, -1, -1, true, !!aIsHide) : null;
-    return this.announce(
-      UtteranceGenerator.genForLiveRegion(context, aIsHide, aModifiedText));
-  }
-
-  _infoFromContext(aContext) {
-    const state = Utils.getState(aContext.accessible);
-    const info = {
-      bounds: aContext.bounds,
-      focusable: state.contains(States.FOCUSABLE),
-      focused: state.contains(States.FOCUSED),
-      clickable: aContext.accessible.actionCount > 0,
-      checkable: state.contains(States.CHECKABLE),
-      checked: state.contains(States.CHECKED),
-      editable: state.contains(States.EDITABLE),
-      selected: state.contains(States.SELECTED)
-    };
-
-    if (EDIT_TEXT_ROLES.has(aContext.accessible.role)) {
-      let textAcc = aContext.accessible.QueryInterface(Ci.nsIAccessibleText);
-      return {
-        ...info,
-        className: "android.widget.EditText",
-        hint: aContext.accessible.name,
-        text: [textAcc.getText(0, -1)]
-      };
-    }
-
-    return {
-      ...info,
-      className: "android.view.View",
-      text: Utils.localize(UtteranceGenerator.genForContext(aContext)),
-    };
-  }
-}
-
-const Presentation = new AndroidPresentor();
--- a/accessible/jsat/moz.build
+++ b/accessible/jsat/moz.build
@@ -4,15 +4,13 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXTRA_JS_MODULES.accessibility += [
     'AccessFu.jsm',
     'Constants.jsm',
     'ContentControl.jsm',
     'EventManager.jsm',
-    'OutputGenerator.jsm',
-    'Presentation.jsm',
     'Traversal.jsm',
     'Utils.jsm'
 ]
 
 JAR_MANIFESTS += ['jar.mn']
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -5,24 +5,33 @@ support-files =
   doc_traversal.html
   doc_content_integration.html
   doc_content_text.html
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/moz.png
 
 [test_alive.html]
 [test_content_integration.html]
+skip-if = true
 [test_explicit_names.html]
+skip-if = true
 [test_hints.html]
+skip-if = true
 [test_landmarks.html]
+skip-if = true
 [test_live_regions.html]
+skip-if = true
 [test_output_mathml.html]
+skip-if = true
 [test_output.html]
+skip-if = true
 [test_tables.html]
+skip-if = true
 [test_text_editable_navigation.html]
-skip-if = (verify && !debug && (os == 'linux'))
+skip-if = true
 [test_text_editing.html]
-skip-if = (verify && !debug && (os == 'linux'))
+skip-if = true
 [test_text_navigation_focus.html]
-skip-if = (verify && !debug && (os == 'linux'))
+skip-if = true
 [test_text_navigation.html]
+skip-if = true
 [test_traversal.html]
 [test_traversal_helper.html]
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt
@@ -29,16 +29,17 @@ import android.view.ViewGroup
 import android.widget.EditText
 
 import android.widget.FrameLayout
 
 import org.hamcrest.Matchers.*
 import org.junit.Test
 import org.junit.Before
 import org.junit.After
+import org.junit.Ignore
 import org.junit.runner.RunWith
 
 const val DISPLAY_WIDTH = 480
 const val DISPLAY_HEIGHT = 640
 
 @RunWith(AndroidJUnit4::class)
 @MediumTest
 @WithDisplay(width = DISPLAY_WIDTH, height = DISPLAY_HEIGHT)
@@ -149,26 +150,26 @@ class AccessibilityTest : BaseSessionTes
 
     @Test fun testRootNode() {
         assertThat("provider is not null", provider, notNullValue())
         val node = createNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID)
         assertThat("Root node should have WebView class name",
             node.className.toString(), equalTo("android.webkit.WebView"))
     }
 
-    @Test fun testPageLoad() {
+    @Ignore @Test fun testPageLoad() {
         sessionRule.session.loadTestPath(INPUTS_PATH)
 
         sessionRule.waitUntilCalled(object : EventDelegate {
             @AssertCalled(count = 1)
             override fun onFocused(event: AccessibilityEvent) { }
         })
     }
 
-    @Test fun testAccessibilityFocus() {
+    @Ignore @Test fun testAccessibilityFocus() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID
         sessionRule.session.loadTestPath(INPUTS_PATH)
         waitForInitialFocus()
 
         provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID,
             AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null)
 
         sessionRule.waitUntilCalled(object : EventDelegate {
@@ -188,17 +189,17 @@ class AccessibilityTest : BaseSessionTes
             override fun onAccessibilityFocused(event: AccessibilityEvent) {
                 nodeId = getSourceId(event)
                 val node = createNodeInfo(nodeId)
                 assertThat("Entry node should be focusable", node.isFocusable, equalTo(true))
             }
         })
     }
 
-    @Test fun testTextEntryNode() {
+    @Ignore @Test fun testTextEntryNode() {
         sessionRule.session.loadString("<input aria-label='Name' value='Tobias'>", "text/html")
         waitForInitialFocus()
 
         mainSession.evaluateJS("$('input').focus()")
 
         sessionRule.waitUntilCalled(object : EventDelegate {
             @AssertCalled(count = 1)
             override fun onAccessibilityFocused(event: AccessibilityEvent) {
@@ -270,17 +271,17 @@ class AccessibilityTest : BaseSessionTes
 
     private fun moveByGranularityArguments(granularity: Int, extendSelection: Boolean = false): Bundle {
         val arguments = Bundle(2)
         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, granularity)
         arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, extendSelection)
         return arguments
     }
 
-    @Test fun testClipboard() {
+    @Ignore @Test fun testClipboard() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID;
         sessionRule.session.loadString("<input value='hello cruel world' id='input'>", "text/html")
         waitForInitialFocus()
 
         mainSession.evaluateJS("$('input').focus()")
 
         sessionRule.waitUntilCalled(object : EventDelegate {
             @AssertCalled(count = 1)
@@ -321,17 +322,17 @@ class AccessibilityTest : BaseSessionTes
         sessionRule.waitUntilCalled(object : EventDelegate {
             @AssertCalled
             override fun onTextChanged(event: AccessibilityEvent) {
                 assertThat("text should be pasted", event.text[0].toString(), equalTo("hello cruel cruel cruel"))
             }
         })
     }
 
-    @Test fun testMoveByCharacter() {
+    @Ignore @Test fun testMoveByCharacter() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID
         sessionRule.session.loadTestPath(LOREM_IPSUM_HTML_PATH)
         waitForInitialFocus()
 
         provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID,
                 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null)
 
         sessionRule.waitUntilCalled(object : EventDelegate {
@@ -354,17 +355,17 @@ class AccessibilityTest : BaseSessionTes
         waitUntilTextTraversed(1, 2) // "o"
 
         provider.performAction(nodeId,
                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                 moveByGranularityArguments(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER))
         waitUntilTextTraversed(0, 1) // "L"
     }
 
-    @Test fun testMoveByWord() {
+    @Ignore @Test fun testMoveByWord() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID
         sessionRule.session.loadTestPath(LOREM_IPSUM_HTML_PATH)
         waitForInitialFocus()
 
         provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID,
                 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null)
 
         sessionRule.waitUntilCalled(object : EventDelegate {
@@ -387,17 +388,17 @@ class AccessibilityTest : BaseSessionTes
         waitUntilTextTraversed(6, 11) // "ipsum"
 
         provider.performAction(nodeId,
                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                 moveByGranularityArguments(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD))
         waitUntilTextTraversed(0, 5) // "Lorem"
     }
 
-    @Test fun testMoveByLine() {
+    @Ignore @Test fun testMoveByLine() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID
         sessionRule.session.loadTestPath(LOREM_IPSUM_HTML_PATH)
         waitForInitialFocus()
 
         provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID,
                 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null)
 
         sessionRule.waitUntilCalled(object : EventDelegate {
@@ -420,17 +421,17 @@ class AccessibilityTest : BaseSessionTes
         waitUntilTextTraversed(18, 28) // "sit amet, "
 
         provider.performAction(nodeId,
                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                 moveByGranularityArguments(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE))
         waitUntilTextTraversed(0, 18) // "Lorem ipsum dolor "
     }
 
-    @Test fun testCheckbox() {
+    @Ignore @Test fun testCheckbox() {
         var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID;
         sessionRule.session.loadString("<label><input id='checkbox' type='checkbox'>many option</label>", "text/html")
         waitForInitialFocus()
 
         mainSession.evaluateJS("$('#checkbox').focus()")
         sessionRule.waitUntilCalled(object : EventDelegate {
             @AssertCalled(count = 1)
             override fun onAccessibilityFocused(event: AccessibilityEvent) {
@@ -446,17 +447,17 @@ class AccessibilityTest : BaseSessionTes
 
         provider.performAction(nodeId, AccessibilityNodeInfo.ACTION_CLICK, null)
         waitUntilClick(true)
 
         provider.performAction(nodeId, AccessibilityNodeInfo.ACTION_CLICK, null)
         waitUntilClick(false)
     }
 
-    @Test fun testSelectable() {
+    @Ignore @Test fun testSelectable() {
         var nodeId = View.NO_ID
         sessionRule.session.loadString(
                 """<ul style="list-style-type: none;" role="listbox">
                         <li id="li" role="option" onclick="this.setAttribute('aria-selected',
                             this.getAttribute('aria-selected') == 'true' ? 'false' : 'true')">1</li>
                 </ul>""","text/html")
         waitForInitialFocus()
 
@@ -487,17 +488,17 @@ class AccessibilityTest : BaseSessionTes
 
     private fun screenContainsNode(nodeId: Int): Boolean {
         var node = createNodeInfo(nodeId)
         var nodeBounds = Rect()
         node.getBoundsInScreen(nodeBounds)
         return screenRect.contains(nodeBounds)
     }
 
-    @Test fun testScroll() {
+    @Ignore @Test fun testScroll() {
         var nodeId = View.NO_ID
         sessionRule.session.loadString(
                 """<body style="margin: 0;">
                         <div style="height: 100vh;"></div>
                         <button>Hello</button>
                         <p style="margin: 0;">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                             sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                 </body>""",
@@ -582,17 +583,17 @@ class AccessibilityTest : BaseSessionTes
                 nodeId = getSourceId(event)
                 assertThat("Focused node is onscreen", screenContainsNode(nodeId), equalTo(true))
             }
         })
     }
 
     @ReuseSession(false) // XXX automation crash fix (bug 1485107)
     @WithDevToolsAPI
-    @Test fun autoFill() {
+    @Ignore @Test fun autoFill() {
         // Wait for the accessibility nodes to populate.
         mainSession.loadTestPath(FORMS_HTML_PATH)
         sessionRule.waitUntilCalled(object : EventDelegate {
             // For the root document and the iframe document, each has a form group and
             // a group for inputs outside of forms, so the total count is 4.
             @AssertCalled(count = 4)
             override fun onWinContentChanged(event: AccessibilityEvent) {
             }
@@ -662,17 +663,17 @@ class AccessibilityTest : BaseSessionTes
 
         // Wait on the promises and check for correct values.
         for ((actual, expected) in promises.map { it.value.asJSList<String>() }) {
             assertThat("Auto-filled value must match", actual, equalTo(expected))
         }
     }
 
     @ReuseSession(false) // XXX automation crash fix (bug 1485107)
-    @Test fun autoFill_navigation() {
+    @Ignore @Test fun autoFill_navigation() {
         fun countAutoFillNodes(cond: (AccessibilityNodeInfo) -> Boolean =
                                        { it.className == "android.widget.EditText" },
                                id: Int = View.NO_ID): Int {
             val info = createNodeInfo(id)
             return (if (cond(info)) 1 else 0) + (if (info.childCount > 0)
                 (0 until info.childCount).sumBy {
                     countAutoFillNodes(cond, info.getChildId(it))
                 } else 0)
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -1079,19 +1079,16 @@ public class GeckoSession extends LayerS
         onWindowChanged(WINDOW_CLOSE, /* inProgress */ false);
     }
 
     private void onWindowChanged(int change, boolean inProgress) {
         if ((change == WINDOW_OPEN || change == WINDOW_TRANSFER_IN) && !inProgress) {
             mTextInput.onWindowChanged(mWindow);
         }
         if ((change == WINDOW_CLOSE || change == WINDOW_TRANSFER_OUT) && !inProgress) {
-            if (mAccessibility != null) {
-                mAccessibility.clearAutoFill();
-            }
             mTextInput.clearAutoFill();
         }
     }
 
     /**
      * Get the SessionTextInput instance for this session. May be called on any thread.
      *
      * @return SessionTextInput instance.
@@ -1411,20 +1408,16 @@ public class GeckoSession extends LayerS
      *                false if the session should lose focus.
      *
      * @see #setActive
      */
     public void setFocused(boolean focused) {
         final GeckoBundle msg = new GeckoBundle(1);
         msg.putBoolean("focused", focused);
         mEventDispatcher.dispatch("GeckoView:SetFocused", msg);
-
-        if (focused && mAccessibility != null) {
-            mAccessibility.onWindowFocus();
-        }
     }
 
     /**
      * Class representing a saved session state.
      */
     public static class SessionState implements Parcelable {
         private String mState;
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
@@ -14,147 +14,58 @@ import org.mozilla.gecko.util.EventCallb
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.mozglue.JNIObject;
 
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.text.InputType;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 
 public class SessionAccessibility {
     private static final String LOGTAG = "GeckoAccessibility";
     private static final boolean DEBUG = false;
 
-    // This is a special ID we use for nodes that are event sources.
-    // We expose it as a fragment and not an actual child of the View node.
-    private static final int VIRTUAL_CONTENT_ID = -2;
-
     // This is the number BrailleBack uses to start indexing routing keys.
     private static final int BRAILLE_CLICK_BASE_INDEX = -275000000;
 
     private static final int ACTION_SET_TEXT = 0x200000;
     private static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
 
     /* package */ final class NodeProvider extends AccessibilityNodeProvider {
         @Override
         public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualDescendantId) {
-            AccessibilityNodeInfo info = getAutoFillNode(virtualDescendantId);
-            if (info != null) {
-                // Try auto-fill nodes first.
-                return info;
+            AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(mView, virtualDescendantId);
+            if (Build.VERSION.SDK_INT < 17 || mView.getDisplay() != null) {
+                // When running junit tests we don't have a display
+                mView.onInitializeAccessibilityNodeInfo(node);
             }
-
-            info = (virtualDescendantId == VIRTUAL_CONTENT_ID && mVirtualContentNode != null)
-                   ? AccessibilityNodeInfo.obtain(mVirtualContentNode)
-                   : AccessibilityNodeInfo.obtain(mView, virtualDescendantId);
-
-            switch (virtualDescendantId) {
-            case View.NO_ID:
-                // This is the parent View node.
-                // We intentionally don't add VIRTUAL_CONTENT_ID
-                // as a child. It is a source for events,
-                // but not a member of the tree you
-                // can get to by traversing down.
-                if (Build.VERSION.SDK_INT < 17 || mView.getDisplay() != null) {
-                    // When running junit tests we don't have a display
-                    mView.onInitializeAccessibilityNodeInfo(info);
-                }
-                info.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
-                info.setClassName("android.webkit.WebView"); // TODO: WTF
-
-                if (Build.VERSION.SDK_INT >= 19) {
-                    Bundle bundle = info.getExtras();
-                    bundle.putCharSequence(
-                        "ACTION_ARGUMENT_HTML_ELEMENT_STRING_VALUES",
-                        "ARTICLE,BUTTON,CHECKBOX,COMBOBOX,CONTROL," +
-                        "FOCUSABLE,FRAME,GRAPHIC,H1,H2,H3,H4,H5,H6," +
-                        "HEADING,LANDMARK,LINK,LIST,LIST_ITEM,MAIN," +
-                        "MEDIA,RADIO,SECTION,TABLE,TEXT_FIELD," +
-                        "UNVISITED_LINK,VISITED_LINK");
-                }
-                info.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
-
-                if (mAutoFillRoots != null) {
-                    // Add auto-fill nodes.
-                    if (DEBUG) {
-                        Log.d(LOGTAG, "Adding roots " + mAutoFillRoots);
-                    }
-                    for (int i = 0; i < mAutoFillRoots.size(); i++) {
-                        info.addChild(mView, mAutoFillRoots.keyAt(i));
-                    }
-                }
-                break;
-            default:
-                info.setParent(mView);
-                info.setSource(mView, virtualDescendantId);
-                info.setVisibleToUser(mView.isShown());
-                info.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
-                info.setEnabled(true);
-                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.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
-                info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
-                info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
-                                              AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD |
-                                              AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
-                break;
-            }
-            return info;
+            node.setClassName("android.webkit.WebView");
+            return node;
         }
 
         @Override
-        public boolean performAction(int virtualViewId, int action, Bundle arguments) {
-            if (virtualViewId == View.NO_ID) {
-                return performRootAction(action, arguments);
-            }
-            if (action == AccessibilityNodeInfo.ACTION_SET_TEXT) {
-                final String value = arguments.getString(Build.VERSION.SDK_INT >= 21
-                        ? AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
-                        : ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE);
-                return performAutoFill(virtualViewId, value);
-            }
-            return performContentAction(action, arguments);
-        }
-
-        private boolean performRootAction(int action, Bundle arguments) {
-            switch (action) {
-            case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
-            case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
-                final GeckoBundle data = new GeckoBundle(1);
-                data.putBoolean("gainFocus", action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
-                mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityViewFocused", data);
-                return true;
-            }
-
-            return mView.performAccessibilityAction(action, arguments);
-        }
-
-        @SuppressWarnings("fallthrough")
-        private boolean performContentAction(int action, Bundle arguments) {
+        public boolean performAction(final int virtualViewId, int action, Bundle arguments) {
             final GeckoBundle data;
             switch (action) {
             case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
-                final AccessibilityEvent event = obtainEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, VIRTUAL_CONTENT_ID);
+                final AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+                event.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
+                event.setSource(mView, virtualViewId);
                 ((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
                 return true;
             case AccessibilityNodeInfo.ACTION_CLICK:
                 mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityActivate", null);
                 return true;
             case AccessibilityNodeInfo.ACTION_LONG_CLICK:
                 mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityLongPress", null);
                 return true;
@@ -163,20 +74,16 @@ public class SessionAccessibility {
                 return true;
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
                 mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityScrollBackward", null);
                 return true;
             case AccessibilityNodeInfo.ACTION_SELECT:
                 mSession.getEventDispatcher().dispatch("GeckoView:AccessibilitySelect", null);
                 return true;
             case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT:
-                if (mLastItem) {
-                    return false;
-                }
-                // fall-through
             case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT:
                 if (arguments != null) {
                     data = new GeckoBundle(1);
                     data.putString("rule", arguments.getString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING));
                 } else {
                     data = null;
                 }
                 mSession.getEventDispatcher().dispatch(action == AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT ?
@@ -231,53 +138,23 @@ public class SessionAccessibility {
     };
 
     // Gecko session we are proxying
     /* package */  final GeckoSession mSession;
     // This is the view that delegates accessibility to us. We also sends event through it.
     private View mView;
     // The native portion of the node provider.
     /* package */ final NativeProvider nativeProvider = new NativeProvider();
-    // Have we reached the last item in content?
-    private boolean mLastItem;
-    // Used to store the JSON message and populate the event later in the code path.
-    private AccessibilityNodeInfo mVirtualContentNode;
-    // Auto-fill nodes.
-    private SparseArray<GeckoBundle> mAutoFillNodes;
-    private SparseArray<EventCallback> mAutoFillRoots;
-    private int mAutoFillFocusedId = View.NO_ID;
-    private int mAutoFillFocusedRoot = View.NO_ID;
 
     private boolean mAttached = false;
 
     /* package */ SessionAccessibility(final GeckoSession session) {
         mSession = session;
 
         Settings.updateAccessibilitySettings();
-
-        session.getEventDispatcher().registerUiThreadListener(new BundleEventListener() {
-                @Override
-                public void handleMessage(final String event, final GeckoBundle message,
-                                          final EventCallback callback) {
-                    if ("GeckoView:AccessibilityEvent".equals(event)) {
-                        sendAccessibilityEvent(message);
-                    } else if ("GeckoView:AddAutoFill".equals(event)) {
-                        addAutoFill(message, callback);
-                    } else if ("GeckoView:ClearAutoFill".equals(event)) {
-                        clearAutoFill();
-                    } else if ("GeckoView:OnAutoFillFocus".equals(event)) {
-                        onAutoFillFocus(message);
-                    }
-                }
-            },
-            "GeckoView:AccessibilityEvent",
-            "GeckoView:AddAutoFill",
-            "GeckoView:ClearAutoFill",
-            "GeckoView:OnAutoFillFocus",
-            null);
     }
 
     /**
       * Get the View instance that delegates accessibility to this session.
       *
       * @return View instance.
       */
     public View getView() {
@@ -290,17 +167,16 @@ public class SessionAccessibility {
       * @param view View instance.
       */
     public void setView(final View view) {
         if (mView != null) {
             mView.setAccessibilityDelegate(null);
         }
 
         mView = view;
-        mLastItem = false;
 
         if (mView == null) {
             return;
         }
 
         mView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
             private NodeProvider mProvider;
 
@@ -382,174 +258,16 @@ public class SessionAccessibility {
             ret.putBoolean("enabled", isTouchExplorationEnabled());
             // "GeckoView:AccessibilitySettings" is dispatched to the Gecko thread.
             EventDispatcher.getInstance().dispatch("GeckoView:AccessibilitySettings", ret);
             // "GeckoView:AccessibilityEnabled" is dispatched to the UI thread.
             EventDispatcher.getInstance().dispatch("GeckoView:AccessibilityEnabled", ret);
         }
     }
 
-    private AccessibilityEvent obtainEvent(final int eventType, final int sourceId) {
-        AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-        event.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
-        event.setSource(mView, sourceId);
-
-        return event;
-    }
-
-    private static void populateEventFromJSON(AccessibilityEvent event, final GeckoBundle message) {
-        final String[] textArray = message.getStringArray("text");
-        if (textArray != null) {
-            for (int i = 0; i < textArray.length; i++)
-                event.getText().add(textArray[i] != null ? textArray[i] : "");
-        }
-
-        if (message.containsKey("className"))
-            event.setClassName(message.getString("className"));
-        event.setContentDescription(message.getString("description", ""));
-        event.setEnabled(message.getBoolean("enabled", true));
-        event.setChecked(message.getBoolean("checked"));
-        event.setPassword(message.getBoolean("password"));
-        event.setAddedCount(message.getInt("addedCount", -1));
-        event.setRemovedCount(message.getInt("removedCount", -1));
-        event.setFromIndex(message.getInt("fromIndex", -1));
-        event.setItemCount(message.getInt("itemCount", -1));
-        event.setCurrentItemIndex(message.getInt("currentItemIndex", -1));
-        event.setBeforeText(message.getString("beforeText", ""));
-        event.setToIndex(message.getInt("toIndex", -1));
-        event.setScrollable(message.getBoolean("scrollable"));
-        event.setScrollX(message.getInt("scrollX", -1));
-        event.setScrollY(message.getInt("scrollY", -1));
-        event.setMaxScrollX(message.getInt("maxScrollX", -1));
-        event.setMaxScrollY(message.getInt("maxScrollY", -1));
-    }
-
-    private void populateNodeInfoFromJSON(AccessibilityNodeInfo node, final GeckoBundle message) {
-        node.setEnabled(message.getBoolean("enabled", true));
-        node.setCheckable(message.getBoolean("checkable"));
-        node.setChecked(message.getBoolean("checked"));
-        node.setPassword(message.getBoolean("password"));
-        node.setFocusable(message.getBoolean("focusable"));
-        node.setFocused(message.getBoolean("focused"));
-        node.setSelected(message.getBoolean("selected"));
-
-        node.setClassName(message.getString("className", "android.view.View"));
-
-        final String[] textArray = message.getStringArray("text");
-        StringBuilder sb = new StringBuilder();
-        if (textArray != null && textArray.length > 0) {
-            sb.append(textArray[0] != null ? textArray[0] : "");
-            for (int i = 1; i < textArray.length; i++) {
-                sb.append(' ').append(textArray[i] != null ? textArray[i] : "");
-            }
-            node.setText(sb.toString());
-        }
-        node.setContentDescription(message.getString("description", ""));
-
-        if (Build.VERSION.SDK_INT >= 18 && message.getBoolean("editable")) {
-            node.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
-            node.addAction(AccessibilityNodeInfo.ACTION_CUT);
-            node.addAction(AccessibilityNodeInfo.ACTION_COPY);
-            node.addAction(AccessibilityNodeInfo.ACTION_PASTE);
-            node.setEditable(true);
-        }
-
-        if (message.getBoolean("clickable")) {
-            node.setClickable(true);
-            node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
-        }
-
-        if (Build.VERSION.SDK_INT >= 19 && message.containsKey("hint")) {
-            Bundle bundle = node.getExtras();
-            bundle.putCharSequence("AccessibilityNodeInfo.hint", message.getString("hint"));
-        }
-    }
-
-    private void updateBounds(final AccessibilityNodeInfo node, final GeckoBundle message) {
-        final GeckoBundle bounds = message.getBundle("bounds");
-        if (bounds == null) {
-            return;
-        }
-
-        Rect screenBounds = new Rect(bounds.getInt("left"), bounds.getInt("top"),
-                                     bounds.getInt("right"), bounds.getInt("bottom"));
-        node.setBoundsInScreen(screenBounds);
-
-        final Matrix matrix = new Matrix();
-        final float[] origin = new float[2];
-        mSession.getClientToScreenMatrix(matrix);
-        matrix.mapPoints(origin);
-
-        screenBounds.offset((int) -origin[0], (int) -origin[1]);
-        node.setBoundsInParent(screenBounds);
-    }
-
-    private void updateState(final AccessibilityNodeInfo node, final GeckoBundle message) {
-        if (message.containsKey("checked")) {
-            node.setChecked(message.getBoolean("checked"));
-        }
-        if (message.containsKey("selected")) {
-            node.setSelected(message.getBoolean("selected"));
-        }
-    }
-
-    private void sendAccessibilityEvent(final GeckoBundle message) {
-        if (mView == null || !Settings.isTouchExplorationEnabled())
-            return;
-
-        final int eventType = message.getInt("eventType", -1);
-        if (eventType < 0) {
-            Log.e(LOGTAG, "No accessibility event type provided");
-            return;
-        }
-
-        int eventSource = VIRTUAL_CONTENT_ID;
-
-        if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
-            final String exitView = message.getString("exitView", "");
-
-            mLastItem = exitView.equals("moveNext");
-            if (mLastItem) {
-                return;
-            }
-
-            if (exitView.equals("movePrevious")) {
-                eventSource = View.NO_ID;
-            }
-        }
-
-        if (eventSource != View.NO_ID &&
-                (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED ||
-                 eventType == AccessibilityEvent.TYPE_VIEW_FOCUSED ||
-                 eventType == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)) {
-            // In Jelly Bean we populate an AccessibilityNodeInfo with the minimal amount of data to have
-            // it work with TalkBack.
-            if (mVirtualContentNode != null) {
-                mVirtualContentNode.recycle();
-            }
-            mVirtualContentNode = AccessibilityNodeInfo.obtain(mView, eventSource);
-            populateNodeInfoFromJSON(mVirtualContentNode, message);
-        }
-
-        if (mVirtualContentNode != null) {
-            // Bounds for the virtual content can be updated from any event.
-            updateBounds(mVirtualContentNode, message);
-
-            // State for the virtual content can be updated when view is clicked/selected.
-            if (eventType == AccessibilityEvent.TYPE_VIEW_CLICKED ||
-                eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) {
-                updateState(mVirtualContentNode, message);
-            }
-        }
-
-        final AccessibilityEvent accessibilityEvent = obtainEvent(eventType, eventSource);
-        populateEventFromJSON(accessibilityEvent, message);
-        ((ViewParent) mView).requestSendAccessibilityEvent(mView, accessibilityEvent);
-    }
-
     public boolean onMotionEvent(final MotionEvent event) {
         if (!Settings.isTouchExplorationEnabled()) {
             return false;
         }
 
         if (event.getSource() != InputDevice.SOURCE_TOUCHSCREEN) {
             return false;
         }
@@ -562,255 +280,16 @@ public class SessionAccessibility {
         }
 
         final GeckoBundle data = new GeckoBundle(2);
         data.putDoubleArray("coordinates", new double[] {event.getRawX(), event.getRawY()});
         mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityExploreByTouch", data);
         return true;
     }
 
-    /* package */ AccessibilityNodeInfo getAutoFillNode(final int id) {
-        if (mView == null || mAutoFillRoots == null) {
-            return null;
-        }
-
-        final GeckoBundle bundle = mAutoFillNodes.get(id);
-        if (bundle == null) {
-            return null;
-        }
-
-        if (DEBUG) {
-            Log.d(LOGTAG, "getAutoFillNode(" + id + ')');
-        }
-
-        final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(mView, id);
-        node.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
-        node.setParent(mView, bundle.getInt("parent", View.NO_ID));
-        node.setEnabled(true);
-
-        if (mAutoFillFocusedRoot != View.NO_ID &&
-                mAutoFillFocusedRoot == bundle.getInt("root", View.NO_ID)) {
-            // Some auto-fill clients require a dummy rect for the focused View.
-            final Rect rect = new Rect();
-            mSession.getSurfaceBounds(rect);
-            node.setVisibleToUser(!rect.isEmpty());
-            node.setBoundsInParent(rect);
-
-            final int[] offset = new int[2];
-            mView.getLocationOnScreen(offset);
-            rect.offset(offset[0], offset[1]);
-            node.setBoundsInScreen(rect);
-        }
-
-        final GeckoBundle[] children = bundle.getBundleArray("children");
-        if (children != null) {
-            for (final GeckoBundle child : children) {
-                final int childId = child.getInt("id");
-                node.addChild(mView, childId);
-                mAutoFillNodes.append(childId, child);
-            }
-        }
-
-        String tag = bundle.getString("tag", "");
-        final String type = bundle.getString("type", "text");
-        final GeckoBundle attrs = bundle.getBundle("attributes");
-
-        if ("INPUT".equals(tag) && !bundle.getBoolean("editable", false)) {
-            tag = ""; // Don't process non-editable inputs (e.g. type="button").
-        }
-        switch (tag) {
-            case "INPUT":
-            case "TEXTAREA": {
-                final boolean disabled = bundle.getBoolean("disabled");
-                node.setClassName("android.widget.EditText");
-                node.setEnabled(!disabled);
-                node.setFocusable(!disabled);
-                node.setFocused(id == mAutoFillFocusedId);
-
-                if ("password".equals(type)) {
-                    node.setPassword(true);
-                }
-                if (Build.VERSION.SDK_INT >= 18) {
-                    node.setEditable(!disabled);
-                }
-                if (Build.VERSION.SDK_INT >= 19) {
-                    node.setMultiLine("TEXTAREA".equals(tag));
-                }
-                if (Build.VERSION.SDK_INT >= 21) {
-                    try {
-                        node.setMaxTextLength(Integer.parseInt(
-                                String.valueOf(attrs.get("maxlength"))));
-                    } catch (final NumberFormatException ignore) {
-                    }
-                }
-
-                if (!disabled) {
-                    if (Build.VERSION.SDK_INT >= 21) {
-                        node.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
-                    } else {
-                        node.addAction(ACTION_SET_TEXT);
-                    }
-                }
-                break;
-            }
-            default:
-                if (children != null) {
-                    node.setClassName("android.view.ViewGroup");
-                } else {
-                    node.setClassName("android.view.View");
-                }
-                break;
-        }
-
-        if (Build.VERSION.SDK_INT >= 19 && "INPUT".equals(tag)) {
-            switch (type) {
-                case "email":
-                    node.setInputType(InputType.TYPE_CLASS_TEXT |
-                                      InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS);
-                    break;
-                case "number":
-                    node.setInputType(InputType.TYPE_CLASS_NUMBER);
-                    break;
-                case "password":
-                    node.setInputType(InputType.TYPE_CLASS_TEXT |
-                                      InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD);
-                    break;
-                case "tel":
-                    node.setInputType(InputType.TYPE_CLASS_PHONE);
-                    break;
-                case "text":
-                    node.setInputType(InputType.TYPE_CLASS_TEXT |
-                                      InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
-                    break;
-                case "url":
-                    node.setInputType(InputType.TYPE_CLASS_TEXT |
-                                      InputType.TYPE_TEXT_VARIATION_URI);
-                    break;
-            }
-        }
-        return node;
-    }
-
-    /* package */ boolean performAutoFill(final int id, final String value) {
-        if (mAutoFillRoots == null) {
-            return false;
-        }
-
-        int rootId = id;
-        for (int currentId = id; currentId != View.NO_ID;) {
-            final GeckoBundle bundle = mAutoFillNodes.get(currentId);
-            if (bundle == null) {
-                return false;
-            }
-            rootId = currentId;
-            currentId = bundle.getInt("parent", View.NO_ID);
-        }
-
-        if (DEBUG) {
-            Log.d(LOGTAG, "performAutoFill(" + id + ')');
-        }
-
-        final EventCallback callback = mAutoFillRoots.get(rootId);
-        if (callback == null) {
-            return false;
-        }
-
-        final GeckoBundle response = new GeckoBundle(1);
-        response.putString(String.valueOf(id), value);
-        callback.sendSuccess(response);
-        return true;
-    }
-
-    private void fireWindowChangedEvent(final int id) {
-        if (Settings.isEnabled() && mView instanceof ViewParent) {
-            final AccessibilityEvent event = obtainEvent(
-                    AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, id);
-            if (Build.VERSION.SDK_INT >= 19) {
-                event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
-            }
-            ((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
-        }
-    }
-
-    /* package */ void addAutoFill(final GeckoBundle message, final EventCallback callback) {
-        if (!Settings.isEnabled()) {
-            return;
-        }
-
-        if (mAutoFillRoots == null) {
-            mAutoFillRoots = new SparseArray<>();
-            mAutoFillNodes = new SparseArray<>();
-        }
-
-        final int id = message.getInt("id");
-        if (DEBUG) {
-            Log.d(LOGTAG, "addAutoFill(" + id + ')');
-        }
-
-        mAutoFillRoots.append(id, callback);
-        mAutoFillNodes.append(id, message);
-        fireWindowChangedEvent(id);
-    }
-
-    /* package */ void clearAutoFill() {
-        if (mAutoFillRoots != null) {
-            if (DEBUG) {
-                Log.d(LOGTAG, "clearAutoFill()");
-            }
-            mAutoFillRoots = null;
-            mAutoFillNodes = null;
-            mAutoFillFocusedId = View.NO_ID;
-            mAutoFillFocusedRoot = View.NO_ID;
-            fireWindowChangedEvent(View.NO_ID);
-        }
-    }
-
-    /* package */ void onAutoFillFocus(final GeckoBundle message) {
-        if (!Settings.isEnabled() || !(mView instanceof ViewParent) || mAutoFillNodes == null) {
-            return;
-        }
-
-        final int id;
-        final int root;
-        if (message != null) {
-            id = message.getInt("id");
-            root = message.getInt("root");
-        } else {
-            id = root = View.NO_ID;
-        }
-
-        if (DEBUG) {
-            Log.d(LOGTAG, "onAutoFillFocus(" + id + ')');
-        }
-        if (mAutoFillFocusedId == id) {
-            return;
-        }
-        mAutoFillFocusedId = id;
-        mAutoFillFocusedRoot = root;
-
-        // We already send "TYPE_VIEW_FOCUSED" in touch exploration mode,
-        // so in that case don't send it here.
-        if (!Settings.isTouchExplorationEnabled()) {
-            AccessibilityEvent event = obtainEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED, id);
-            ((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
-        }
-    }
-
-    /* package */ void onWindowFocus() {
-        // Auto-fill clients expect a state change event on focus.
-        if (Settings.isEnabled() && mView instanceof ViewParent) {
-            if (DEBUG) {
-                Log.d(LOGTAG, "onWindowFocus()");
-            }
-            final AccessibilityEvent event = obtainEvent(
-                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, View.NO_ID);
-            ((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
-        }
-    }
-
     /* package */ final class NativeProvider extends JNIObject {
         @WrapForJNI(calledFrom = "ui")
         private void setAttached(final boolean attached) {
             mAttached = attached;
         }
 
         @Override // JNIObject
         protected void disposeNative() {