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