Bug 1331154 - 4. Notify browser.js when a tab gets moved. r?sebastian draft
authorTom Klein <twointofive@gmail.com>
Thu, 02 Feb 2017 21:02:51 -0600
changeset 479993 149f0ae8cccd82ea287691b15af24077d120aacf
parent 479992 c8d13a86bb0b54d7d025b729c70ba776085066bf
child 479994 21fcffb9254785bd4ac9ba4004986533c3e29fdf
push id44428
push userbmo:twointofive@gmail.com
push dateTue, 07 Feb 2017 17:59:56 +0000
reviewerssebastian
bugs1331154
milestone54.0a1
Bug 1331154 - 4. Notify browser.js when a tab gets moved. r?sebastian Session store will be notified in the next patch. MozReview-Commit-ID: APTJykdnMF2
mobile/android/base/java/org/mozilla/gecko/Tabs.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -1106,27 +1106,29 @@ public class Tabs implements BundleEvent
         if (fromPositionHint == toPositionHint) {
             return;
         }
 
         // The provided position hints index into either all private tabs or all non-private tabs,
         // but we need the indices with respect to mOrder, which lists all tabs, both private and
         // non-private, in the order in which they were added.
 
+        // The positions in mOrder of the from and to tabs.
+        final int fromPosition;
+        final int toPosition;
         synchronized (this) {
-            final int fromPosition;
             if (tabPositionCache.mTabId == fromTabId) {
                 fromPosition = tabPositionCache.mOrderPosition;
             } else {
                 fromPosition = getOrderPositionForTab(fromTabId, fromPositionHint, true);
             }
 
             // Start the toPosition search from the mOrder from position.
             final int adjustedToPositionHint = fromPosition + (toPositionHint - fromPositionHint);
-            final int toPosition = getOrderPositionForTab(toTabId, adjustedToPositionHint, fromPositionHint < toPositionHint);
+            toPosition = getOrderPositionForTab(toTabId, adjustedToPositionHint, fromPositionHint < toPositionHint);
             // Remember where the tab was moved to so that if this move continues we'll be ready.
             tabPositionCache.cache(fromTabId, toPosition);
 
             if (fromPosition == -1 || toPosition == -1) {
                 throw new IllegalStateException("Tabs search failed: (" + fromPositionHint + ", " + toPositionHint + ")" +
                         " --> (" + fromPosition + ", " + toPosition + ")");
             }
 
@@ -1143,16 +1145,23 @@ public class Tabs implements BundleEvent
             // and hence no way (short of synchronizing all readers of mOrder) to prevent readers on
             // other threads from possibly choosing to start iterating mOrder in between when we
             // might mOrder.clear() and then mOrder.addAll(newTabsArray) if we were to repopulate
             // mOrder in place.)
             mOrder = new CopyOnWriteArrayList<>(newTabsList);
         }
 
         queuePersistAllTabs();
+
+        final GeckoBundle data = new GeckoBundle();
+        data.putInt("fromTabId", fromTabId);
+        data.putInt("fromPosition", fromPosition);
+        data.putInt("toTabId", toTabId);
+        data.putInt("toPosition", toPosition);
+        EventDispatcher.getInstance().dispatch("Tab:Move", data);
     }
 
     static public void moveTabInList(List<Tab> tabsList, int fromPosition, int toPosition) {
         final Tab movedTab = tabsList.get(fromPosition);
         final int step = (fromPosition < toPosition) ? 1 : -1;
         for (int i = fromPosition; i != toPosition; i += step) {
             tabsList.set(i, tabsList.get(i + step));
         }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -380,16 +380,17 @@ var BrowserApp = {
     ViewportHandler.init();
 
     Services.androidBridge.browserApp = this;
 
     GlobalEventDispatcher.registerListener(this, [
       "Tab:Load",
       "Tab:Selected",
       "Tab:Closed",
+      "Tab:Move",
       "Browser:LoadManifest",
       "Session:GetHistory",
       "Session:Reload",
     ]);
 
     Services.obs.addObserver(this, "Locale:OS", false);
     Services.obs.addObserver(this, "Locale:Changed", false);
     Services.obs.addObserver(this, "Session:Back", false);
@@ -1288,16 +1289,32 @@ var BrowserApp = {
         });
       }
     }
 
     aTab.destroy();
     this._tabs.splice(tabIndex, 1);
   },
 
+  _handleTabMove(fromTabId, fromPosition, toTabId, toPosition) {
+    let movedTab = this._tabs[fromPosition];
+    if (movedTab.id != fromTabId || this._tabs[toPosition].id != toTabId) {
+      // The gecko and/or java Tabs tabs lists changed sometime between when the Tabs list was
+      // updated and when news of the update arrived here.
+      throw "Moved tab mismatch: (" + fromTabId + ", " + movedTab.id + "), " +
+            "(" + toTabId + ", " + this._tabs[toPosition].id + ")";
+    }
+
+    let step = (fromPosition < toPosition) ? 1 : -1;
+    for (let i = fromPosition; i != toPosition; i += step) {
+      this._tabs[i] = this._tabs[i + step];
+    }
+    this._tabs[toPosition] = movedTab;
+  },
+
   // Use this method to select a tab from JS. This method sends a message
   // to Java to select the tab in the Java UI (we'll get a Tab:Selected message
   // back from Java when that happens).
   selectTab: function selectTab(aTab) {
     if (!aTab) {
       Cu.reportError("Error trying to select tab (tab doesn't exist)");
       return;
     }
@@ -1751,16 +1768,20 @@ var BrowserApp = {
       case "Tab:Selected":
         this._handleTabSelected(this.getTabForId(data.id));
         break;
 
       case "Tab:Closed": {
         this._handleTabClosed(this.getTabForId(data.tabId), data.showUndoToast);
         break;
       }
+
+      case "Tab:Move":
+        this._handleTabMove(data.fromTabId, data.fromPosition, data.toTabId, data.toPosition);
+        break;
     }
   },
 
   observe: function(aSubject, aTopic, aData) {
     let browser = this.selectedBrowser;
 
     switch (aTopic) {
       case "Session:Back":