Bug 1301160 - Part 3 - Pass the saved parent tab ID when restoring tabs. r?sebastian draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Sat, 07 Jan 2017 22:26:36 +0100
changeset 460765 3a5dffafac5826467c8995cd7239c241b299b842
parent 460764 a5d0dc2a200a5c3f977afa498c321fcd728e7bc8
child 460766 221e44a38a3b384efcce3d0e6249642033fdf6a7
push id41481
push usermozilla@buttercookie.de
push dateFri, 13 Jan 2017 19:07:33 +0000
reviewerssebastian
bugs1301160
milestone53.0a1
Bug 1301160 - Part 3 - Pass the saved parent tab ID when restoring tabs. r?sebastian When restoring recently closed tabs during a browsing session, we can just pass the stored parentId as a parameter to addTab and be done with it. During startup however, we first need to update the parent tab IDs before being able to use it. At the moment, new tabs are always opened at the end of the tab list and cannot be resorted by the user, so child tabs always appear *after* their parent tabs in the tab list. However because we don't want to rely on this behaviour, we still need to collect a complete mapping between old and new tab IDs first before being able to update the stored parent tab IDs. Therefore we cannot use the usual method of passing in the parentId during tab creation and have to set it after the fact for this case. MozReview-Commit-ID: JT5YSkuOSZw
mobile/android/base/java/org/mozilla/gecko/Tab.java
mobile/android/base/java/org/mozilla/gecko/Tabs.java
mobile/android/chrome/content/browser.js
mobile/android/components/SessionStore.js
--- a/mobile/android/base/java/org/mozilla/gecko/Tab.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tab.java
@@ -59,17 +59,17 @@ public class Tab {
     private IconRequestBuilder mIconRequestBuilder;
     private Future<IconResponse> mRunningIconRequest;
 
     private boolean mHasFeeds;
     private boolean mHasOpenSearch;
     private final SiteIdentity mSiteIdentity;
     private SiteLogins mSiteLogins;
     private BitmapDrawable mThumbnail;
-    private final int mParentId;
+    private volatile int mParentId;
     // Indicates the url was loaded from a source external to the app. This will be cleared
     // when the user explicitly loads a new url (e.g. clicking a link is not explicit).
     private final boolean mExternal;
     private boolean mBookmark;
     private int mFaviconLoadId;
     private String mContentType;
     private boolean mHasTouchListeners;
     private final ArrayList<View> mPluginViews;
@@ -163,16 +163,27 @@ public class Tab {
     public synchronized long getLastUsed() {
         return mLastUsed;
     }
 
     public int getParentId() {
         return mParentId;
     }
 
+    /**
+     * Updates the stored parent tab ID to a new value.
+     * Note: Calling this directly from Java currently won't update the parent ID value
+     * held by Gecko and the session store.
+     *
+     * @param parentId The ID of the tab to be set as new parent, or -1 for no parent.
+     */
+    public void setParentId(int parentId) {
+        mParentId = parentId;
+    }
+
     // may be null if user-entered query hasn't yet been resolved to a URI
     public synchronized String getURL() {
         return mUrl;
     }
 
     // mUserRequested should never be null, but it may be an empty string
     public synchronized String getUserRequested() {
         return mUserRequested;
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -124,17 +124,19 @@ public class Tabs implements BundleEvent
             "Link:Favicon",
             "Link:Touchicon",
             "Link:Feed",
             "Link:OpenSearch",
             "DesktopMode:Changed",
             "Tab:StreamStart",
             "Tab:StreamStop",
             "Tab:AudioPlayingChange",
-            "Tab:MediaPlaybackChange");
+            "Tab:MediaPlaybackChange",
+            "Tab:SetParentId",
+            null);
 
         mPrivateClearColor = Color.RED;
 
     }
 
     public synchronized void attachToContext(Context context, LayerView layerView) {
         final Context appContext = context.getApplicationContext();
         if (mAppContext == appContext) {
@@ -600,16 +602,19 @@ public class Tabs implements BundleEvent
             } else if (event.equals("Tab:MediaPlaybackChange")) {
                 final String status = message.getString("status");
                 if (status.equals("resume")) {
                     notifyListeners(tab, TabEvents.MEDIA_PLAYING_RESUME);
                 } else {
                     tab.setIsMediaPlaying(status.equals("start"));
                     notifyListeners(tab, TabEvents.MEDIA_PLAYING_CHANGE);
                 }
+            } else if (event.equals("Tab:SetParentId")) {
+                int newParentId = message.getInt("parentID");
+                tab.setParentId(newParentId);
             }
 
         } catch (Exception e) {
             Log.w(LOGTAG, "handleMessage threw for " + event, e);
         }
     }
 
     public void refreshThumbnails() {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3830,16 +3830,26 @@ Tab.prototype = {
           type: "Link:OpenSearch",
           tabID: this.id,
           visible: true
         });
       });
     }
   },
 
