Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(748)

Side by Side Diff: remoting/webapp/base/js/application.js

Issue 1016373003: [Chromoting] Change Application.Delegate to proper subclass of Application. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comments; remove desktopDelegateForTesting Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview 6 * @fileoverview
7 * Interface abstracting the Application functionality. 7 * Interface abstracting the Application functionality.
8 */ 8 */
9 9
10 'use strict'; 10 'use strict';
11 11
12 /** @suppress {duplicate} */ 12 /** @suppress {duplicate} */
13 var remoting = remoting || {}; 13 var remoting = remoting || {};
14 14
15 /** 15 /**
16 * The interface specifies the methods that a subclass of remoting.Application
17 * is required implement to override the default behavior.
18 *
19 * @interface
20 */
21 remoting.ApplicationInterface = function() {};
22
23 /**
24 * @return {string} Application product name to be used in UI.
25 */
26 remoting.ApplicationInterface.prototype.getApplicationName = function() {};
27
28 /**
29 * Report an authentication error to the user. This is called in lieu of
30 * startApplication() if the user cannot be authenticated or if they decline
31 * the app permissions.
32 *
33 * @param {!remoting.Error} error The failure reason.
34 */
35 remoting.ApplicationInterface.prototype.signInFailed = function(error) {};
36
37 /**
38 * Initialize the application. This is called before an OAuth token is requested
39 * and should be used for tasks such as initializing the DOM, registering event
40 * handlers, etc. After this is called, the app is running and waiting for
41 * user events.
42 *
43 * @return {void} Nothing.
44 */
45 remoting.ApplicationInterface.prototype.initApplication = function() {};
46
47 /**
48 * Start the application. Once startApplication() is called, we can assume that
49 * the user has consented to all permissions specified in the manifest.
50 *
51 * @param {string} token An OAuth access token. The app should not cache
52 * this token, but can assume that it will remain valid during application
53 * start-up.
54 */
55 remoting.ApplicationInterface.prototype.startApplication = function(token) {};
56
57
58 /**
16 * @param {Array<string>} appCapabilities Array of application capabilities. 59 * @param {Array<string>} appCapabilities Array of application capabilities.
17 * @constructor 60 * @constructor
61 * @implements {remoting.ApplicationInterface}
18 */ 62 */
19 remoting.Application = function(appCapabilities) { 63 remoting.Application = function(appCapabilities) {
20 /** @private {remoting.Application.Delegate} */ 64 // Create global objects.
21 this.delegate_ = null; 65 remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory();
66 remoting.SessionConnector.factory =
67 new remoting.DefaultSessionConnectorFactory();
garykac 2015/03/23 18:44:22 Moved here from start() since this is required to
Jamie 2015/03/25 20:00:39 The purpose of these factories is to allow test co
garykac 2015/03/26 01:41:57 Previously, they were setup in the start() functio
22 68
23 /** @private {Array<string>} */ 69 /** @private {Array<string>} */
24 this.appCapabilities_ = [ 70 this.appCapabilities_ = [
25 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION, 71 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
26 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS, 72 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
27 remoting.ClientSession.Capability.VIDEO_RECORDER 73 remoting.ClientSession.Capability.VIDEO_RECORDER
28 ]; 74 ];
29 // Append the app-specific capabilities. 75 // Append the app-specific capabilities.
30 this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities); 76 this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities);
31 77
32 /** @private {remoting.SessionConnector} */ 78 /** @protected {remoting.SessionConnector} */
33 this.sessionConnector_ = null; 79 this.sessionConnector_ = remoting.SessionConnector.factory.createConnector(
garykac 2015/03/23 18:44:22 Moved here from getter.
80 document.getElementById('client-container'),
81 this.onConnected.bind(this),
82 this.onError.bind(this),
83 this.onConnectionFailed.bind(this),
84 this.appCapabilities_);
34 85
35 /** @private {base.Disposable} */ 86 /** @private {base.Disposable} */
36 this.sessionConnectedHooks_ = null; 87 this.sessionConnectedHooks_ = null;
37 }; 88 };
38 89
39 /** 90 /**
40 * @param {remoting.Application.Delegate} appDelegate The delegate that 91 * @return {remoting.SessionConnector} The session connector.
41 * contains the app-specific functionality.
42 */ 92 */
43 remoting.Application.prototype.setDelegate = function(appDelegate) { 93 remoting.Application.prototype.getSessionConnector = function() {
44 this.delegate_ = appDelegate; 94 return this.sessionConnector_;
45 }; 95 };
46 96
47 /** 97 /**
48 * @return {string} Application product name to be used in UI.
49 */
50 remoting.Application.prototype.getApplicationName = function() {
51 return this.delegate_.getApplicationName();
52 };
53
54 /**
55 * @param {remoting.ClientSession.Capability} capability 98 * @param {remoting.ClientSession.Capability} capability
56 * @return {boolean} 99 * @return {boolean}
57 */ 100 */
58 remoting.Application.prototype.hasCapability = function(capability) { 101 remoting.Application.prototype.hasCapability = function(capability) {
59 var capabilities = this.appCapabilities_; 102 var capabilities = this.appCapabilities_;
60 return capabilities.indexOf(capability) != -1; 103 return capabilities.indexOf(capability) != -1;
61 }; 104 };
62 105
106
107 /** @return {string} */
Jamie 2015/03/24 21:57:05 AFAICT, these functions are essentially boilerplat
garykac 2015/03/26 01:41:57 Done.
108 remoting.Application.prototype.getApplicationName = function() {
109 throw "Subclass must override";
Jamie 2015/03/24 21:57:05 base.assert would be more appropriate here.
garykac 2015/03/26 01:41:57 Done.
110 };
111
112 /** @param {!remoting.Error} error */
113 remoting.Application.prototype.signInFailed = function(error) {
114 throw "Subclass must override";
115 };
116
117 remoting.Application.prototype.initApplication = function() {
118 throw "Subclass must override";
119 };
120
121 /** @param {string} token */
122 remoting.Application.prototype.startApplication = function(token) {
123 throw "Subclass must override";
124 };
125
126
63 /** 127 /**
64 * Initialize the application and register all event handlers. After this 128 * Initialize the application and register all event handlers. After this
65 * is called, the app is running and waiting for user events. 129 * is called, the app is running and waiting for user events.
66 * 130 *
67 * @return {void} Nothing. 131 * @return {void} Nothing.
68 */ 132 */
69 remoting.Application.prototype.start = function() { 133 remoting.Application.prototype.start = function() {
70 // Create global objects.
71 remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory();
72 remoting.SessionConnector.factory =
73 new remoting.DefaultSessionConnectorFactory();
74
75 // TODO(garykac): This should be owned properly rather than living in the 134 // TODO(garykac): This should be owned properly rather than living in the
76 // global 'remoting' namespace. 135 // global 'remoting' namespace.
77 remoting.settings = new remoting.Settings(); 136 remoting.settings = new remoting.Settings();
78 137
79 remoting.initGlobalObjects(); 138 remoting.initGlobalObjects();
80 remoting.initIdentity(); 139 remoting.initIdentity();
81 140
82 this.delegate_.init(); 141 this.initApplication();
83 142
84 var that = this; 143 var that = this;
85 remoting.identity.getToken().then( 144 remoting.identity.getToken().
86 this.delegate_.start.bind(this.delegate_, this.getSessionConnector()) 145 then(this.startApplication.bind(this)).
87 ).catch(remoting.Error.handler( 146 catch(remoting.Error.handler(
88 function(/** !remoting.Error */ error) { 147 function(/** !remoting.Error */ error) {
89 if (error.hasTag(remoting.Error.Tag.CANCELLED)) { 148 if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
90 that.exit(); 149 that.exit();
91 } else { 150 } else {
92 that.delegate_.signInFailed(error); 151 that.signInFailed(error);
93 } 152 }
94 } 153 }
95 ) 154 )
96 ); 155 );
97 }; 156 };
98 157
99 /** 158 /**
100 * Quit the application. 159 * Quit the application.
101 */ 160 */
102 remoting.Application.prototype.exit = function() { 161 remoting.Application.prototype.exit = function() {
103 this.delegate_.handleExit();
Jamie 2015/03/24 21:57:05 I'm concerned about a loss of readability here. Wi
Jamie 2015/03/25 20:00:39 As discussed off-line, please refactor so that all
garykac 2015/03/26 01:41:57 Done.
104 chrome.app.window.current().close(); 162 chrome.app.window.current().close();
105 }; 163 };
106 164
107 /** Disconnect the remoting client. */ 165 /** Disconnect the remoting client. */
108 remoting.Application.prototype.disconnect = function() { 166 remoting.Application.prototype.disconnect = function() {
109 if (remoting.clientSession) { 167 if (remoting.clientSession) {
110 remoting.clientSession.disconnect(remoting.Error.none()); 168 remoting.clientSession.disconnect(remoting.Error.none());
111 console.log('Disconnected.'); 169 console.log('Disconnected.');
112 } 170 }
113 }; 171 };
114 172
115 /**
116 * Called when a new session has been connected.
117 *
118 * @param {remoting.ConnectionInfo} connectionInfo
119 * @return {void} Nothing.
120 */
121 remoting.Application.prototype.onConnected = function(connectionInfo) {
garykac 2015/03/23 18:44:22 This has been moved a bit further down so that it
122 this.sessionConnectedHooks_ = new base.Disposables(
123 new base.EventHook(connectionInfo.session(), 'stateChanged',
124 this.onSessionFinished_.bind(this)),
125 new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000)
126 );
127 remoting.clipboard.startSession();
128
129 this.delegate_.handleConnected(connectionInfo);
130 };
131 173
132 /** 174 /**
133 * Called when the current session has been disconnected. 175 * Called when the current session has been disconnected.
134 * 176 *
135 * @return {void} Nothing. 177 * @return {void} Nothing.
136 */ 178 */
137 remoting.Application.prototype.onDisconnected = function() { 179 remoting.Application.prototype.onDisconnected = function() {
Jamie 2015/03/25 20:00:39 Under the new "pure-virtual or final" model, I thi
garykac 2015/03/26 01:41:57 All of them except getApplicationName are now @pro
138 this.delegate_.handleDisconnected();
garykac 2015/03/23 18:44:22 These redirects are no longer needed. Subclass wil
139 }; 180 };
140 181
141 /** 182 /**
142 * Called when the current session's connection has failed. 183 * Called when the current session's connection has failed.
143 * 184 *
144 * @param {!remoting.Error} error 185 * @param {!remoting.Error} error
145 * @return {void} Nothing. 186 * @return {void} Nothing.
146 */ 187 */
147 remoting.Application.prototype.onConnectionFailed = function(error) { 188 remoting.Application.prototype.onConnectionFailed = function(error) {
148 this.delegate_.handleConnectionFailed(this.sessionConnector_, error);
149 }; 189 };
150 190
151 /** 191 /**
152 * Called when an error needs to be displayed to the user. 192 * Called when an error needs to be displayed to the user.
153 * 193 *
154 * @param {!remoting.Error} errorTag The error to be localized and displayed. 194 * @param {!remoting.Error} errorTag The error to be localized and displayed.
155 * @return {void} Nothing. 195 * @return {void} Nothing.
156 */ 196 */
157 remoting.Application.prototype.onError = function(errorTag) { 197 remoting.Application.prototype.onError = function(errorTag) {
158 this.delegate_.handleError(errorTag);
159 }; 198 };
160 199
161 /** 200 /**
162 * @return {remoting.SessionConnector} A session connector, creating a new one 201 * Called when a new session has been connected.
163 * if necessary. 202 *
203 * @param {remoting.ConnectionInfo} connectionInfo
204 * @return {void} Nothing.
164 */ 205 */
165 remoting.Application.prototype.getSessionConnector = function() { 206 remoting.Application.prototype.onConnected = function(connectionInfo) {
166 // TODO(garykac): Check if this can be initialized in the ctor. 207 this.sessionConnectedHooks_ = new base.Disposables(
garykac 2015/03/23 18:44:22 Recent changes make this easy to move into the con
167 if (!this.sessionConnector_) { 208 new base.EventHook(connectionInfo.session(), 'stateChanged',
168 this.sessionConnector_ = remoting.SessionConnector.factory.createConnector( 209 this.onSessionFinished_.bind(this)),
169 document.getElementById('client-container'), 210 new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000)
170 this.onConnected.bind(this), 211 );
171 this.onError.bind(this), 212 remoting.clipboard.startSession();
172 this.onConnectionFailed.bind(this),
173 this.appCapabilities_);
174 }
175 return this.sessionConnector_;
176 }; 213 };
177 214
178 /** 215 /**
179 * Callback function called when the state of the client plugin changes. The 216 * Callback function called when the state of the client plugin changes. The
180 * current and previous states are available via the |state| member variable. 217 * current and previous states are available via the |state| member variable.
181 * 218 *
182 * @param {remoting.ClientSession.StateEvent=} state 219 * @param {remoting.ClientSession.StateEvent=} state
183 * @private 220 * @private
184 */ 221 */
185 remoting.Application.prototype.onSessionFinished_ = function(state) { 222 remoting.Application.prototype.onSessionFinished_ = function(state) {
(...skipping 26 matching lines...) Expand all
212 }; 249 };
213 250
214 /** @private */ 251 /** @private */
215 remoting.Application.prototype.updateStatistics_ = function() { 252 remoting.Application.prototype.updateStatistics_ = function() {
216 var perfstats = remoting.clientSession.getPerfStats(); 253 var perfstats = remoting.clientSession.getPerfStats();
217 remoting.stats.update(perfstats); 254 remoting.stats.update(perfstats);
218 remoting.clientSession.logStatistics(perfstats); 255 remoting.clientSession.logStatistics(perfstats);
219 }; 256 };
220 257
221 258
222 /**
223 * @interface
224 */
225 remoting.Application.Delegate = function() {};
226
227 /**
228 * Initialize the application. This is called before an OAuth token is requested
229 * and should be used for tasks such as initializing the DOM, registering event
230 * handlers, etc.
231 */
232 remoting.Application.Delegate.prototype.init = function() {};
233
234 /**
235 * Start the application. Once start() is called, the delegate can assume that
236 * the user has consented to all permissions specified in the manifest.
237 *
238 * @param {remoting.SessionConnector} connector
239 * @param {string} token An OAuth access token. The delegate should not cache
240 * this token, but can assume that it will remain valid during application
241 * start-up.
242 */
243 remoting.Application.Delegate.prototype.start = function(connector, token) {};
244
245 /**
246 * Report an authentication error to the user. This is called in lieu of start()
247 * if the user cannot be authenticated.
248 *
249 * @param {!remoting.Error} error The failure reason.
250 */
251 remoting.Application.Delegate.prototype.signInFailed = function(error) {};
252
253 /**
254 * @return {string} Application product name to be used in UI.
255 */
256 remoting.Application.Delegate.prototype.getApplicationName = function() {};
257
258 /**
259 * Called when a new session has been connected.
260 *
261 * @param {remoting.ConnectionInfo} connectionInfo
262 * @return {void} Nothing.
263 */
264 remoting.Application.Delegate.prototype.handleConnected = function(
265 connectionInfo) {};
266
267 /**
268 * Called when the current session has been disconnected.
269 *
270 * @return {void} Nothing.
271 */
272 remoting.Application.Delegate.prototype.handleDisconnected = function() {};
273
274 /**
275 * Called when the current session's connection has failed.
276 *
277 * @param {remoting.SessionConnector} connector
278 * @param {!remoting.Error} error
279 * @return {void} Nothing.
280 */
281 remoting.Application.Delegate.prototype.handleConnectionFailed =
282 function(connector, error) {};
283
284 /**
285 * Called when an error needs to be displayed to the user.
286 *
287 * @param {!remoting.Error} errorTag The error to be localized and displayed.
288 * @return {void} Nothing.
289 */
290 remoting.Application.Delegate.prototype.handleError = function(errorTag) {};
291
292 /**
293 * Perform any application-specific cleanup before exiting. This is called in
294 * lieu of start() if the user declines the app permissions, and will usually
295 * be called immediately prior to exiting, although delegates should not rely
296 * on this.
297 */
298 remoting.Application.Delegate.prototype.handleExit = function() {};
299
300
301 /** @type {remoting.Application} */ 259 /** @type {remoting.Application} */
302 remoting.app = null; 260 remoting.app = null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698