Bug 797075 - Part 2: Implement Java-side tab stubs. r=mfinkle
authorBrian Nicholson <bnicholson@mozilla.com>
Fri, 05 Oct 2012 14:53:44 -0700
changeset 109770 b4989f34fdf7c09237e0ce05f1875f79d5bc6672
parent 109769 3e0deee3c6fda70397d668c3013098ba6aaafdf7
child 109771 093b6818007cc43fd416c6ddf06f7fa637da582b
push id23652
push userryanvm@gmail.com
push dateWed, 10 Oct 2012 01:10:20 +0000
treeherdermozilla-central@5cca0408a73f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs797075
milestone19.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 797075 - Part 2: Implement Java-side tab stubs. r=mfinkle
mobile/android/base/Tabs.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -16,16 +16,17 @@ import android.content.Intent;
 import android.os.SystemClock;
 import android.util.Log;
 import android.widget.Toast;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class Tabs implements GeckoEventListener {
     private static final String LOGTAG = "GeckoTabs";
 
     private Tab mSelectedTab;
     private final HashMap<Integer, Tab> mTabs = new HashMap<Integer, Tab>();
     private final CopyOnWriteArrayList<Tab> mOrder = new CopyOnWriteArrayList<Tab>();
     private boolean mRestoringSession;
@@ -36,16 +37,18 @@ public class Tabs implements GeckoEventL
     public static final int LOADURL_NONE = 0;
     public static final int LOADURL_NEW_TAB = 1;
     public static final int LOADURL_USER_ENTERED = 2;
 
     private static final int SCORE_INCREMENT_TAB_LOCATION_CHANGE = 5;
     private static final int SCORE_INCREMENT_TAB_SELECTED = 10;
     private static final int SCORE_THRESHOLD = 30;
 
+    private static AtomicInteger sTabId = new AtomicInteger(0);
+
     private GeckoApp mActivity;
 
     private Tabs() {
         registerEventListener("SessionHistory:New");
         registerEventListener("SessionHistory:Back");
         registerEventListener("SessionHistory:Forward");
         registerEventListener("SessionHistory:Goto");
         registerEventListener("SessionHistory:Purge");
@@ -63,27 +66,17 @@ public class Tabs implements GeckoEventL
     public void attachToActivity(GeckoApp activity) {
         mActivity = activity;
     }
 
     public int getCount() {
         return mTabs.size();
     }
 
-    private Tab addTab(JSONObject params) throws JSONException {
-        int id = params.getInt("tabID");
-        if (mTabs.containsKey(id))
-           return mTabs.get(id);
-
-        // null strings return "null" (http://code.google.com/p/android/issues/detail?id=13830)
-        String url = params.isNull("uri") ? null : params.getString("uri");
-        Boolean external = params.getBoolean("external");
-        int parentId = params.getInt("parentId");
-        String title = params.getString("title");
-
+    private Tab addTab(int id, String url, boolean external, int parentId, String title) {
         final Tab tab = new Tab(id, url, external, parentId, title);
         mTabs.put(id, tab);
         mOrder.add(tab);
 
         if (!mRestoringSession) {
             mActivity.runOnUiThread(new Runnable() {
                 public void run() {
                     notifyListeners(tab, TabEvents.ADDED);
@@ -240,17 +233,30 @@ public class Tabs implements GeckoEventL
             if (event.startsWith("SessionHistory:")) {
                 Tab tab = getTab(message.getInt("tabID"));
                 if (tab != null) {
                     event = event.substring("SessionHistory:".length());
                     tab.handleSessionHistoryMessage(event, message);
                 }
             } else if (event.equals("Tab:Added")) {
                 Log.i(LOGTAG, "Received message from Gecko: " + SystemClock.uptimeMillis() + " - Tab:Added");
-                Tab tab = addTab(message);
+
+                int id = message.getInt("tabID");
+                Tab tab = null;
+
+                if (mTabs.containsKey(id)) {
+                    tab = mTabs.get(id);
+                } else {
+                    tab = addTab(id,
+                                 message.isNull("uri") ? null : message.getString("uri"),
+                                 message.getBoolean("external"),
+                                 message.getInt("parentId"),
+                                 message.getString("title"));
+                }
+
                 if (message.getBoolean("selected"))
                     selectTab(tab.getId());
                 if (message.getBoolean("delayLoad"))
                     tab.setState(Tab.STATE_DELAYED);
                 if (message.getBoolean("desktopMode"))
                     tab.setDesktopMode(true);
             } else if (event.equals("Tab:Close")) {
                 Tab tab = getTab(message.getInt("tabID"));
@@ -441,28 +447,40 @@ public class Tabs implements GeckoEventL
      * @param url          URL of page to load, or search term used if searchEngine is given
      * @param searchEngine if given, the search engine with this name is used
      *                     to search for the url string; if null, the URL is loaded directly
      * @param parentId     ID of this tab's parent, or -1 if it has no parent
      * @param flags        flags used to load tab
      */
     public void loadUrl(String url, String searchEngine, int parentId, int flags) {
         JSONObject args = new JSONObject();
+        int tabId = -1;
+
         try {
             args.put("url", url);
             args.put("engine", searchEngine);
             args.put("parentId", parentId);
             args.put("userEntered", (flags & LOADURL_USER_ENTERED) != 0);
             args.put("newTab", (flags & LOADURL_NEW_TAB) != 0);
+
+            if ((flags & LOADURL_NEW_TAB) != 0) {
+                tabId = getNextTabId();
+                args.put("tabID", tabId);
+                addTab(tabId, null, false, parentId, url);
+            }
         } catch (Exception e) {
             Log.e(LOGTAG, "error building JSON arguments");
         }
 
         Log.d(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Load");
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
+
+        if (tabId != -1) {
+            selectTab(tabId);
+        }
     }
 
     /**
      * Open the url as a new tab, and mark the selected tab as its "parent".
      *
      * If the url is already open in a tab, the existing tab is selected.
      * Use this for tabs opened by the browser chrome, so users can press the
      * "Back" button to return to the previous tab.
@@ -475,9 +493,18 @@ public class Tabs implements GeckoEventL
             if (url.equals(tab.getURL())) {
                 selectTab(tab.getId());
                 return;
             }
         }
 
         loadUrl(url, null, getSelectedTab().getId(), LOADURL_NEW_TAB);
     }
+
+    /**
+     * Gets the next tab ID.
+     *
+     * This method is invoked via JNI.
+     */
+    public static int getNextTabId() {
+        return sTabId.getAndIncrement();
+    }
 }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -8,16 +8,17 @@ let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 let Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/JNI.jsm");
 
 #ifdef ACCESSIBILITY
 Cu.import("resource://gre/modules/accessibility/AccessFu.jsm");
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "PluralForm", function() {
   Cu.import("resource://gre/modules/PluralForm.jsm");
   return PluralForm;
@@ -1082,17 +1083,18 @@ var BrowserApp = {
       // inheriting the currently loaded document's principal.
       let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
       if (data.userEntered)
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
 
       let params = {
         selected: true,
         parentId: ("parentId" in data) ? data.parentId : -1,
-        flags: flags
+        flags: flags,
+        tabID: data.tabID
       };
 
       let url = data.url;
       if (data.engine) {
         let engine = Services.search.getEngineByName(data.engine);
         if (engine) {
           let submission = engine.getSubmission(url);
           url = submission.uri.spec;
@@ -2232,18 +2234,16 @@ nsBrowserAccess.prototype = {
   },
 
   isTabContentWindow: function(aWindow) {
     return BrowserApp.getBrowserForWindow(aWindow) != null;
   }
 };
 
 
-let gTabIDFactory = 0;
-
 // track the last known screen size so that new tabs
 // get created with the right size rather than being 1x1
 let gScreenWidth = 1;
 let gScreenHeight = 1;
 
 function Tab(aURL, aParams) {
   this.browser = null;
   this.id = 0;
@@ -2289,17 +2289,26 @@ Tab.prototype = {
 
     // only set tab uri if uri is valid
     let uri = null;
     try {
       uri = Services.io.newURI(aURL, null, null).spec;
     } catch (e) {}
 
     if (!aParams.zombifying) {
-      this.id = ++gTabIDFactory;
+      if ("tabID" in aParams) {
+        this.id = aParams.tabID;
+      } else {
+        let jni = new JNI();
+        let cls = jni.findClass("org/mozilla/gecko/Tabs");
+        let method = jni.getStaticMethodID(cls, "getNextTabId", "()I");
+        this.id = jni.callStaticIntMethod(cls, method);
+        jni.close();
+      }
+
       this.desktopMode = ("desktopMode" in aParams) ? aParams.desktopMode : false;
 
       let message = {
         gecko: {
           type: "Tab:Added",
           tabID: this.id,
           uri: uri,
           parentId: ("parentId" in aParams) ? aParams.parentId : -1,
@@ -6620,17 +6629,16 @@ var WebappsUI = {
         origin: aOrigin
       }
     });
   },
 
   get iconSize() {
     let iconSize = 64;
     try {
-      Cu.import("resource://gre/modules/JNI.jsm");
       let jni = new JNI();
       let cls = jni.findClass("org/mozilla/gecko/GeckoAppShell");
       let method = jni.getStaticMethodID(cls, "getPreferredIconSize", "()I");
       iconSize = jni.callStaticIntMethod(cls, method);
       jni.close();
     } catch(ex) {
       console.log(ex);
     }