1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * This class implements the functionality that is specific to desktop
8 * remoting ("Chromoting" or CRD).
13 /** @suppress {duplicate} */
14 var remoting = remoting || {};
17 * @param {remoting.Application} app The main app that owns this delegate.
19 * @implements {remoting.Application.Delegate}
21 remoting.DesktopRemoting = function(app) {
23 * TODO(garykac): Remove this reference to the Application. It's only
24 * needed to get the current mode when reporting errors. So we should be
25 * able to refactor and remove this reference cycle.
27 * @type {remoting.Application}
31 app.setDelegate(this);
34 * Whether to refresh the JID and retry the connection if the current JID
40 this.refreshHostJidIfOffline_ = true;
44 * Display the user's email address and allow access to the rest of the app,
45 * including parsing URL parameters.
47 * @param {string} email The user's email address.
48 * @param {string} fullName The user's full name. This is always null since
49 * CRD doesn't request userinfo.profile permission.
50 * @return {void} Nothing.
52 remoting.onUserInfoAvailable = function(email, fullName) {
53 document.getElementById('current-email').innerText = email;
54 document.getElementById('get-started-it2me').disabled = false;
55 document.getElementById('get-started-me2me').disabled = false;
59 * Initialize the application and register all event handlers. After this
60 * is called, the app is running and waiting for user events.
62 * @return {void} Nothing.
64 remoting.DesktopRemoting.prototype.init = function() {
65 remoting.initGlobalObjects();
66 remoting.initIdentity(remoting.onUserInfoAvailable);
68 remoting.initElementEventHandlers();
70 if (base.isAppsV2()) {
71 remoting.windowFrame = new remoting.WindowFrame(
72 document.getElementById('title-bar'));
73 remoting.optionsMenu = remoting.windowFrame.createOptionsMenu();
75 var START_FULLSCREEN = 'start-fullscreen';
76 remoting.fullscreen = new remoting.FullscreenAppsV2();
77 remoting.fullscreen.addListener(function(isFullscreen) {
78 chrome.storage.local.set({START_FULLSCREEN: isFullscreen});
80 // TODO(jamiewalch): This should be handled by the background page when the
81 // window is created, but due to crbug.com/51587 it needs to be done here.
82 // Remove this hack once that bug is fixed.
83 chrome.storage.local.get(
85 /** @param {Object} values */
87 if (values[START_FULLSCREEN]) {
88 remoting.fullscreen.activate(true);
94 remoting.fullscreen = new remoting.FullscreenAppsV1();
95 remoting.toolbar = new remoting.Toolbar(
96 document.getElementById('session-toolbar'));
97 remoting.optionsMenu = remoting.toolbar.createOptionsMenu();
99 window.addEventListener('beforeunload', remoting.promptClose, false);
100 window.addEventListener('unload', remoting.disconnect, false);
103 // When a window goes full-screen, a resize event is triggered, but the
104 // Fullscreen.isActive call is not guaranteed to return true until the
105 // full-screen event is triggered. In apps v2, the size of the window's
106 // client area is calculated differently in full-screen mode, so register
108 window.addEventListener('resize', remoting.onResize, false);
109 remoting.fullscreen.addListener(remoting.onResize);
111 remoting.initHostlist_();
113 var homeFeedback = new remoting.MenuButton(
114 document.getElementById('help-feedback-main'));
115 var toolbarFeedback = new remoting.MenuButton(
116 document.getElementById('help-feedback-toolbar'));
117 remoting.manageHelpAndFeedback(
118 document.getElementById('title-bar'));
119 remoting.manageHelpAndFeedback(
120 document.getElementById('help-feedback-toolbar'));
121 remoting.manageHelpAndFeedback(
122 document.getElementById('help-feedback-main'));
124 remoting.windowShape.updateClientWindowShape();
126 remoting.showOrHideIT2MeUi();
127 remoting.showOrHideMe2MeUi();
129 // For Apps v1, check the tab type to warn the user if they are not getting
130 // the best keyboard experience.
131 if (!base.isAppsV2() && !remoting.platformIsMac()) {
132 /** @param {boolean} isWindowed */
133 var onIsWindowed = function(isWindowed) {
135 document.getElementById('startup-mode-box-me2me').hidden = false;
136 document.getElementById('startup-mode-box-it2me').hidden = false;
139 isWindowed_(onIsWindowed);
142 remoting.ClientPlugin.factory.preloadPlugin();
146 * @return {string} Application product name to be used in UI.
148 remoting.DesktopRemoting.prototype.getApplicationName = function() {
149 return chrome.i18n.getMessage(/*i18n-content*/'PRODUCT_NAME');
153 * @return {string} The default remap keys for the current platform.
155 remoting.DesktopRemoting.prototype.getDefaultRemapKeys = function() {
157 // By default, under ChromeOS, remap the right Control key to the right
159 if (remoting.platformIsChromeOS()) {
160 remapKeys = '0x0700e4>0x0700e7';
166 * Called when a new session has been connected.
168 * @param {remoting.ClientSession} clientSession
169 * @return {void} Nothing.
171 remoting.DesktopRemoting.prototype.handleConnected = function(clientSession) {
172 // Set the text on the buttons shown under the error message so that they are
173 // easy to understand in the case where a successful connection failed, as
174 // opposed to the case where a connection never succeeded.
175 // TODO(garykac): Investigate to see if these need to be reverted to their
176 // original values in the onDisconnected method.
177 var button1 = document.getElementById('client-reconnect-button');
178 l10n.localizeElementFromTag(button1, /*i18n-content*/'RECONNECT');
179 button1.removeAttribute('autofocus');
180 var button2 = document.getElementById('client-finished-me2me-button');
181 l10n.localizeElementFromTag(button2, /*i18n-content*/'OK');
182 button2.setAttribute('autofocus', 'autofocus');
184 // Reset the refresh flag so that the next connection will retry if needed.
185 this.refreshHostJidIfOffline_ = true;
187 document.getElementById('access-code-entry').value = '';
188 remoting.setMode(remoting.AppMode.IN_SESSION);
189 if (!base.isAppsV2()) {
190 remoting.toolbar.center();
191 remoting.toolbar.preview();
194 if (remoting.pairingRequested) {
196 * @param {string} clientId
197 * @param {string} sharedSecret
199 var onPairingComplete = function(clientId, sharedSecret) {
203 sharedSecret: sharedSecret
206 var connector = remoting.app.getSessionConnector();
207 remoting.HostSettings.save(connector.getHostId(), pairingInfo);
208 connector.updatePairingInfo(clientId, sharedSecret);
210 // Use the platform name as a proxy for the local computer name.
211 // TODO(jamiewalch): Use a descriptive name for the local computer, for
212 // example, its Chrome Sync name.
214 if (remoting.platformIsMac()) {
216 } else if (remoting.platformIsWindows()) {
217 clientName = 'Windows';
218 } else if (remoting.platformIsChromeOS()) {
219 clientName = 'ChromeOS';
220 } else if (remoting.platformIsLinux()) {
221 clientName = 'Linux';
223 console.log('Unrecognized client platform. Using navigator.platform.');
224 clientName = navigator.platform;
226 clientSession.requestPairing(clientName, onPairingComplete);
231 * Called when the current session has been disconnected.
233 * @return {void} Nothing.
235 remoting.DesktopRemoting.prototype.handleDisconnected = function() {
239 * Called when the current session's connection has failed.
241 * @param {remoting.SessionConnector} connector
242 * @param {remoting.Error} error
243 * @return {void} Nothing.
245 remoting.DesktopRemoting.prototype.handleConnectionFailed = function(
247 /** @type {remoting.DesktopRemoting} */
250 /** @param {boolean} success */
251 var onHostListRefresh = function(success) {
253 var host = remoting.hostList.getHostForId(connector.getHostId());
255 connector.retryConnectMe2Me(host);
259 that.handleError(error);
262 if (error == remoting.Error.HOST_IS_OFFLINE &&
263 that.refreshHostJidIfOffline_) {
264 that.refreshHostJidIfOffline_ = false;
265 // The plugin will be re-created when the host finished refreshing
266 remoting.hostList.refresh(onHostListRefresh);
268 this.handleError(error);
273 * Called when the current session has reached the point where the host has
274 * started streaming video frames to the client.
276 * @return {void} Nothing.
278 remoting.DesktopRemoting.prototype.handleVideoStreamingStarted = function() {
282 * @param {string} type The type of the extension message.
283 * @param {Object} message The parsed extension message data.
284 * @return {boolean} Return true if the extension message was recognized.
286 remoting.DesktopRemoting.prototype.handleExtensionMessage = function(
292 * Called when an error needs to be displayed to the user.
294 * @param {remoting.Error} errorTag The error to be localized and displayed.
295 * @return {void} Nothing.
297 remoting.DesktopRemoting.prototype.handleError = function(errorTag) {
298 console.error('Connection failed: ' + errorTag);
299 remoting.accessCode = '';
301 if (errorTag === remoting.Error.AUTHENTICATION_FAILED) {
302 remoting.setMode(remoting.AppMode.HOME);
303 remoting.handleAuthFailureAndRelaunch();
307 // Reset the refresh flag so that the next connection will retry if needed.
308 this.refreshHostJidIfOffline_ = true;
310 var errorDiv = document.getElementById('connect-error-message');
311 l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
313 var mode = remoting.clientSession ? remoting.desktopConnectedView.getMode()
314 : this.app_.getSessionConnector().getConnectionMode();
315 if (mode == remoting.DesktopConnectedView.Mode.IT2ME) {
316 remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
317 remoting.hangoutSessionEvents.raiseEvent(
318 remoting.hangoutSessionEvents.sessionStateChanged,
319 remoting.ClientSession.State.FAILED
322 remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);