OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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. | |
4 | |
5 /** | |
6 * @fileoverview | |
7 * Functions related to the 'host screen' for Chromoting. | |
8 */ | |
9 | |
10 'use strict'; | |
11 | |
12 /** @suppress {duplicate} */ | |
13 var remoting = remoting || {}; | |
14 | |
15 (function() { | |
16 | |
17 /** | |
18 * @type {boolean} Whether or not the last share was cancelled by the user. | |
19 * This controls what screen is shown when the host plugin signals | |
20 * completion. | |
21 */ | |
22 var lastShareWasCancelled_ = false; | |
23 | |
24 /** | |
25 * Start a host session. This is the main entry point for the host screen, | |
26 * called directly from the onclick action of a button on the home screen. | |
27 */ | |
28 remoting.tryShare = function() { | |
29 remoting.debug.log('Attempting to share...'); | |
30 lastShareWasCancelled_ = false; | |
31 if (remoting.oauth2.needsNewAccessToken()) { | |
32 remoting.debug.log('Refreshing token...'); | |
33 remoting.oauth2.refreshAccessToken(function() { | |
34 if (remoting.oauth2.needsNewAccessToken()) { | |
35 // If we still need it, we're going to infinite loop. | |
36 showShareError_(/*i18n-content*/'ERROR_AUTHENTICATION_FAILED'); | |
37 throw 'Unable to get access token'; | |
38 } | |
39 remoting.tryShare(); | |
40 }); | |
41 return; | |
42 } | |
43 | |
44 onNatTraversalPolicyChanged_(true); // Hide warning by default. | |
45 remoting.setMode(remoting.AppMode.HOST_WAITING_FOR_CODE); | |
46 document.getElementById('cancel-button').disabled = false; | |
47 disableTimeoutCountdown_(); | |
48 | |
49 var div = document.getElementById('host-plugin-container'); | |
50 remoting.hostSession = new remoting.HostSession(); | |
51 remoting.hostSession.createPluginAndConnect( | |
52 document.getElementById('host-plugin-container'), | |
53 /** @type {string} */(remoting.oauth2.getCachedEmail()), | |
54 remoting.oauth2.getAccessToken(), | |
55 onNatTraversalPolicyChanged_, | |
56 onHostStateChanged_, | |
57 logDebugInfo_); | |
58 }; | |
59 | |
60 /** | |
61 * Callback for the host plugin to notify the web app of state changes. | |
62 * @param {remoting.HostSession.State} state The new state of the plugin. | |
63 */ | |
64 function onHostStateChanged_(state) { | |
65 if (state == remoting.HostSession.State.STARTING) { | |
66 // Nothing to do here. | |
67 remoting.debug.log('Host plugin state: STARTING'); | |
68 | |
69 } else if (state == remoting.HostSession.State.REQUESTED_ACCESS_CODE) { | |
70 // Nothing to do here. | |
71 remoting.debug.log('Host plugin state: REQUESTED_ACCESS_CODE'); | |
72 | |
73 } else if (state == remoting.HostSession.State.RECEIVED_ACCESS_CODE) { | |
74 remoting.debug.log('Host plugin state: RECEIVED_ACCESS_CODE'); | |
75 var accessCode = remoting.hostSession.getAccessCode(); | |
76 var accessCodeDisplay = document.getElementById('access-code-display'); | |
77 accessCodeDisplay.innerText = ''; | |
78 // Display the access code in groups of four digits for readability. | |
79 var kDigitsPerGroup = 4; | |
80 for (var i = 0; i < accessCode.length; i += kDigitsPerGroup) { | |
81 var nextFourDigits = document.createElement('span'); | |
82 nextFourDigits.className = 'access-code-digit-group'; | |
83 nextFourDigits.innerText = accessCode.substring(i, i + kDigitsPerGroup); | |
84 accessCodeDisplay.appendChild(nextFourDigits); | |
85 } | |
86 accessCodeExpiresIn_ = remoting.hostSession.getAccessCodeLifetime(); | |
87 if (accessCodeExpiresIn_ > 0) { // Check it hasn't expired. | |
88 accessCodeTimerId_ = setInterval( | |
89 'remoting.decrementAccessCodeTimeout_()', 1000); | |
90 timerRunning_ = true; | |
91 updateAccessCodeTimeoutElement_(); | |
92 updateTimeoutStyles_(); | |
93 remoting.setMode(remoting.AppMode.HOST_WAITING_FOR_CONNECTION); | |
94 } else { | |
95 // This can only happen if the cloud tells us that the code lifetime is | |
96 // <= 0s, which shouldn't happen so we don't care how clean this UX is. | |
97 remoting.debug.log('Access code already invalid on receipt!'); | |
98 remoting.cancelShare(); | |
99 } | |
100 | |
101 } else if (state == remoting.HostSession.State.CONNECTED) { | |
102 remoting.debug.log('Host plugin state: CONNECTED'); | |
103 var element = document.getElementById('host-shared-message'); | |
104 var client = remoting.hostSession.getClient(); | |
105 l10n.localizeElement(element, client); | |
106 remoting.setMode(remoting.AppMode.HOST_SHARED); | |
107 disableTimeoutCountdown_(); | |
108 | |
109 } else if (state == remoting.HostSession.State.DISCONNECTING) { | |
110 remoting.debug.log('Host plugin state: DISCONNECTING'); | |
111 | |
112 } else if (state == remoting.HostSession.State.DISCONNECTED) { | |
113 remoting.debug.log('Host plugin state: DISCONNECTED'); | |
114 if (remoting.currentMode != remoting.AppMode.HOST_SHARE_FAILED) { | |
115 // If an error is being displayed, then the plugin should not be able to | |
116 // hide it by setting the state. Errors must be dismissed by the user | |
117 // clicking OK, which puts the app into mode HOME. | |
118 if (lastShareWasCancelled_) { | |
119 remoting.setMode(remoting.AppMode.HOME); | |
120 } else { | |
121 remoting.setMode(remoting.AppMode.HOST_SHARE_FINISHED); | |
122 } | |
123 } | |
124 remoting.hostSession.removePlugin(); | |
125 | |
126 } else if (state == remoting.HostSession.State.ERROR) { | |
127 remoting.debug.log('Host plugin state: ERROR'); | |
128 showShareError_(/*i18n-content*/'ERROR_GENERIC'); | |
129 } else { | |
130 remoting.debug.log('Unknown state -> ' + state); | |
131 } | |
132 } | |
133 | |
134 /** | |
135 * This is the callback that the host plugin invokes to indicate that there | |
136 * is additional debug log info to display. | |
137 * @param {string} msg The message (which will not be localized) to be logged. | |
138 */ | |
139 function logDebugInfo_(msg) { | |
140 remoting.debug.log('plugin: ' + msg); | |
141 } | |
142 | |
143 /** | |
144 * Show a host-side error message. | |
145 * | |
146 * @param {string} errorTag The error message to be localized and displayed. | |
147 * @return {void} Nothing. | |
148 */ | |
149 function showShareError_(errorTag) { | |
150 var errorDiv = document.getElementById('host-plugin-error'); | |
151 l10n.localizeElementFromTag(errorDiv, errorTag); | |
152 remoting.debug.log('Sharing error: ' + errorTag); | |
153 remoting.setMode(remoting.AppMode.HOST_SHARE_FAILED); | |
154 } | |
155 | |
156 /** | |
157 * Cancel an active or pending share operation. | |
158 * | |
159 * @return {void} Nothing. | |
160 */ | |
161 remoting.cancelShare = function() { | |
162 remoting.debug.log('Canceling share...'); | |
163 remoting.lastShareWasCancelled = true; | |
164 try { | |
165 remoting.hostSession.disconnect(); | |
166 } catch (error) { | |
167 // Hack to force JSCompiler type-safety. | |
168 var errorTyped = /** @type {{description: string}} */ error; | |
169 remoting.debug.log('Error disconnecting: ' + errorTyped.description + | |
170 '. The host plugin probably crashed.'); | |
171 // TODO(jamiewalch): Clean this up. We should have a class representing | |
172 // the host plugin, like we do for the client, which should handle crash | |
173 // reporting and it should use a more detailed error message than the | |
174 // default 'generic' one. See crbug.com/94624 | |
175 showShareError_(/*i18n-content*/'ERROR_GENERIC'); | |
176 } | |
177 disableTimeoutCountdown_(); | |
178 }; | |
179 | |
180 /** | |
181 * @type {boolean} Whether or not the access code timeout countdown is running. | |
182 */ | |
183 var timerRunning_ = false; | |
garykac
2011/10/27 22:32:39
I was contemplatingpulling these timer routines in
Jamie
2011/10/27 22:51:37
I think in order to do that, more of them would ne
| |
184 | |
185 /** | |
186 * @type {number} The id of the access code expiry countdown timer. | |
187 */ | |
188 var accessCodeTimerId_ = 0; | |
189 | |
190 /** | |
191 * @type {number} The number of seconds until the access code expires. | |
192 */ | |
193 var accessCodeExpiresIn_ = 0; | |
194 | |
195 /** | |
196 * The timer callback function, which needs to be visible from the global | |
197 * namespace. | |
198 */ | |
199 remoting.decrementAccessCodeTimeout_ = function() { | |
200 --accessCodeExpiresIn_; | |
201 updateAccessCodeTimeoutElement_(); | |
202 }; | |
203 | |
204 /** | |
205 * Stop the access code timeout countdown if it is running. | |
206 */ | |
207 function disableTimeoutCountdown_() { | |
208 if (timerRunning_) { | |
209 clearInterval(accessCodeTimerId_); | |
210 timerRunning_ = false; | |
211 updateTimeoutStyles_(); | |
212 } | |
213 } | |
214 | |
215 /** | |
216 * Constants controlling the access code timer countdown display. | |
217 */ | |
218 var ACCESS_CODE_TIMER_DISPLAY_THRESHOLD_ = 30; | |
219 var ACCESS_CODE_RED_THRESHOLD_ = 10; | |
220 | |
221 /** | |
222 * Show/hide or restyle various elements, depending on the remaining countdown | |
223 * and timer state. | |
224 * | |
225 * @return {boolean} True if the timeout is in progress, false if it has | |
226 * expired. | |
227 */ | |
228 function updateTimeoutStyles_() { | |
229 if (timerRunning_) { | |
230 if (accessCodeExpiresIn_ <= 0) { | |
231 remoting.cancelShare(); | |
232 return false; | |
233 } | |
234 if (accessCodeExpiresIn_ <= ACCESS_CODE_RED_THRESHOLD_) { | |
235 addClass(document.getElementById('access-code-display'), 'expiring'); | |
236 } else { | |
237 removeClass(document.getElementById('access-code-display'), 'expiring'); | |
238 } | |
239 } | |
240 document.getElementById('access-code-countdown').hidden = | |
241 (accessCodeExpiresIn_ > ACCESS_CODE_TIMER_DISPLAY_THRESHOLD_) || | |
242 !timerRunning_; | |
243 return true; | |
244 } | |
245 | |
246 /** | |
247 * Update the text and appearance of the access code timeout element to | |
248 * reflect the time remaining. | |
249 */ | |
250 function updateAccessCodeTimeoutElement_() { | |
251 var pad = (accessCodeExpiresIn_ < 10) ? '0:0' : '0:'; | |
252 l10n.localizeElement(document.getElementById('seconds-remaining'), | |
253 pad + accessCodeExpiresIn_); | |
254 if (!updateTimeoutStyles_()) { | |
255 disableTimeoutCountdown_(); | |
256 } | |
257 } | |
258 | |
259 /** | |
260 * Callback to show or hide the NAT traversal warning when the policy changes. | |
261 * @param {boolean} enabled True if NAT traversal is enabled. | |
262 * @return {void} Nothing. | |
263 */ | |
264 function onNatTraversalPolicyChanged_(enabled) { | |
265 var container = document.getElementById('nat-box-container'); | |
266 container.hidden = enabled; | |
267 } | |
268 | |
269 }()); | |
OLD | NEW |