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

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: sync/merge 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 * @param {Array<string>} appCapabilities Array of application capabilities. 16 * @param {Array<string>} appCapabilities Array of application capabilities.
17 * @constructor 17 * @constructor
18 * @implements {remoting.ApplicationInterface}
18 */ 19 */
19 remoting.Application = function(appCapabilities) { 20 remoting.Application = function(appCapabilities) {
20 /** @private {remoting.Application.Delegate} */ 21 // Create global factories.
21 this.delegate_ = null; 22 remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory();
23 remoting.SessionConnector.factory =
24 new remoting.DefaultSessionConnectorFactory();
22 25
23 /** @private {Array<string>} */ 26 /** @private {Array<string>} */
24 this.appCapabilities_ = [ 27 this.appCapabilities_ = [
25 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION, 28 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
26 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS, 29 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
27 remoting.ClientSession.Capability.VIDEO_RECORDER 30 remoting.ClientSession.Capability.VIDEO_RECORDER
28 ]; 31 ];
29 // Append the app-specific capabilities. 32 // Append the app-specific capabilities.
30 this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities); 33 this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities);
31 34
32 /** @private {remoting.SessionConnector} */ 35 /** @protected {remoting.SessionConnector} */
33 this.sessionConnector_ = null; 36 this.sessionConnector_ = remoting.SessionConnector.factory.createConnector(
37 document.getElementById('client-container'),
38 this.onConnected_.bind(this),
39 this.onError_.bind(this),
40 this.onConnectionFailed_.bind(this),
41 this.appCapabilities_);
34 42
35 /** @private {base.Disposable} */ 43 /** @private {base.Disposable} */
36 this.sessionConnectedHooks_ = null; 44 this.sessionConnectedHooks_ = null;
37 }; 45 };
38 46
39 /** 47 /**
40 * @param {remoting.Application.Delegate} appDelegate The delegate that 48 * @return {remoting.SessionConnector} The session connector.
41 * contains the app-specific functionality.
42 */ 49 */
43 remoting.Application.prototype.setDelegate = function(appDelegate) { 50 remoting.Application.prototype.getSessionConnector = function() {
44 this.delegate_ = appDelegate; 51 return this.sessionConnector_;
45 }; 52 };
46 53
47 /** 54 /**
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 55 * @param {remoting.ClientSession.Capability} capability
56 * @return {boolean} 56 * @return {boolean}
57 */ 57 */
58 remoting.Application.prototype.hasCapability = function(capability) { 58 remoting.Application.prototype.hasCapability = function(capability) {
59 var capabilities = this.appCapabilities_; 59 var capabilities = this.appCapabilities_;
60 return capabilities.indexOf(capability) != -1; 60 return capabilities.indexOf(capability) != -1;
61 }; 61 };
62 62
63 /* Disconnect the remoting client. */
64 remoting.Application.prototype.disconnect = function() {
65 if (remoting.clientSession) {
66 remoting.clientSession.disconnect(remoting.Error.none());
67 console.log('Disconnected.');
68 }
69 };
70
71 /* Public method to exit the application. */
72 remoting.Application.prototype.quit = function() {
73 this.exitApplication_();
74 };
75
76 /**
77 * Close the main window when quitting the application. This should be called
78 * by exitApplication() in the subclass.
79 * @protected
80 */
81 remoting.Application.prototype.closeMainWindow_ = function() {
82 chrome.app.window.current().close();
83 };
84
63 /** 85 /**
64 * Initialize the application and register all event handlers. After this 86 * Initialize the application and register all event handlers. After this
65 * is called, the app is running and waiting for user events. 87 * is called, the app is running and waiting for user events.
66 *
67 * @return {void} Nothing.
68 */ 88 */
69 remoting.Application.prototype.start = function() { 89 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 90 // TODO(garykac): This should be owned properly rather than living in the
76 // global 'remoting' namespace. 91 // global 'remoting' namespace.
77 remoting.settings = new remoting.Settings(); 92 remoting.settings = new remoting.Settings();
78 93
79 remoting.initGlobalObjects(); 94 remoting.initGlobalObjects();
80 remoting.initIdentity(); 95 remoting.initIdentity();
81 96
82 this.delegate_.init(); 97 this.initApplication_();
83 98
84 var that = this; 99 var that = this;
85 remoting.identity.getToken().then( 100 remoting.identity.getToken().
86 this.delegate_.start.bind(this.delegate_, this.getSessionConnector()) 101 then(this.startApplication_.bind(this)).
87 ).catch(remoting.Error.handler( 102 catch(remoting.Error.handler(
88 function(/** !remoting.Error */ error) { 103 function(/** !remoting.Error */ error) {
89 if (error.hasTag(remoting.Error.Tag.CANCELLED)) { 104 if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
90 that.exit(); 105 that.exitApplication_();
91 } else { 106 } else {
92 that.delegate_.signInFailed(error); 107 that.signInFailed_(error);
93 } 108 }
94 } 109 }
95 ) 110 )
96 ); 111 );
97 }; 112 };
98 113
99 /** 114 /**
100 * Quit the application.
101 */
102 remoting.Application.prototype.exit = function() {
103 this.delegate_.handleExit();
104 chrome.app.window.current().close();
105 };
106
107 /** Disconnect the remoting client. */
108 remoting.Application.prototype.disconnect = function() {
109 if (remoting.clientSession) {
110 remoting.clientSession.disconnect(remoting.Error.none());
111 console.log('Disconnected.');
112 }
113 };
114
115 /**
116 * Called when a new session has been connected. 115 * Called when a new session has been connected.
117 * 116 *
118 * @param {remoting.ConnectionInfo} connectionInfo 117 * @param {remoting.ConnectionInfo} connectionInfo
119 * @return {void} Nothing. 118 * @return {void} Nothing.
119 * @protected
120 */ 120 */
121 remoting.Application.prototype.onConnected = function(connectionInfo) { 121 remoting.Application.prototype.initSession_ = function(connectionInfo) {
122 this.sessionConnectedHooks_ = new base.Disposables( 122 this.sessionConnectedHooks_ = new base.Disposables(
123 new base.EventHook(connectionInfo.session(), 'stateChanged', 123 new base.EventHook(connectionInfo.session(), 'stateChanged',
124 this.onSessionFinished_.bind(this)), 124 this.onSessionFinished_.bind(this)),
125 new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000) 125 new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000)
126 ); 126 );
127 remoting.clipboard.startSession(); 127 remoting.clipboard.startSession();
128
129 this.delegate_.handleConnected(connectionInfo);
130 }; 128 };
131 129
132 /** 130 /**
133 * Called when the current session has been disconnected.
134 *
135 * @return {void} Nothing.
136 */
137 remoting.Application.prototype.onDisconnected = function() {
138 this.delegate_.handleDisconnected();
139 };
140
141 /**
142 * Called when the current session's connection has failed.
143 *
144 * @param {!remoting.Error} error
145 * @return {void} Nothing.
146 */
147 remoting.Application.prototype.onConnectionFailed = function(error) {
148 this.delegate_.handleConnectionFailed(this.sessionConnector_, error);
149 };
150
151 /**
152 * Called when an error needs to be displayed to the user.
153 *
154 * @param {!remoting.Error} errorTag The error to be localized and displayed.
155 * @return {void} Nothing.
156 */
157 remoting.Application.prototype.onError = function(errorTag) {
158 this.delegate_.handleError(errorTag);
159 };
160
161 /**
162 * @return {remoting.SessionConnector} A session connector, creating a new one
163 * if necessary.
164 */
165 remoting.Application.prototype.getSessionConnector = function() {
166 // TODO(garykac): Check if this can be initialized in the ctor.
167 if (!this.sessionConnector_) {
168 this.sessionConnector_ = remoting.SessionConnector.factory.createConnector(
169 document.getElementById('client-container'),
170 this.onConnected.bind(this),
171 this.onError.bind(this),
172 this.onConnectionFailed.bind(this),
173 this.appCapabilities_);
174 }
175 return this.sessionConnector_;
176 };
177
178 /**
179 * Callback function called when the state of the client plugin changes. The 131 * Callback function called when the state of the client plugin changes. The
180 * current and previous states are available via the |state| member variable. 132 * current and previous states are available via the |state| member variable.
181 * 133 *
182 * @param {remoting.ClientSession.StateEvent=} state 134 * @param {remoting.ClientSession.StateEvent=} state
183 * @private 135 * @private
184 */ 136 */
185 remoting.Application.prototype.onSessionFinished_ = function(state) { 137 remoting.Application.prototype.onSessionFinished_ = function(state) {
186 switch (state.current) { 138 switch (state.current) {
187 case remoting.ClientSession.State.CLOSED: 139 case remoting.ClientSession.State.CLOSED:
188 console.log('Connection closed by host'); 140 console.log('Connection closed by host');
189 this.onDisconnected(); 141 this.onDisconnected_();
190 break; 142 break;
191 case remoting.ClientSession.State.FAILED: 143 case remoting.ClientSession.State.FAILED:
192 var error = remoting.clientSession.getError(); 144 var error = remoting.clientSession.getError();
193 console.error('Client plugin reported connection failed: ' + 145 console.error('Client plugin reported connection failed: ' +
194 error.toString()); 146 error.toString());
195 if (error === null) { 147 if (error === null) {
196 error = remoting.Error.unexpected(); 148 error = remoting.Error.unexpected();
197 } 149 }
198 this.onError(error); 150 this.onError_(error);
199 break; 151 break;
200 152
201 default: 153 default:
202 console.error('Unexpected client plugin state: ' + state.current); 154 console.error('Unexpected client plugin state: ' + state.current);
203 // This should only happen if the web-app and client plugin get out of 155 // This should only happen if the web-app and client plugin get out of
204 // sync, so MISSING_PLUGIN is a suitable error. 156 // sync, so MISSING_PLUGIN is a suitable error.
205 this.onError(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); 157 this.onError_(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN));
206 break; 158 break;
207 } 159 }
208 160
209 base.dispose(this.sessionConnectedHooks_); 161 base.dispose(this.sessionConnectedHooks_);
210 this.sessionConnectedHooks_= null; 162 this.sessionConnectedHooks_= null;
211 this.sessionConnector_.closeSession(); 163 this.sessionConnector_.closeSession();
212 }; 164 };
213 165
214 /** @private */ 166 /** @private */
215 remoting.Application.prototype.updateStatistics_ = function() { 167 remoting.Application.prototype.updateStatistics_ = function() {
216 var perfstats = remoting.clientSession.getPerfStats(); 168 var perfstats = remoting.clientSession.getPerfStats();
217 remoting.stats.update(perfstats); 169 remoting.stats.update(perfstats);
218 remoting.clientSession.logStatistics(perfstats); 170 remoting.clientSession.logStatistics(perfstats);
219 }; 171 };
220 172
221 173
174 /*
175 * remoting.ApplicationInterface
176 * These functions must be overridden in the subclass.
177 */
178
179 /** @return {string} */
180 remoting.Application.prototype.getApplicationName = function() {
181 base.debug.assert(false, "Subclass must override");
182 };
183
184 /**
185 * @param {!remoting.Error} error
186 * @protected
187 */
188 remoting.Application.prototype.signInFailed_ = function(error) {
189 base.debug.assert(false, "Subclass must override");
190 };
191
192 /** @protected */
193 remoting.Application.prototype.initApplication_ = function() {
194 base.debug.assert(false, "Subclass must override");
195 };
196
197 /**
198 * @param {string} token
199 * @protected
200 */
201 remoting.Application.prototype.startApplication_ = function(token) {
202 base.debug.assert(false, "Subclass must override");
203 };
204
205 /** @protected */
206 remoting.Application.prototype.exitApplication_ = function() {
207 base.debug.assert(false, "Subclass must override");
208 };
209
210 /**
211 * @param {remoting.ConnectionInfo} connectionInfo
212 * @protected
213 */
214 remoting.Application.prototype.onConnected_ = function(connectionInfo) {
215 base.debug.assert(false, "Subclass must override");
216 };
217
218 /** @protected */
219 remoting.Application.prototype.onDisconnected_ = function() {
220 base.debug.assert(false, "Subclass must override");
221 };
222
223 /**
224 * @param {!remoting.Error} error
225 * @protected
226 */
227 remoting.Application.prototype.onConnectionFailed_ = function(error) {
228 base.debug.assert(false, "Subclass must override");
229 };
230
231 /**
232 * @param {!remoting.Error} error The error to be localized and displayed.
233 * @protected
234 */
235 remoting.Application.prototype.onError_ = function(error) {
236 base.debug.assert(false, "Subclass must override");
237 };
238
239
222 /** 240 /**
241 * The interface specifies the methods that a subclass of remoting.Application
242 * is required implement to override the default behavior.
243 *
223 * @interface 244 * @interface
224 */ 245 */
225 remoting.Application.Delegate = function() {}; 246 remoting.ApplicationInterface = function() {};
247
248 /**
249 * @return {string} Application product name to be used in UI.
250 */
251 remoting.ApplicationInterface.prototype.getApplicationName = function() {};
252
253 /**
254 * Report an authentication error to the user. This is called in lieu of
255 * startApplication() if the user cannot be authenticated or if they decline
256 * the app permissions.
257 *
258 * @param {!remoting.Error} error The failure reason.
259 */
260 remoting.ApplicationInterface.prototype.signInFailed_ = function(error) {};
226 261
227 /** 262 /**
228 * Initialize the application. This is called before an OAuth token is requested 263 * 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 264 * and should be used for tasks such as initializing the DOM, registering event
230 * handlers, etc. 265 * handlers, etc. After this is called, the app is running and waiting for
266 * user events.
231 */ 267 */
232 remoting.Application.Delegate.prototype.init = function() {}; 268 remoting.ApplicationInterface.prototype.initApplication_ = function() {};
233 269
234 /** 270 /**
235 * Start the application. Once start() is called, the delegate can assume that 271 * Start the application. Once startApplication() is called, we can assume that
236 * the user has consented to all permissions specified in the manifest. 272 * the user has consented to all permissions specified in the manifest.
237 * 273 *
238 * @param {remoting.SessionConnector} connector 274 * @param {string} token An OAuth access token. The app should not cache
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 275 * this token, but can assume that it will remain valid during application
241 * start-up. 276 * start-up.
242 */ 277 */
243 remoting.Application.Delegate.prototype.start = function(connector, token) {}; 278 remoting.ApplicationInterface.prototype.startApplication_ = function(token) {};
244 279
245 /** 280 /**
246 * Report an authentication error to the user. This is called in lieu of start() 281 * Close down the application before exiting.
247 * if the user cannot be authenticated.
248 *
249 * @param {!remoting.Error} error The failure reason.
250 */ 282 */
251 remoting.Application.Delegate.prototype.signInFailed = function(error) {}; 283 remoting.ApplicationInterface.prototype.exitApplication_ = function() {};
252
253 /**
254 * @return {string} Application product name to be used in UI.
255 */
256 remoting.Application.Delegate.prototype.getApplicationName = function() {};
257 284
258 /** 285 /**
259 * Called when a new session has been connected. 286 * Called when a new session has been connected.
260 * 287 *
261 * @param {remoting.ConnectionInfo} connectionInfo 288 * @param {remoting.ConnectionInfo} connectionInfo
262 * @return {void} Nothing.
263 */ 289 */
264 remoting.Application.Delegate.prototype.handleConnected = function( 290 remoting.ApplicationInterface.prototype.onConnected_ =
265 connectionInfo) {}; 291 function(connectionInfo) {};
266 292
267 /** 293 /**
268 * Called when the current session has been disconnected. 294 * Called when the current session has been disconnected.
269 *
270 * @return {void} Nothing.
271 */ 295 */
272 remoting.Application.Delegate.prototype.handleDisconnected = function() {}; 296 remoting.ApplicationInterface.prototype.onDisconnected_ = function() {};
273 297
274 /** 298 /**
275 * Called when the current session's connection has failed. 299 * Called when the current session's connection has failed.
276 * 300 *
277 * @param {remoting.SessionConnector} connector
278 * @param {!remoting.Error} error 301 * @param {!remoting.Error} error
279 * @return {void} Nothing.
280 */ 302 */
281 remoting.Application.Delegate.prototype.handleConnectionFailed = 303 remoting.ApplicationInterface.prototype.onConnectionFailed_ =
282 function(connector, error) {}; 304 function(error) {};
283 305
284 /** 306 /**
285 * Called when an error needs to be displayed to the user. 307 * Called when an error needs to be displayed to the user.
286 * 308 *
287 * @param {!remoting.Error} errorTag The error to be localized and displayed. 309 * @param {!remoting.Error} errorTag The error to be localized and displayed.
288 * @return {void} Nothing.
289 */ 310 */
290 remoting.Application.Delegate.prototype.handleError = function(errorTag) {}; 311 remoting.ApplicationInterface.prototype.onError_ = 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 312
300 313
301 /** @type {remoting.Application} */ 314 /** @type {remoting.Application} */
302 remoting.app = null; 315 remoting.app = null;
OLDNEW
« no previous file with comments | « remoting/webapp/app_remoting/js/ar_main.js ('k') | remoting/webapp/base/js/base_inherits_unittest.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698