Bug 840574 - Add applicationId to tabs; use it to open new urls in the correct tabs. r=margaret
Note that I'm not actually sure where delayLoad and selected are used by Gecko and thus the side effects of changing them (but I did set the flags as I'd expect for them to work).
This commit is contained in:
@@ -19,9 +19,8 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
|
import android.provider.Browser;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -1424,27 +1423,33 @@ public abstract class GeckoApp
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the initial tab at Fennec startup.
|
* Loads the initial tab at Fennec startup. If we don't restore tabs, this
|
||||||
*
|
* tab will be about:home. If we restore tabs, we don't need to create a new tab.
|
||||||
* If Fennec was opened with an external URL, that URL will be loaded.
|
|
||||||
* Otherwise, unless there was a session restore, the default URL
|
|
||||||
* (about:home) be loaded.
|
|
||||||
*
|
|
||||||
* @param url External URL to load, or null to load the default URL
|
|
||||||
*/
|
*/
|
||||||
protected void loadStartupTab(String url, int flags) {
|
protected void loadStartupTabWithAboutHome(final int flags) {
|
||||||
if (url == null) {
|
if (!mShouldRestore) {
|
||||||
if (!mShouldRestore) {
|
Tabs.getInstance().loadUrl(AboutPages.HOME, flags);
|
||||||
// Show about:home if we aren't restoring previous session and
|
|
||||||
// there's no external URL.
|
|
||||||
Tabs.getInstance().loadUrl(AboutPages.HOME, flags);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If given an external URL, load it
|
|
||||||
Tabs.getInstance().loadUrl(url, flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the initial tab at Fennec startup. This tab will load with the given
|
||||||
|
* external URL. If that URL is invalid, about:home will be loaded.
|
||||||
|
*
|
||||||
|
* @param url External URL to load.
|
||||||
|
* @param extraApplicationId Identifies the calling application; delivered with the URL
|
||||||
|
*/
|
||||||
|
protected void loadStartupTabWithExternalUrl(final String url, final String extraApplicationId,
|
||||||
|
final int flags) {
|
||||||
|
// Invalid url
|
||||||
|
if (url == null) {
|
||||||
|
loadStartupTabWithAboutHome(flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tabs.getInstance().loadUrl(url, extraApplicationId, flags);
|
||||||
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
|
|
||||||
@@ -1509,10 +1514,11 @@ public abstract class GeckoApp
|
|||||||
if (ACTION_HOMESCREEN_SHORTCUT.equals(action)) {
|
if (ACTION_HOMESCREEN_SHORTCUT.equals(action)) {
|
||||||
flags |= Tabs.LOADURL_PINNED;
|
flags |= Tabs.LOADURL_PINNED;
|
||||||
}
|
}
|
||||||
loadStartupTab(passedUri, flags);
|
final String extraApplicationId = intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
|
||||||
|
loadStartupTabWithExternalUrl(passedUri, extraApplicationId, flags);
|
||||||
} else {
|
} else {
|
||||||
if (!mIsRestoringActivity) {
|
if (!mIsRestoringActivity) {
|
||||||
loadStartupTab(null, Tabs.LOADURL_NEW_TAB);
|
loadStartupTabWithAboutHome(Tabs.LOADURL_NEW_TAB);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED);
|
Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED);
|
||||||
@@ -1824,9 +1830,10 @@ public abstract class GeckoApp
|
|||||||
TabQueueHelper.openQueuedUrls(GeckoApp.this, mProfile, TabQueueHelper.FILE_NAME, true);
|
TabQueueHelper.openQueuedUrls(GeckoApp.this, mProfile, TabQueueHelper.FILE_NAME, true);
|
||||||
} else {
|
} else {
|
||||||
String uri = intent.getDataString();
|
String uri = intent.getDataString();
|
||||||
Tabs.getInstance().loadUrl(uri, Tabs.LOADURL_NEW_TAB |
|
final String extraApplicationId = intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
|
||||||
Tabs.LOADURL_USER_ENTERED |
|
Tabs.getInstance().loadUrl(uri, extraApplicationId, Tabs.LOADURL_NEW_TAB |
|
||||||
Tabs.LOADURL_EXTERNAL);
|
Tabs.LOADURL_USER_ENTERED |
|
||||||
|
Tabs.LOADURL_EXTERNAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class Tab {
|
|||||||
private String mTitle;
|
private String mTitle;
|
||||||
private Bitmap mFavicon;
|
private Bitmap mFavicon;
|
||||||
private String mFaviconUrl;
|
private String mFaviconUrl;
|
||||||
|
private String mApplicationId;
|
||||||
|
|
||||||
// The set of all available Favicons for this tab, sorted by attractiveness.
|
// The set of all available Favicons for this tab, sorted by attractiveness.
|
||||||
final TreeSet<RemoteFavicon> mAvailableFavicons = new TreeSet<>();
|
final TreeSet<RemoteFavicon> mAvailableFavicons = new TreeSet<>();
|
||||||
@@ -194,6 +195,14 @@ public class Tab {
|
|||||||
return mFavicon;
|
return mFavicon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getApplicationId() {
|
||||||
|
return mApplicationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setApplicationId(final String applicationId) {
|
||||||
|
mApplicationId = applicationId;
|
||||||
|
}
|
||||||
|
|
||||||
public BitmapDrawable getThumbnail() {
|
public BitmapDrawable getThumbnail() {
|
||||||
return mThumbnail;
|
return mThumbnail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,6 +343,20 @@ public class Tabs implements GeckoEventListener {
|
|||||||
return mTabs.get(id);
|
return mTabs.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized Tab getTabForApplicationId(final String applicationId) {
|
||||||
|
if (applicationId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Tab tab : mOrder) {
|
||||||
|
if (applicationId.equals(tab.getApplicationId())) {
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Close tab and then select the default next tab */
|
/** Close tab and then select the default next tab */
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
public synchronized void closeTab(Tab tab) {
|
public synchronized void closeTab(Tab tab) {
|
||||||
@@ -796,23 +810,33 @@ public class Tabs implements GeckoEventListener {
|
|||||||
* @return the Tab if a new one was created; null otherwise
|
* @return the Tab if a new one was created; null otherwise
|
||||||
*/
|
*/
|
||||||
public Tab loadUrl(String url, int flags) {
|
public Tab loadUrl(String url, int flags) {
|
||||||
return loadUrl(url, null, -1, flags);
|
return loadUrl(url, null, -1, null, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tab loadUrl(final String url, final String applicationId, final int flags) {
|
||||||
|
return loadUrl(url, null, -1, applicationId, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tab loadUrl(final String url, final String searchEngine, final int parentId, final int flags) {
|
||||||
|
return loadUrl(url, searchEngine, parentId, null, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a tab with the given URL.
|
* Loads a tab with the given URL.
|
||||||
*
|
*
|
||||||
* @param url URL of page to load, or search term used if searchEngine is given
|
* @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
|
* @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
|
* 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 parentId ID of this tab's parent, or -1 if it has no parent
|
||||||
* @param flags flags used to load tab
|
* @param applicationId Identity of the calling application
|
||||||
|
* @param flags flags used to load tab
|
||||||
*
|
*
|
||||||
* @return the Tab if a new one was created; null otherwise
|
* @return the Tab if a new one was created; null otherwise
|
||||||
*/
|
*/
|
||||||
public Tab loadUrl(String url, String searchEngine, int parentId, int flags) {
|
public Tab loadUrl(final String url, final String searchEngine, final int parentId,
|
||||||
|
final String applicationId, final int flags) {
|
||||||
JSONObject args = new JSONObject();
|
JSONObject args = new JSONObject();
|
||||||
Tab added = null;
|
Tab tabToSelect = null;
|
||||||
boolean delayLoad = (flags & LOADURL_DELAY_LOAD) != 0;
|
boolean delayLoad = (flags & LOADURL_DELAY_LOAD) != 0;
|
||||||
|
|
||||||
// delayLoad implies background tab
|
// delayLoad implies background tab
|
||||||
@@ -828,14 +852,42 @@ public class Tabs implements GeckoEventListener {
|
|||||||
args.put("engine", searchEngine);
|
args.put("engine", searchEngine);
|
||||||
args.put("parentId", parentId);
|
args.put("parentId", parentId);
|
||||||
args.put("userEntered", userEntered);
|
args.put("userEntered", userEntered);
|
||||||
args.put("newTab", (flags & LOADURL_NEW_TAB) != 0);
|
|
||||||
args.put("isPrivate", isPrivate);
|
args.put("isPrivate", isPrivate);
|
||||||
args.put("pinned", (flags & LOADURL_PINNED) != 0);
|
args.put("pinned", (flags & LOADURL_PINNED) != 0);
|
||||||
args.put("delayLoad", delayLoad);
|
|
||||||
args.put("desktopMode", desktopMode);
|
args.put("desktopMode", desktopMode);
|
||||||
|
|
||||||
|
final boolean needsNewTab;
|
||||||
|
if (applicationId == null) {
|
||||||
|
needsNewTab = (flags & LOADURL_NEW_TAB) != 0;
|
||||||
|
} else {
|
||||||
|
final Tab applicationTab = getTabForApplicationId(applicationId);
|
||||||
|
if (applicationTab == null) {
|
||||||
|
needsNewTab = true;
|
||||||
|
} else {
|
||||||
|
needsNewTab = false;
|
||||||
|
delayLoad = false;
|
||||||
|
background = false;
|
||||||
|
|
||||||
|
tabToSelect = applicationTab;
|
||||||
|
final int tabToSelectId = tabToSelect.getId();
|
||||||
|
args.put("tabID", tabToSelectId);
|
||||||
|
|
||||||
|
// This must be called before the "Tab:Load" event is sent. I think addTab gets
|
||||||
|
// away with it because having "newTab" == true causes the selected tab to be
|
||||||
|
// updated in JS for the "Tab:Load" event but "newTab" is false in our case.
|
||||||
|
// This makes me think the other selectTab is not necessary (bug 1160673).
|
||||||
|
//
|
||||||
|
// Note: that makes the later call redundant but selectTab exits early so I'm
|
||||||
|
// fine not adding the complex logic to avoid calling it again.
|
||||||
|
selectTab(tabToSelect.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.put("newTab", needsNewTab);
|
||||||
|
args.put("delayLoad", delayLoad);
|
||||||
args.put("selected", !background);
|
args.put("selected", !background);
|
||||||
|
|
||||||
if ((flags & LOADURL_NEW_TAB) != 0) {
|
if (needsNewTab) {
|
||||||
int tabId = getNextTabId();
|
int tabId = getNextTabId();
|
||||||
args.put("tabID", tabId);
|
args.put("tabID", tabId);
|
||||||
|
|
||||||
@@ -847,8 +899,9 @@ public class Tabs implements GeckoEventListener {
|
|||||||
// Add the new tab to the end of the tab order.
|
// Add the new tab to the end of the tab order.
|
||||||
final int tabIndex = -1;
|
final int tabIndex = -1;
|
||||||
|
|
||||||
added = addTab(tabId, tabUrl, external, parentId, url, isPrivate, tabIndex);
|
tabToSelect = addTab(tabId, tabUrl, external, parentId, url, isPrivate, tabIndex);
|
||||||
added.setDesktopMode(desktopMode);
|
tabToSelect.setDesktopMode(desktopMode);
|
||||||
|
tabToSelect.setApplicationId(applicationId);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e);
|
Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e);
|
||||||
@@ -856,22 +909,22 @@ public class Tabs implements GeckoEventListener {
|
|||||||
|
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
|
||||||
|
|
||||||
if (added == null) {
|
if (tabToSelect == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!delayLoad && !background) {
|
if (!delayLoad && !background) {
|
||||||
selectTab(added.getId());
|
selectTab(tabToSelect.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: surely we could just fetch *any* cached icon?
|
// TODO: surely we could just fetch *any* cached icon?
|
||||||
if (AboutPages.isBuiltinIconPage(url)) {
|
if (AboutPages.isBuiltinIconPage(url)) {
|
||||||
Log.d(LOGTAG, "Setting about: tab favicon inline.");
|
Log.d(LOGTAG, "Setting about: tab favicon inline.");
|
||||||
added.addFavicon(url, Favicons.browserToolbarFaviconSize, "");
|
tabToSelect.addFavicon(url, Favicons.browserToolbarFaviconSize, "");
|
||||||
added.loadFavicon();
|
tabToSelect.loadFavicon();
|
||||||
}
|
}
|
||||||
|
|
||||||
return added;
|
return tabToSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tab addTab() {
|
public Tab addTab() {
|
||||||
|
|||||||
@@ -185,11 +185,19 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadStartupTab(String uri, int flags) {
|
protected void loadStartupTabWithAboutHome(final int flags) {
|
||||||
|
loadStartupTabWithExternalUrl(null, null, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: there is no support for applicationId in Webapps at
|
||||||
|
// the moment because I don't have time to debug/test.
|
||||||
|
@Override
|
||||||
|
protected void loadStartupTabWithExternalUrl(final String uri, final String applicationId,
|
||||||
|
int flags) {
|
||||||
// Load a tab so it's available for any code that assumes a tab
|
// Load a tab so it's available for any code that assumes a tab
|
||||||
// before the app tab itself is loaded in BrowserApp._loadWebapp.
|
// before the app tab itself is loaded in BrowserApp._loadWebapp.
|
||||||
flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_EXTERNAL;
|
flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_EXTERNAL;
|
||||||
super.loadStartupTab("about:blank", flags);
|
super.loadStartupTabWithExternalUrl("about:blank", null, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSplash() {
|
private void showSplash() {
|
||||||
|
|||||||
Reference in New Issue
Block a user