+  setParentId: function(aParentId) {
+    let newParentId = (typeof aParentId == "number") ? aParentId : -1;
+    this.parentId = newParentId;
+    Messaging.sendRequest({
+      type: "Tab:SetParentId",
+      tabID: this.id,
+      parentID: newParentId
+    });
+  },
+
   handleEvent: function(aEvent) {
     switch (aEvent.type) {
       case "DOMContentLoaded": {
         let target = aEvent.originalTarget;
 
         // ignore on frames and other documents
         if (target != this.browser.contentDocument)
           return;
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -1479,17 +1479,18 @@ SessionStore.prototype = {
     let window = Services.wm.getMostRecentWindow("navigator:browser");
     for (let i = 0; i < aData.tabs.length; i++) {
       let tabData = JSON.parse(aData.tabs[i]);
       let isSelectedTab = (i == aData.tabs.length - 1);
       let params = {
         selected: isSelectedTab,
         isPrivate: tabData.isPrivate,
         desktopMode: tabData.desktopMode,
-        cancelEditMode: isSelectedTab
+        cancelEditMode: isSelectedTab,
+        parentId: tabData.parentId
       };
 
       let tab = window.BrowserApp.addTab(tabData.entries[tabData.index - 1].url, params);
       tab.browser.__SS_data = tabData;
       tab.browser.__SS_extdata = tabData.extData;
       this._restoreTab(tabData, tab.browser);
     }
   },
@@ -1631,33 +1632,38 @@ SessionStore.prototype = {
     log("restoreWindow() window.BrowserApp.selectedTab is " + window.BrowserApp.selectedTab.id);
 
     for (let i = 0; i < tabs.length; i++) {
       let tabData = tabs[i];
       let entry = tabData.entries[tabData.index - 1];
 
       // Use stubbed tab if we've already created it; otherwise, make a new tab
       let tab;
+      let parentId = tabData.parentId;
       if (tabData.tabId == null) {
         let params = {
           selected: (selected == i+1),
           delayLoad: true,
           title: entry.title,
           desktopMode: (tabData.desktopMode == true),
-          isPrivate: (tabData.isPrivate == true)
+          isPrivate: (tabData.isPrivate == true),
+          parentId: parentId
         };
         tab = window.BrowserApp.addTab(entry.url, params);
       } else {
         tab = window.BrowserApp.getTabForId(tabData.tabId);
 
         // Don't restore tab if user has closed it
         if (tab == null) {
           delete tabData.tabId;
           continue;
         }
+        if (parentId > -1) {
+          tab.setParentId(parentId);
+        }
       }
 
       tab.browser.__SS_data = tabData;
       tab.browser.__SS_extdata = tabData.extData;
 
       if (window.BrowserApp.selectedTab == tab) {
         this._restoreTab(tabData, tab.browser);
 
@@ -1718,17 +1724,18 @@ SessionStore.prototype = {
       }
     });
 
     // create a new tab and bring to front
     let params = {
       selected: true,
       isPrivate: aCloseTabData.isPrivate,
       desktopMode: aCloseTabData.desktopMode,
-      tabIndex: this._lastClosedTabIndex
+      tabIndex: this._lastClosedTabIndex,
+      parentId: aCloseTabData.parentId
     };
     let tab = aWindow.BrowserApp.addTab(aCloseTabData.entries[aCloseTabData.index - 1].url, params);
     tab.browser.__SS_data = aCloseTabData;
     tab.browser.__SS_extdata = aCloseTabData.extData;
     this._restoreTab(aCloseTabData, tab.browser);
 
     this._lastClosedTabIndex = -1;