1 // Copyright (c) 2012 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 * Functions related to the 'client screen' for Chromoting.
12 /** @suppress {duplicate} */
13 var remoting
= remoting
|| {};
16 * @type {remoting.ClientSession} The client session object, set once the
17 * connector has invoked its onOk callback.
19 remoting
.clientSession
= null;
22 * Initiate an IT2Me connection.
24 remoting
.connectIT2Me = function() {
25 var connector
= remoting
.app
.getSessionConnector();
26 var accessCode
= document
.getElementById('access-code-entry').value
;
27 remoting
.setMode(remoting
.AppMode
.CLIENT_CONNECTING
);
28 connector
.connectIT2Me(accessCode
);
32 * Update the remoting client layout in response to a resize event.
34 * @return {void} Nothing.
36 remoting
.onResize = function() {
37 if (remoting
.clientSession
) {
38 remoting
.clientSession
.onResize();
43 * Handle changes in the visibility of the window, for example by pausing video.
45 * @return {void} Nothing.
47 remoting
.onVisibilityChanged = function() {
48 if (remoting
.clientSession
) {
49 remoting
.clientSession
.pauseVideo(
50 ('hidden' in document
) ? document
.hidden
: document
.webkitHidden
);
55 * Disconnect the remoting client.
57 * @return {void} Nothing.
59 remoting
.disconnect = function() {
60 if (!remoting
.clientSession
) {
63 if (remoting
.clientSession
.getMode() == remoting
.ClientSession
.Mode
.IT2ME
) {
64 remoting
.setMode(remoting
.AppMode
.CLIENT_SESSION_FINISHED_IT2ME
);
66 remoting
.setMode(remoting
.AppMode
.CLIENT_SESSION_FINISHED_ME2ME
);
68 remoting
.clientSession
.disconnect(remoting
.Error
.NONE
);
69 remoting
.clientSession
= null;
70 console
.log('Disconnected.');
74 * Callback function called when the state of the client plugin changes. The
75 * current and previous states are available via the |state| member variable.
77 * @param {remoting.ClientSession.StateEvent} state
79 function onClientStateChange_(state
) {
80 switch (state
.current
) {
81 case remoting
.ClientSession
.State
.CLOSED
:
82 console
.log('Connection closed by host');
83 if (remoting
.clientSession
.getMode() ==
84 remoting
.ClientSession
.Mode
.IT2ME
) {
85 remoting
.setMode(remoting
.AppMode
.CLIENT_SESSION_FINISHED_IT2ME
);
86 remoting
.hangoutSessionEvents
.raiseEvent(
87 remoting
.hangoutSessionEvents
.sessionStateChanged
,
88 remoting
.ClientSession
.State
.CLOSED
);
90 remoting
.setMode(remoting
.AppMode
.CLIENT_SESSION_FINISHED_ME2ME
);
94 case remoting
.ClientSession
.State
.FAILED
:
95 var error
= remoting
.clientSession
.getError();
96 console
.error('Client plugin reported connection failed: ' + error
);
98 error
= remoting
.Error
.UNEXPECTED
;
100 remoting
.app
.onError(error
);
104 console
.error('Unexpected client plugin state: ' + state
.current
);
105 // This should only happen if the web-app and client plugin get out of
106 // sync, so MISSING_PLUGIN is a suitable error.
107 remoting
.app
.onError(remoting
.Error
.MISSING_PLUGIN
);
111 remoting
.clientSession
.removeEventListener('stateChanged',
112 onClientStateChange_
);
113 remoting
.clientSession
.cleanup();
114 remoting
.clientSession
= null;
118 * Timer callback to update the statistics panel.
120 function updateStatistics_() {
121 if (!remoting
.clientSession
||
122 remoting
.clientSession
.getState() !=
123 remoting
.ClientSession
.State
.CONNECTED
) {
126 var perfstats
= remoting
.clientSession
.getPerfStats();
127 remoting
.stats
.update(perfstats
);
128 remoting
.clientSession
.logStatistics(perfstats
);
129 // Update the stats once per second.
130 window
.setTimeout(updateStatistics_
, 1000);
134 * Entry-point for Me2Me connections, handling showing of the host-upgrade nag
135 * dialog if necessary.
137 * @param {string} hostId The unique id of the host.
138 * @return {void} Nothing.
140 remoting
.connectMe2Me = function(hostId
) {
141 var host
= remoting
.hostList
.getHostForId(hostId
);
143 remoting
.app
.onError(remoting
.Error
.HOST_IS_OFFLINE
);
146 var webappVersion
= chrome
.runtime
.getManifest().version
;
147 if (remoting
.Host
.needsUpdate(host
, webappVersion
)) {
148 var needsUpdateMessage
=
149 document
.getElementById('host-needs-update-message');
150 l10n
.localizeElementFromTag(needsUpdateMessage
,
151 /*i18n-content*/'HOST_NEEDS_UPDATE_TITLE',
153 /** @type {Element} */
154 var connect
= document
.getElementById('host-needs-update-connect-button');
155 /** @type {Element} */
156 var cancel
= document
.getElementById('host-needs-update-cancel-button');
157 /** @param {Event} event */
158 var onClick = function(event
) {
159 connect
.removeEventListener('click', onClick
, false);
160 cancel
.removeEventListener('click', onClick
, false);
161 if (event
.target
== connect
) {
162 remoting
.connectMe2MeHostVersionAcknowledged_(host
);
164 remoting
.setMode(remoting
.AppMode
.HOME
);
167 connect
.addEventListener('click', onClick
, false);
168 cancel
.addEventListener('click', onClick
, false);
169 remoting
.setMode(remoting
.AppMode
.CLIENT_HOST_NEEDS_UPGRADE
);
171 remoting
.connectMe2MeHostVersionAcknowledged_(host
);
176 * Shows PIN entry screen localized to include the host name, and registers
177 * a host-specific one-shot event handler for the form submission.
179 * @param {remoting.Host} host The Me2Me host to which to connect.
180 * @return {void} Nothing.
182 remoting
.connectMe2MeHostVersionAcknowledged_ = function(host
) {
183 /** @type {remoting.SessionConnector} */
184 var connector
= remoting
.app
.getSessionConnector();
185 remoting
.setMode(remoting
.AppMode
.CLIENT_CONNECTING
);
188 * @param {string} tokenUrl Token-issue URL received from the host.
189 * @param {string} scope OAuth scope to request the token for.
190 * @param {string} hostPublicKey Host public key (DER and Base64 encoded).
191 * @param {function(string, string):void} onThirdPartyTokenFetched Callback.
193 var fetchThirdPartyToken = function(
194 tokenUrl
, hostPublicKey
, scope
, onThirdPartyTokenFetched
) {
195 var thirdPartyTokenFetcher
= new remoting
.ThirdPartyTokenFetcher(
196 tokenUrl
, hostPublicKey
, scope
, host
.tokenUrlPatterns
,
197 onThirdPartyTokenFetched
);
198 thirdPartyTokenFetcher
.fetchToken();
202 * @param {boolean} supportsPairing
203 * @param {function(string):void} onPinFetched
205 var requestPin = function(supportsPairing
, onPinFetched
) {
206 /** @type {Element} */
207 var pinForm
= document
.getElementById('pin-form');
208 /** @type {Element} */
209 var pinCancel
= document
.getElementById('cancel-pin-entry-button');
210 /** @type {Element} */
211 var rememberPin
= document
.getElementById('remember-pin');
212 /** @type {Element} */
213 var rememberPinCheckbox
= document
.getElementById('remember-pin-checkbox');
215 * Event handler for both the 'submit' and 'cancel' actions. Using
216 * a single handler for both greatly simplifies the task of making
217 * them one-shot. If separate handlers were used, each would have
218 * to unregister both itself and the other.
220 * @param {Event} event The click or submit event.
222 var onSubmitOrCancel = function(event
) {
223 pinForm
.removeEventListener('submit', onSubmitOrCancel
, false);
224 pinCancel
.removeEventListener('click', onSubmitOrCancel
, false);
225 var pinField
= document
.getElementById('pin-entry');
226 var pin
= pinField
.value
;
228 if (event
.target
== pinForm
) {
229 event
.preventDefault();
231 // Set the focus away from the password field. This has to be done
232 // before the password field gets hidden, to work around a Blink
233 // clipboard-handling bug - http://crbug.com/281523.
234 document
.getElementById('pin-connect-button').focus();
236 remoting
.setMode(remoting
.AppMode
.CLIENT_CONNECTING
);
238 if (/** @type {boolean} */(rememberPinCheckbox
.checked
)) {
239 /** @type {boolean} */
240 remoting
.pairingRequested
= true;
243 remoting
.setMode(remoting
.AppMode
.HOME
);
246 pinForm
.addEventListener('submit', onSubmitOrCancel
, false);
247 pinCancel
.addEventListener('click', onSubmitOrCancel
, false);
248 rememberPin
.hidden
= !supportsPairing
;
249 rememberPinCheckbox
.checked
= false;
250 var message
= document
.getElementById('pin-message');
251 l10n
.localizeElement(message
, host
.hostName
);
252 remoting
.setMode(remoting
.AppMode
.CLIENT_PIN_PROMPT
);
255 /** @param {Object} settings */
256 var connectMe2MeHostSettingsRetrieved = function(settings
) {
257 /** @type {string} */
259 /** @type {string} */
260 var sharedSecret
= '';
261 var pairingInfo
= /** @type {Object} */ (settings
['pairingInfo']);
263 clientId
= /** @type {string} */ (pairingInfo
['clientId']);
264 sharedSecret
= /** @type {string} */ (pairingInfo
['sharedSecret']);
266 connector
.connectMe2Me(host
, requestPin
, fetchThirdPartyToken
,
267 clientId
, sharedSecret
);
270 remoting
.HostSettings
.load(host
.hostId
, connectMe2MeHostSettingsRetrieved
);