Index: remoting/webapp/me2mom/remoting.js |
diff --git a/remoting/webapp/me2mom/remoting.js b/remoting/webapp/me2mom/remoting.js |
index 2f4250b0fe2d8ee6252c9a757a34a145cfc5ae69..3e86b05c8af7746b7a53f9ee031ae9773f230be7 100644 |
--- a/remoting/webapp/me2mom/remoting.js |
+++ b/remoting/webapp/me2mom/remoting.js |
@@ -7,202 +7,31 @@ |
/** @suppress {duplicate} */ |
var remoting = remoting || {}; |
-/** |
- * Whether or not the plugin should scale itself. |
- * @type {boolean} |
- */ |
-remoting.scaleToFit = false; |
- |
-/** @type {remoting.ClientSession} */ |
-remoting.session = null; |
- |
-/** @type {string} */ remoting.accessCode = ''; |
-/** @type {number} */ remoting.accessCodeTimerId = 0; |
-/** @type {number} */ remoting.accessCodeExpiresIn = 0; |
-/** @type {remoting.AppMode} */ remoting.currentMode; |
-/** @type {string} */ remoting.hostJid = ''; |
-/** @type {string} */ remoting.hostPublicKey = ''; |
-/** @type {boolean} */ remoting.lastShareWasCancelled = false; |
-/** @type {boolean} */ remoting.timerRunning = false; |
-/** @type {string} */ remoting.username = ''; |
- |
-/** @enum {string} */ |
-remoting.AppMode = { |
- HOME: 'home', |
- UNAUTHENTICATED: 'auth', |
- CLIENT: 'client', |
- CLIENT_UNCONNECTED: 'client.unconnected', |
- CLIENT_CONNECTING: 'client.connecting', |
- CLIENT_CONNECT_FAILED: 'client.connect-failed', |
- CLIENT_SESSION_FINISHED: 'client.session-finished', |
- HOST: 'host', |
- HOST_WAITING_FOR_CODE: 'host.waiting-for-code', |
- HOST_WAITING_FOR_CONNECTION: 'host.waiting-for-connection', |
- HOST_SHARED: 'host.shared', |
- HOST_SHARE_FAILED: 'host.share-failed', |
- HOST_SHARE_FINISHED: 'host.share-finished', |
- IN_SESSION: 'in-session' |
-}; |
+/** @type {remoting.HostSession} */ remoting.hostSession = null; |
(function() { |
-window.addEventListener('blur', pluginLostFocus_, false); |
- |
-function pluginLostFocus_() { |
- // If the plug loses input focus, release all keys as a precaution against |
- // leaving them 'stuck down' on the host. |
- if (remoting.session && remoting.session.plugin) { |
- remoting.session.plugin.releaseAllKeys(); |
- } |
-} |
- |
-/** @type {string} */ |
-remoting.HOST_PLUGIN_ID = 'host-plugin-id'; |
- |
-/** @enum {string} */ |
-remoting.ClientError = { |
- NO_RESPONSE: /*i18n-content*/'ERROR_NO_RESPONSE', |
- INVALID_ACCESS_CODE: /*i18n-content*/'ERROR_INVALID_ACCESS_CODE', |
- MISSING_PLUGIN: /*i18n-content*/'ERROR_MISSING_PLUGIN', |
- OAUTH_FETCH_FAILED: /*i18n-content*/'ERROR_AUTHENTICATION_FAILED', |
- HOST_IS_OFFLINE: /*i18n-content*/'ERROR_HOST_IS_OFFLINE', |
- INCOMPATIBLE_PROTOCOL: /*i18n-content*/'ERROR_INCOMPATIBLE_PROTOCOL', |
- BAD_PLUGIN_VERSION: /*i18n-content*/'ERROR_BAD_PLUGIN_VERSION', |
- OTHER_ERROR: /*i18n-content*/'ERROR_GENERIC' |
-}; |
- |
-// Constants representing keys used for storing persistent application state. |
-var KEY_APP_MODE_ = 'remoting-app-mode'; |
-var KEY_EMAIL_ = 'remoting-email'; |
-var KEY_USE_P2P_API_ = 'remoting-use-p2p-api'; |
- |
-// Some constants for pretty-printing the access code. |
-/** @type {number} */ var kSupportIdLen = 7; |
-/** @type {number} */ var kHostSecretLen = 5; |
-/** @type {number} */ var kAccessCodeLen = kSupportIdLen + kHostSecretLen; |
-/** @type {number} */ var kDigitsPerGroup = 4; |
- |
/** |
- * @param {string} classes A space-separated list of classes. |
- * @param {string} cls The class to check for. |
- * @return {boolean} True if |cls| is found within |classes|. |
+ * Entry point for app initialization. |
*/ |
-function hasClass(classes, cls) { |
- return classes.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) != null; |
-} |
- |
-/** |
- * @param {Element} element The element to which to add the class. |
- * @param {string} cls The new class. |
- * @return {void} Nothing. |
- */ |
-function addClass(element, cls) { |
- if (!hasClass(element.className, cls)) { |
- var padded = element.className == '' ? '' : element.className + ' '; |
- element.className = padded + cls; |
- } |
-} |
- |
-/** |
- * @param {Element} element The element from which to remove the class. |
- * @param {string} cls The new class. |
- * @return {void} Nothing. |
- */ |
-function removeClass(element, cls) { |
- element.className = |
- element.className.replace(new RegExp('\\b' + cls + '\\b', 'g'), '') |
- .replace(' ', ' '); |
-} |
- |
-function retrieveEmail_(access_token) { |
- var headers = { |
- 'Authorization': 'OAuth ' + remoting.oauth2.getAccessToken() |
- }; |
- |
- /** @param {XMLHttpRequest} xhr The XHR response. */ |
- var onResponse = function(xhr) { |
- if (xhr.status != 200) { |
- // TODO(ajwong): Have a better way of showing an error. |
- remoting.debug.log('Unable to get email'); |
- document.getElementById('current-email').innerText = '???'; |
- return; |
- } |
- |
- // TODO(ajwong): See if we can't find a JSON endpoint. |
- setEmail(xhr.responseText.split('&')[0].split('=')[1]); |
- }; |
- |
- // TODO(ajwong): Update to new v2 API. |
- remoting.xhr.get('https://www.googleapis.com/userinfo/email', |
- onResponse, '', headers); |
-} |
- |
-function refreshEmail_() { |
- if (!getEmail() && remoting.oauth2.isAuthenticated()) { |
- remoting.oauth2.callWithToken(retrieveEmail_); |
- } |
-} |
- |
-/** |
- * @param {string} value The email address to place in local storage. |
- * @return {void} Nothing. |
- */ |
-function setEmail(value) { |
- window.localStorage.setItem(KEY_EMAIL_, value); |
- document.getElementById('current-email').innerText = value; |
-} |
- |
-/** |
- * @return {?string} The email address associated with the auth credentials. |
- */ |
-function getEmail() { |
- var result = window.localStorage.getItem(KEY_EMAIL_); |
- return typeof result == 'string' ? result : null; |
-} |
- |
-function exchangedCodeForToken_() { |
- if (!remoting.oauth2.isAuthenticated()) { |
- alert('Your OAuth2 token was invalid. Please try again.'); |
- } |
- /** @param {string} token The auth token. */ |
- var retrieveEmail = function(token) { retrieveEmail_(token); } |
- remoting.oauth2.callWithToken(retrieveEmail); |
-} |
- |
-remoting.clearOAuth2 = function() { |
- remoting.oauth2.clear(); |
- window.localStorage.removeItem(KEY_EMAIL_); |
- remoting.setMode(remoting.AppMode.UNAUTHENTICATED); |
-} |
- |
-remoting.toggleDebugLog = function() { |
- var debugLog = document.getElementById('debug-log'); |
- if (debugLog.hidden) { |
- debugLog.hidden = false; |
- } else { |
- debugLog.hidden = true; |
- } |
-} |
- |
remoting.init = function() { |
l10n.localize(); |
var button = document.getElementById('toggle-scaling'); |
button.title = chrome.i18n.getMessage(/*i18n-content*/'TOOLTIP_SCALING'); |
// Create global objects. |
remoting.oauth2 = new remoting.OAuth2(); |
- remoting.debug = |
- new remoting.DebugLog(document.getElementById('debug-messages')); |
- /** @type {XMLHttpRequest} */ |
- remoting.supportHostsXhr = null; |
+ remoting.debug = new remoting.DebugLog( |
+ document.getElementById('debug-messages'), |
+ document.getElementById('statistics')); |
refreshEmail_(); |
- var email = getEmail(); |
+ var email = remoting.oauth2.getCachedEmail(); |
if (email) { |
document.getElementById('current-email').innerText = email; |
} |
- remoting.setMode(getAppStartupMode()); |
- if (isHostModeSupported()) { |
+ remoting.setMode(getAppStartupMode_()); |
+ if (isHostModeSupported_()) { |
var unsupported = document.getElementById('client-footer-text-cros'); |
unsupported.parentNode.removeChild(unsupported); |
} else { |
@@ -211,553 +40,106 @@ remoting.init = function() { |
document.getElementById('client-footer-text-cros').id = |
'client-footer-text'; |
} |
-} |
- |
-/** |
- * Change the app's modal state to |mode|, which is considered to be a dotted |
- * hierachy of modes. For example, setMode('host.shared') will show any modal |
- * elements with an data-ui-mode attribute of 'host' or 'host.shared' and hide |
- * all others. |
- * |
- * @param {remoting.AppMode} mode The new modal state, expressed as a dotted |
- * hiearchy. |
- */ |
-remoting.setMode = function(mode) { |
- var modes = mode.split('.'); |
- for (var i = 1; i < modes.length; ++i) |
- modes[i] = modes[i - 1] + '.' + modes[i]; |
- var elements = document.querySelectorAll('[data-ui-mode]'); |
- for (var i = 0; i < elements.length; ++i) { |
- /** @type {Element} */ var element = elements[i]; |
- var hidden = true; |
- for (var m = 0; m < modes.length; ++m) { |
- if (hasClass(element.getAttribute('data-ui-mode'), modes[m])) { |
- hidden = false; |
- break; |
- } |
- } |
- element.hidden = hidden; |
- } |
- remoting.debug.log('App mode: ' + mode); |
- remoting.currentMode = mode; |
- if (mode == remoting.AppMode.IN_SESSION) { |
- document.removeEventListener('keydown', remoting.checkHotkeys, false); |
- } else { |
- document.addEventListener('keydown', remoting.checkHotkeys, false); |
- } |
-} |
- |
-/** |
- * Get the major mode that the app is running in. |
- * @return {string} The app's current major mode. |
- */ |
-remoting.getMajorMode = function() { |
- return remoting.currentMode.split('.')[0]; |
-} |
- |
-remoting.tryShare = function() { |
- remoting.debug.log('Attempting to share...'); |
- remoting.lastShareWasCancelled = false; |
- if (remoting.oauth2.needsNewAccessToken()) { |
- remoting.debug.log('Refreshing token...'); |
- remoting.oauth2.refreshAccessToken(function() { |
- if (remoting.oauth2.needsNewAccessToken()) { |
- // If we still need it, we're going to infinite loop. |
- showShareError_(/*i18n-content*/'ERROR_AUTHENTICATION_FAILED'); |
- throw 'Unable to get access token'; |
- } |
- remoting.tryShare(); |
- }); |
- return; |
- } |
- |
- remoting.setMode(remoting.AppMode.HOST_WAITING_FOR_CODE); |
- document.getElementById('cancel-button').disabled = false; |
- disableTimeoutCountdown_(); |
- |
- var div = document.getElementById('host-plugin-container'); |
- var plugin = /** @type {remoting.HostPlugin} */ |
- document.createElement('embed'); |
- plugin.type = remoting.PLUGIN_MIMETYPE; |
- plugin.id = remoting.HOST_PLUGIN_ID; |
- // Hiding the plugin means it doesn't load, so make it size zero instead. |
- plugin.width = 0; |
- plugin.height = 0; |
- div.appendChild(plugin); |
- onNatTraversalPolicyChanged_(true); // Hide warning by default. |
- plugin.onNatTraversalPolicyChanged = onNatTraversalPolicyChanged_; |
- plugin.onStateChanged = onStateChanged_; |
- plugin.logDebugInfo = debugInfoCallback_; |
- plugin.localize(chrome.i18n.getMessage); |
- plugin.connect(/** @type {string} */ (getEmail()), |
- 'oauth2:' + remoting.oauth2.getAccessToken()); |
-} |
-function disableTimeoutCountdown_() { |
- if (remoting.timerRunning) { |
- clearInterval(remoting.accessCodeTimerId); |
- remoting.timerRunning = false; |
- updateTimeoutStyles_(); |
- } |
+ window.addEventListener('blur', pluginLostFocus_, false); |
} |
-var ACCESS_CODE_TIMER_DISPLAY_THRESHOLD = 30; |
-var ACCESS_CODE_RED_THRESHOLD = 10; |
- |
-/** |
- * Show/hide or restyle various elements, depending on the remaining countdown |
- * and timer state. |
- * |
- * @return {boolean} True if the timeout is in progress, false if it has |
- * expired. |
- */ |
-function updateTimeoutStyles_() { |
- if (remoting.timerRunning) { |
- if (remoting.accessCodeExpiresIn <= 0) { |
+remoting.cancelPendingOperation = function() { |
+ document.getElementById('cancel-button').disabled = true; |
+ switch (remoting.getMajorMode()) { |
+ case remoting.AppMode.HOST: |
remoting.cancelShare(); |
- return false; |
- } |
- if (remoting.accessCodeExpiresIn <= ACCESS_CODE_RED_THRESHOLD) { |
- addClass(document.getElementById('access-code-display'), 'expiring'); |
- } else { |
- removeClass(document.getElementById('access-code-display'), 'expiring'); |
- } |
- } |
- document.getElementById('access-code-countdown').hidden = |
- (remoting.accessCodeExpiresIn > ACCESS_CODE_TIMER_DISPLAY_THRESHOLD) || |
- !remoting.timerRunning; |
- return true; |
-} |
- |
-remoting.decrementAccessCodeTimeout_ = function() { |
- --remoting.accessCodeExpiresIn; |
- remoting.updateAccessCodeTimeoutElement_(); |
-} |
- |
-remoting.updateAccessCodeTimeoutElement_ = function() { |
- var pad = (remoting.accessCodeExpiresIn < 10) ? '0:0' : '0:'; |
- l10n.localizeElement(document.getElementById('seconds-remaining'), |
- pad + remoting.accessCodeExpiresIn); |
- if (!updateTimeoutStyles_()) { |
- disableTimeoutCountdown_(); |
+ break; |
+ case remoting.AppMode.CLIENT: |
+ remoting.cancelConnect(); |
+ break; |
} |
} |
/** |
- * Callback to show or hide the NAT traversal warning when the policy changes. |
- * @param {boolean} enabled True if NAT traversal is enabled. |
- * @return {void} Nothing. |
- */ |
-function onNatTraversalPolicyChanged_(enabled) { |
- var container = document.getElementById('nat-box-container'); |
- container.hidden = enabled; |
-} |
- |
-/** |
- * Callback for the host plugin to notify the web app of state changes. |
- * @param {number} state The new state of the plugin. |
+ * If the client is connected, or the host is shared, prompt before closing. |
+ * |
+ * @return {?string} The prompt string if a connection is active. |
*/ |
-function onStateChanged_(state) { |
- var plugin = /** @type {remoting.HostPlugin} */ |
- document.getElementById(remoting.HOST_PLUGIN_ID); |
- if (state == plugin.STARTING) { |
- // Nothing to do here. |
- remoting.debug.log('Host plugin state: STARTING'); |
- } else if (state == plugin.REQUESTED_ACCESS_CODE) { |
- // Nothing to do here. |
- remoting.debug.log('Host plugin state: REQUESTED_ACCESS_CODE'); |
- } else if (state == plugin.RECEIVED_ACCESS_CODE) { |
- remoting.debug.log('Host plugin state: RECEIVED_ACCESS_CODE'); |
- var accessCode = plugin.accessCode; |
- var accessCodeDisplay = document.getElementById('access-code-display'); |
- accessCodeDisplay.innerText = ''; |
- // Display the access code in groups of four digits for readability. |
- for (var i = 0; i < accessCode.length; i += kDigitsPerGroup) { |
- var nextFourDigits = document.createElement('span'); |
- nextFourDigits.className = 'access-code-digit-group'; |
- nextFourDigits.innerText = accessCode.substring(i, i + kDigitsPerGroup); |
- accessCodeDisplay.appendChild(nextFourDigits); |
- } |
- remoting.accessCodeExpiresIn = plugin.accessCodeLifetime; |
- if (remoting.accessCodeExpiresIn > 0) { // Check it hasn't expired. |
- remoting.accessCodeTimerId = setInterval( |
- 'remoting.decrementAccessCodeTimeout_()', 1000); |
- remoting.timerRunning = true; |
- remoting.updateAccessCodeTimeoutElement_(); |
- updateTimeoutStyles_(); |
- remoting.setMode(remoting.AppMode.HOST_WAITING_FOR_CONNECTION); |
- } else { |
- // This can only happen if the cloud tells us that the code lifetime is |
- // <= 0s, which shouldn't happen so we don't care how clean this UX is. |
- remoting.debug.log('Access code already invalid on receipt!'); |
- remoting.cancelShare(); |
- } |
- } else if (state == plugin.CONNECTED) { |
- remoting.debug.log('Host plugin state: CONNECTED'); |
- var element = document.getElementById('host-shared-message'); |
- var client = plugin.client; |
- l10n.localizeElement(element, client); |
- remoting.setMode(remoting.AppMode.HOST_SHARED); |
- disableTimeoutCountdown_(); |
- } else if (state == plugin.DISCONNECTING) { |
- remoting.debug.log('Host plugin state: DISCONNECTING'); |
- } else if (state == plugin.DISCONNECTED) { |
- remoting.debug.log('Host plugin state: DISCONNECTED'); |
- if (remoting.currentMode != remoting.AppMode.HOST_SHARE_FAILED) { |
- // If an error is being displayed, then the plugin should not be able to |
- // hide it by setting the state. Errors must be dismissed by the user |
- // clicking OK, which puts the app into mode HOME. |
- if (remoting.lastShareWasCancelled) { |
- remoting.setMode(remoting.AppMode.HOME); |
- } else { |
- remoting.setMode(remoting.AppMode.HOST_SHARE_FINISHED); |
- } |
- } |
- plugin.parentNode.removeChild(plugin); |
- } else if (state == plugin.ERROR) { |
- remoting.debug.log('Host plugin state: ERROR'); |
- showShareError_(/*i18n-content*/'ERROR_GENERIC'); |
- } else { |
- remoting.debug.log('Unknown state -> ' + state); |
+remoting.promptClose = function() { |
+ switch (remoting.currentMode) { |
+ case remoting.AppMode.CLIENT_CONNECTING: |
+ case remoting.AppMode.HOST_WAITING_FOR_CODE: |
+ case remoting.AppMode.HOST_WAITING_FOR_CONNECTION: |
+ case remoting.AppMode.HOST_SHARED: |
+ case remoting.AppMode.IN_SESSION: |
+ var result = chrome.i18n.getMessage(/*i18n-content*/'CLOSE_PROMPT'); |
+ return result; |
+ default: |
+ return null; |
} |
} |
/** |
- * This is the callback that the host plugin invokes to indicate that there |
- * is additional debug log info to display. |
- * @param {string} msg The message (which will not be localized) to be logged. |
- */ |
-function debugInfoCallback_(msg) { |
- remoting.debug.log('plugin: ' + msg); |
-} |
- |
-/** |
- * Show a host-side error message. |
- * |
- * @param {string} errorTag The error message to be localized and displayed. |
- * @return {void} Nothing. |
+ * Sign the user out of Chromoting by clearing the OAuth refresh token. |
*/ |
-function showShareError_(errorTag) { |
- var errorDiv = document.getElementById('host-plugin-error'); |
- l10n.localizeElementFromTag(errorDiv, errorTag); |
- remoting.debug.log('Sharing error: ' + errorTag); |
- remoting.setMode(remoting.AppMode.HOST_SHARE_FAILED); |
+remoting.clearOAuth2 = function() { |
+ remoting.oauth2.clear(); |
+ window.localStorage.removeItem(KEY_EMAIL_); |
+ remoting.setMode(remoting.AppMode.UNAUTHENTICATED); |
} |
/** |
- * Cancel an active or pending share operation. |
- * |
- * @return {void} Nothing. |
+ * Callback function called when the browser window loses focus. In this case, |
+ * release all keys to prevent them becoming 'stuck down' on the host. |
*/ |
-remoting.cancelShare = function() { |
- remoting.debug.log('Canceling share...'); |
- remoting.lastShareWasCancelled = true; |
- var plugin = /** @type {remoting.HostPlugin} */ |
- document.getElementById(remoting.HOST_PLUGIN_ID); |
- try { |
- plugin.disconnect(); |
- } catch (error) { |
- // Hack to force JSCompiler type-safety. |
- var errorTyped = /** @type {{description: string}} */ error; |
- remoting.debug.log('Error disconnecting: ' + errorTyped.description + |
- '. The host plugin probably crashed.'); |
- // TODO(jamiewalch): Clean this up. We should have a class representing |
- // the host plugin, like we do for the client, which should handle crash |
- // reporting and it should use a more detailed error message than the |
- // default 'generic' one. See crbug.com/94624 |
- showShareError_(/*i18n-content*/'ERROR_GENERIC'); |
+function pluginLostFocus_() { |
+ if (remoting.clientSession && remoting.clientSession.plugin) { |
+ remoting.clientSession.plugin.releaseAllKeys(); |
} |
- disableTimeoutCountdown_(); |
} |
/** |
- * Cancel an incomplete connect operation. |
- * |
- * @return {void} Nothing. |
+ * If the user is authenticated, but there is no email address cached, get one. |
*/ |
-remoting.cancelConnect = function() { |
- if (remoting.supportHostsXhr) { |
- remoting.supportHostsXhr.abort(); |
- remoting.supportHostsXhr = null; |
- } |
- if (remoting.session) { |
- remoting.session.removePlugin(); |
- remoting.session = null; |
- } |
- remoting.setMode(remoting.AppMode.HOME); |
-} |
- |
-function updateStatistics() { |
- if (!remoting.session) |
- return; |
- if (remoting.session.state != remoting.ClientSession.State.CONNECTED) |
- return; |
- var stats = remoting.session.stats(); |
- |
- var units = ''; |
- var videoBandwidth = stats['video_bandwidth']; |
- if (videoBandwidth < 1024) { |
- units = 'Bps'; |
- } else if (videoBandwidth < 1048576) { |
- units = 'KiBps'; |
- videoBandwidth = videoBandwidth / 1024; |
- } else if (videoBandwidth < 1073741824) { |
- units = 'MiBps'; |
- videoBandwidth = videoBandwidth / 1048576; |
- } else { |
- units = 'GiBps'; |
- videoBandwidth = videoBandwidth / 1073741824; |
- } |
- |
- var statistics = document.getElementById('statistics'); |
- statistics.innerText = |
- 'Bandwidth: ' + videoBandwidth.toFixed(2) + units + |
- ', Frame Rate: ' + |
- (stats['video_frame_rate'] ? |
- stats['video_frame_rate'].toFixed(2) + ' fps' : 'n/a') + |
- ', Capture: ' + stats['capture_latency'].toFixed(2) + 'ms' + |
- ', Encode: ' + stats['encode_latency'].toFixed(2) + 'ms' + |
- ', Decode: ' + stats['decode_latency'].toFixed(2) + 'ms' + |
- ', Render: ' + stats['render_latency'].toFixed(2) + 'ms' + |
- ', Latency: ' + stats['roundtrip_latency'].toFixed(2) + 'ms'; |
- |
- // Update the stats once per second. |
- window.setTimeout(updateStatistics, 1000); |
-} |
- |
-function showToolbarPreview_() { |
- var toolbar = document.getElementById('session-toolbar'); |
- addClass(toolbar, 'toolbar-preview'); |
- window.setTimeout(removeClass, 3000, toolbar, 'toolbar-preview'); |
-} |
- |
-/** @param {number} oldState The previous state of the plugin. */ |
-function onClientStateChange_(oldState) { |
- if (!remoting.session) { |
- // If the connection has been cancelled, then we no longer have a reference |
- // to the session object and should ignore any state changes. |
- return; |
- } |
- var state = remoting.session.state; |
- if (state == remoting.ClientSession.State.CREATED) { |
- remoting.debug.log('Created plugin'); |
- } else if (state == remoting.ClientSession.State.BAD_PLUGIN_VERSION) { |
- showConnectError_(remoting.ClientError.BAD_PLUGIN_VERSION); |
- } else if (state == remoting.ClientSession.State.CONNECTING) { |
- remoting.debug.log('Connecting as ' + remoting.username); |
- } else if (state == remoting.ClientSession.State.INITIALIZING) { |
- remoting.debug.log('Initializing connection'); |
- } else if (state == remoting.ClientSession.State.CONNECTED) { |
- if (remoting.session) { |
- remoting.setMode(remoting.AppMode.IN_SESSION); |
- recenterToolbar_(); |
- showToolbarPreview_(); |
- updateStatistics(); |
- } |
- } else if (state == remoting.ClientSession.State.CLOSED) { |
- if (oldState == remoting.ClientSession.State.CONNECTED) { |
- remoting.session.removePlugin(); |
- remoting.session = null; |
- remoting.debug.log('Connection closed by host'); |
- remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED); |
- } else { |
- // The transition from CONNECTING to CLOSED state may happen |
- // only with older client plugins. Current version should go the |
- // FAILED state when connection fails. |
- showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE); |
- } |
- } else if (state == remoting.ClientSession.State.CONNECTION_FAILED) { |
- remoting.debug.log('Client plugin reported connection failed: ' + |
- remoting.session.error); |
- if (remoting.session.error == |
- remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE) { |
- showConnectError_(remoting.ClientError.HOST_IS_OFFLINE); |
- } else if (remoting.session.error == |
- remoting.ClientSession.ConnectionError.SESSION_REJECTED) { |
- showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE); |
- } else if (remoting.session.error == |
- remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL) { |
- showConnectError_(remoting.ClientError.INCOMPATIBLE_PROTOCOL); |
- } else if (remoting.session.error == |
- remoting.ClientSession.ConnectionError.NETWORK_FAILURE) { |
- showConnectError_(remoting.ClientError.OTHER_ERROR); |
- } else { |
- showConnectError_(remoting.ClientError.OTHER_ERROR); |
- } |
- } else { |
- remoting.debug.log('Unexpected client plugin state: ' + state); |
- // This should only happen if the web-app and client plugin get out of |
- // sync, and even then the version check should allow compatibility. |
- showConnectError_(remoting.ClientError.MISSING_PLUGIN); |
+function refreshEmail_() { |
+ if (!getEmail_() && remoting.oauth2.isAuthenticated()) { |
+ remoting.oauth2.getEmail(setEmail_); |
} |
} |
-function startSession_() { |
- remoting.debug.log('Starting session...'); |
- var accessCode = document.getElementById('access-code-entry'); |
- accessCode.value = ''; // The code has been validated and won't work again. |
- remoting.username = |
- /** @type {string} email must be non-NULL to get here */ getEmail(); |
- remoting.session = |
- new remoting.ClientSession(remoting.hostJid, remoting.hostPublicKey, |
- remoting.accessCode, remoting.username, |
- onClientStateChange_); |
- /** @param {string} token The auth token. */ |
- var createPluginAndConnect = function(token) { |
- remoting.session.createPluginAndConnect( |
- document.getElementById('session-mode'), |
- token); |
- }; |
- remoting.oauth2.callWithToken(createPluginAndConnect); |
-} |
+/** The key under which the email address is stored. */ |
+var KEY_EMAIL_ = 'remoting-email'; |
/** |
- * Show a client-side error message. |
+ * Save the user's email address in local storage. |
* |
- * @param {remoting.ClientError} errorTag The error to be localized and |
- * displayed. |
- * @return {void} Nothing. |
- */ |
-function showConnectError_(errorTag) { |
- remoting.debug.log('Connection failed: ' + errorTag); |
- var errorDiv = document.getElementById('connect-error-message'); |
- l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag)); |
- remoting.accessCode = ''; |
- if (remoting.session) { |
- remoting.session.disconnect(); |
- remoting.session = null; |
- } |
- remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED); |
-} |
- |
-/** |
- * @param {XMLHttpRequest} xhr The XMLHttpRequest object. |
+ * @param {?string} email The email address to place in local storage. |
* @return {void} Nothing. |
*/ |
-function parseServerResponse_(xhr) { |
- remoting.supportHostsXhr = null; |
- remoting.debug.log('parseServerResponse: status = ' + xhr.status); |
- if (xhr.status == 200) { |
- var host = /** @type {{data: {jabberId: string, publicKey: string}}} */ |
- JSON.parse(xhr.responseText); |
- if (host.data && host.data.jabberId && host.data.publicKey) { |
- remoting.hostJid = host.data.jabberId; |
- remoting.hostPublicKey = host.data.publicKey; |
- var split = remoting.hostJid.split('/'); |
- document.getElementById('connected-to').innerText = split[0]; |
- startSession_(); |
- return; |
- } |
- } |
- var errorMsg = remoting.ClientError.OTHER_ERROR; |
- if (xhr.status == 404) { |
- errorMsg = remoting.ClientError.INVALID_ACCESS_CODE; |
- } else if (xhr.status == 0) { |
- errorMsg = remoting.ClientError.NO_RESPONSE; |
- } else { |
- remoting.debug.log('The server responded: ' + xhr.responseText); |
- } |
- showConnectError_(errorMsg); |
-} |
- |
-/** @param {string} accessCode The access code, as entered by the user. |
- * @return {string} The normalized form of the code (whitespace removed). */ |
-function normalizeAccessCode_(accessCode) { |
- // Trim whitespace. |
- // TODO(sergeyu): Do we need to do any other normalization here? |
- return accessCode.replace(/\s/g, ''); |
-} |
- |
-/** @param {string} supportId The canonicalized support ID. */ |
-function resolveSupportId(supportId) { |
- var headers = { |
- 'Authorization': 'OAuth ' + remoting.oauth2.getAccessToken() |
- }; |
- |
- remoting.supportHostsXhr = remoting.xhr.get( |
- 'https://www.googleapis.com/chromoting/v1/support-hosts/' + |
- encodeURIComponent(supportId), |
- parseServerResponse_, |
- '', |
- headers); |
-} |
- |
-remoting.tryConnect = function() { |
- document.getElementById('cancel-button').disabled = false; |
- if (remoting.oauth2.needsNewAccessToken()) { |
- remoting.oauth2.refreshAccessToken(function(xhr) { |
- if (remoting.oauth2.needsNewAccessToken()) { |
- // Failed to get access token |
- remoting.debug.log('tryConnect: OAuth2 token fetch failed'); |
- showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED); |
- return; |
- } |
- remoting.tryConnectWithAccessToken(); |
- }); |
+function setEmail_(email) { |
+ if (email) { |
+ document.getElementById('current-email').innerText = email; |
} else { |
- remoting.tryConnectWithAccessToken(); |
+ // TODO(ajwong): Have a better way of showing an error. |
+ document.getElementById('current-email').innerText = '???'; |
} |
} |
-remoting.tryConnectWithAccessToken = function() { |
- if (!remoting.wcsLoader) { |
- remoting.wcsLoader = new remoting.WcsLoader(); |
- } |
- /** @param {function(string):void} setToken The callback function. */ |
- var callWithToken = function(setToken) { |
- remoting.oauth2.callWithToken(setToken); |
- }; |
- remoting.wcsLoader.start( |
- remoting.oauth2.getAccessToken(), |
- callWithToken, |
- remoting.tryConnectWithWcs); |
-} |
- |
/** |
- * WcsLoader callback, called when the wcs script has been loaded, or on error. |
- * @param {boolean} success True if the script was loaded successfully. |
+ * Read the user's email address from local storage. |
+ * |
+ * @return {?string} The email address associated with the auth credentials. |
*/ |
-remoting.tryConnectWithWcs = function(success) { |
- if (success) { |
- var accessCode = document.getElementById('access-code-entry').value; |
- remoting.accessCode = normalizeAccessCode_(accessCode); |
- // At present, only 12-digit access codes are supported, of which the first |
- // 7 characters are the supportId. |
- if (remoting.accessCode.length != kAccessCodeLen) { |
- remoting.debug.log('Bad access code length'); |
- showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE); |
- } else { |
- var supportId = remoting.accessCode.substring(0, kSupportIdLen); |
- remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); |
- resolveSupportId(supportId); |
- } |
- } else { |
- showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED); |
- } |
-} |
- |
-remoting.cancelPendingOperation = function() { |
- document.getElementById('cancel-button').disabled = true; |
- switch (remoting.getMajorMode()) { |
- case remoting.AppMode.HOST: |
- remoting.cancelShare(); |
- break; |
- case remoting.AppMode.CLIENT: |
- remoting.cancelConnect(); |
- break; |
- } |
+function getEmail_() { |
+ var result = window.localStorage.getItem(KEY_EMAIL_); |
+ return typeof result == 'string' ? result : null; |
} |
- |
/** |
* Gets the major-mode that this application should start up in. |
* |
* @return {remoting.AppMode} The mode to start in. |
*/ |
-function getAppStartupMode() { |
+function getAppStartupMode_() { |
if (!remoting.oauth2.isAuthenticated()) { |
return remoting.AppMode.UNAUTHENTICATED; |
} |
- if (isHostModeSupported()) { |
+ if (isHostModeSupported_()) { |
return remoting.AppMode.HOME; |
} else { |
return remoting.AppMode.CLIENT_UNCONNECTED; |
@@ -769,86 +151,8 @@ function getAppStartupMode() { |
* |
* @return {boolean} True if Host mode is supported. |
*/ |
-function isHostModeSupported() { |
+function isHostModeSupported_() { |
// Currently, sharing on Chromebooks is not supported. |
return !navigator.userAgent.match(/\bCrOS\b/); |
} |
- |
-/** |
- * Enable or disable scale-to-fit. |
- * |
- * @param {Element} button The scale-to-fit button. The style of this button is |
- * updated to reflect the new scaling state. |
- * @return {void} Nothing. |
- */ |
-remoting.toggleScaleToFit = function(button) { |
- remoting.scaleToFit = !remoting.scaleToFit; |
- if (remoting.scaleToFit) { |
- addClass(button, 'toggle-button-active'); |
- } else { |
- removeClass(button, 'toggle-button-active'); |
- } |
- remoting.session.updateDimensions(); |
-} |
- |
-/** |
- * Update the remoting client layout in response to a resize event. |
- * |
- * @return {void} Nothing. |
- */ |
-remoting.onResize = function() { |
- if (remoting.session) |
- remoting.session.onWindowSizeChanged(); |
- recenterToolbar_(); |
-} |
- |
-/** |
- * Disconnect the remoting client. |
- * |
- * @return {void} Nothing. |
- */ |
-remoting.disconnect = function() { |
- if (remoting.session) { |
- remoting.session.disconnect(); |
- remoting.session = null; |
- remoting.debug.log('Disconnected.'); |
- remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED); |
- } |
-} |
- |
-/** |
- * If the client is connected, or the host is shared, prompt before closing. |
- * |
- * @return {?string} The prompt string if a connection is active. |
- */ |
-remoting.promptClose = function() { |
- switch (remoting.currentMode) { |
- case remoting.AppMode.CLIENT_CONNECTING: |
- case remoting.AppMode.HOST_WAITING_FOR_CODE: |
- case remoting.AppMode.HOST_WAITING_FOR_CONNECTION: |
- case remoting.AppMode.HOST_SHARED: |
- case remoting.AppMode.IN_SESSION: |
- var result = chrome.i18n.getMessage(/*i18n-content*/'CLOSE_PROMPT'); |
- return result; |
- default: |
- return null; |
- } |
-} |
- |
-/** |
- * @param {Event} event The keyboard event. |
- * @return {void} Nothing. |
- */ |
-remoting.checkHotkeys = function(event) { |
- if (String.fromCharCode(event.which) == 'D') { |
- remoting.toggleDebugLog(); |
- } |
-} |
- |
-function recenterToolbar_() { |
- var toolbar = document.getElementById('session-toolbar'); |
- var toolbarX = (window.innerWidth - toolbar.clientWidth) / 2; |
- toolbar.style['left'] = toolbarX + 'px'; |
-} |
- |
}()); |