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:
Michael Comella
2015-05-01 15:04:07 -07:00
parent 1e50dff8be
commit d632ee27c0
4 changed files with 122 additions and 45 deletions

View File

@@ -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);
} }
} }
}); });

View File

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

View File

@@ -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() {

View File

@@ -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() {