Skip to content

Commit

Permalink
Bug 1244597 - Show notification on incoming tab. r=markh
Browse files Browse the repository at this point in the history
MozReview-Commit-ID: BW7irvjVGiv
  • Loading branch information
eoger committed Jul 7, 2016
1 parent 346c615 commit a914a01
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 31 deletions.
69 changes: 52 additions & 17 deletions browser/components/nsBrowserGlue.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ BrowserGlue.prototype = {
case "fxaccounts:device_disconnected":
this._onDeviceDisconnected();
break;
case "weave:engine:clients:display-uri":
this._onDisplaySyncURI(subject);
case "weave:engine:clients:display-uris":
this._onDisplaySyncURIs(subject);
break;
case "session-save":
this._setPrefToSaveSession(true);
Expand Down Expand Up @@ -534,7 +534,7 @@ BrowserGlue.prototype = {
os.addObserver(this, "weave:service:ready", false);
os.addObserver(this, "fxaccounts:onverified", false);
os.addObserver(this, "fxaccounts:device_disconnected", false);
os.addObserver(this, "weave:engine:clients:display-uri", false);
os.addObserver(this, "weave:engine:clients:display-uris", false);
os.addObserver(this, "session-save", false);
os.addObserver(this, "places-init-complete", false);
this._isPlacesInitObserver = true;
Expand Down Expand Up @@ -601,7 +601,7 @@ BrowserGlue.prototype = {
os.removeObserver(this, "weave:service:ready");
os.removeObserver(this, "fxaccounts:onverified");
os.removeObserver(this, "fxaccounts:device_disconnected");
os.removeObserver(this, "weave:engine:clients:display-uri");
os.removeObserver(this, "weave:engine:clients:display-uris");
os.removeObserver(this, "session-save");
if (this._bookmarksBackupIdleTime) {
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
Expand Down Expand Up @@ -2434,24 +2434,59 @@ BrowserGlue.prototype = {
},

/**
* Called as an observer when Sync's "display URI" notification is fired.
* Called as an observer when Sync's "display URIs" notification is fired.
*
* We open the received URI in a background tab.
*
* Eventually, this will likely be replaced by a more robust tab syncing
* feature. This functionality is considered somewhat evil by UX because it
* opens a new tab automatically without any prompting. However, it is a
* lesser evil than sending a tab to a specific device (from e.g. Fennec)
* and having nothing happen on the receiving end.
* We open the received URIs in background tabs.
*/
_onDisplaySyncURI: function _onDisplaySyncURI(data) {
_onDisplaySyncURIs: function _onDisplaySyncURIs(data) {
try {
let tabbrowser = RecentWindow.getMostRecentBrowserWindow({private: false}).gBrowser;

// The payload is wrapped weirdly because of how Sync does notifications.
tabbrowser.addTab(data.wrappedJSObject.object.uri);
const URIs = data.wrappedJSObject.object;

const findWindow = () => RecentWindow.getMostRecentBrowserWindow({private: false});

// win can be null, but it's ok, we'll assign it later in openTab()
let win = findWindow();

const openTab = URI => {
let tab;
if (!win) {
Services.appShell.hiddenDOMWindow.open(URI.uri);
win = findWindow();
tab = win.gBrowser.tabs[0];
} else {
tab = win.gBrowser.addTab(URI.uri);
}
tab.setAttribute("attention", true);
return tab;
};

const firstTab = openTab(URIs[0]);
URIs.slice(1).forEach(URI => openTab(URI));

let title, body;
const deviceName = Weave.Service.clientsEngine.getClientName(URIs[0].clientId);
const bundle = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
if (URIs.length == 1) {
title = bundle.GetStringFromName("tabArrivingNotification.title");
const pageTitle = URIs[0].title || firstTab.linkedBrowser.contentTitle
|| URIs[0].uri;
body = bundle.formatStringFromName("tabArrivingNotification.body", [pageTitle, deviceName], 2);
} else {
title = bundle.GetStringFromName("tabsArrivingNotification.title");
const tabArrivingBody = URIs.every(URI => URI.clientId == URIs[0].clientId) ?
"tabsArrivingNotification.body" : "tabsArrivingNotificationMultiple.body";
body = bundle.formatStringFromName(tabArrivingBody, [URIs.length, deviceName], 2);
}

const clickCallback = (subject, topic, data) => {
if (topic == "alertclickcallback") {
win.gBrowser.selectedTab = firstTab;
}
}
AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
} catch (ex) {
Cu.reportError("Error displaying tab received by Sync: " + ex);
Cu.reportError("Error displaying tab(s) received by Sync: " + ex);
}
},

Expand Down
15 changes: 15 additions & 0 deletions browser/locales/en-US/chrome/browser/accounts.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,18 @@ syncStartNotification.body = Firefox will begin syncing momentarily.
# These strings are used in a notification shown after Sync was disconnected remotely.
deviceDisconnectedNotification.title = Sync disconnected
deviceDisconnectedNotification.body = This computer has been successfully disconnected from Firefox Sync.

# LOCALIZATION NOTE (tabArrivingNotification.title, tabArrivingNotification.body,
# tabsArrivingNotification.title, tabsArrivingNotification.body)
# These strings are used in a notification shown when we're opening tab(s) another device sent us to display.
tabArrivingNotification.title = Tab received
# LOCALIZATION NOTE (tabArrivingNotification.body) %1 is the title of the tab and %2 is the device name.
tabArrivingNotification.body = "%1$S" has arrived from %2$S.

tabsArrivingNotification.title = Multiple tabs received
# LOCALIZATION NOTE (tabsArrivingNotification.body) %1 is the number of tabs received and %2 is the device name.
tabsArrivingNotification.body = %1$S tabs have arrived from %2$S.
# LOCALIZATION NOTE (tabsArrivingNotificationMultiple.body)
# This string is used in a notification shown when we're opening tab(s) that several devices sent us to display.
# %S is the number of tabs received
tabsArrivingNotificationMultiple.body = %S tabs have arrived from your connected devices.
31 changes: 17 additions & 14 deletions services/sync/modules/engines/clients.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ ClientEngine.prototype = {
if (!commands) {
return true;
}
let URIsToDisplay = [];
for (let key in commands) {
let {command, args} = commands[key];
this._log.debug("Processing command: " + command + "(" + args + ")");
Expand All @@ -401,13 +402,17 @@ ClientEngine.prototype = {
this.service.logout();
return false;
case "displayURI":
this._handleDisplayURI.apply(this, args);
let [uri, clientId, title] = args;
URIsToDisplay.push({ uri, clientId, title });
break;
default:
this._log.debug("Received an unknown command: " + command);
break;
}
}
if (URIsToDisplay.length) {
this._handleDisplayURIs(URIsToDisplay);
}

return true;
})();
Expand Down Expand Up @@ -477,32 +482,30 @@ ClientEngine.prototype = {
},

/**
* Handle a single received 'displayURI' command.
* Handle a bunch of received 'displayURI' commands.
*
* Interested parties should observe the "weave:engine:clients:display-uri"
* topic. The callback will receive an object as the subject parameter with
* the following keys:
* Interested parties should observe the "weave:engine:clients:display-uris"
* topic. The callback will receive an array as the subject parameter
* containing objects with the following keys:
*
* uri URI (string) that is requested for display.
* clientId ID of client that sent the command.
* title Title of page that loaded URI (likely) corresponds to.
*
* The 'data' parameter to the callback will not be defined.
*
* @param uri
* @param uris
* An array containing URI objects to display
* @param uris[].uri
* String URI that was received
* @param clientId
* @param uris[].clientId
* ID of client that sent URI
* @param title
* @param uris[].title
* String title of page that URI corresponds to. Older clients may not
* send this.
*/
_handleDisplayURI: function _handleDisplayURI(uri, clientId, title) {
this._log.info("Received a URI for display: " + uri + " (" + title +
") from " + clientId);

let subject = {uri: uri, client: clientId, title: title};
Svc.Obs.notify("weave:engine:clients:display-uri", subject);
_handleDisplayURIs: function _handleDisplayURIs(uris) {
Svc.Obs.notify("weave:engine:clients:display-uris", uris);
},

_removeRemoteClient(id) {
Expand Down

0 comments on commit a914a01

Please sign in to comment.