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
--- 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;