Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / remoting / webapp / base / js / application.js
blob4881380d6315432461a46dbfea500e361bf4e400
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
3 // found in the LICENSE file.
5 /**
6 * @fileoverview
7 * Interface abstracting the Application functionality.
8 */
10 'use strict';
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
15 /**
16 * @param {Array<string>} appCapabilities Array of application capabilities.
17 * @constructor
18 * @implements {remoting.ApplicationInterface}
20 remoting.Application = function(appCapabilities) {
21 // Create global factories.
22 remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory();
23 remoting.SessionConnector.factory =
24 new remoting.DefaultSessionConnectorFactory();
26 /** @private {Array<string>} */
27 this.appCapabilities_ = [
28 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
29 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
30 remoting.ClientSession.Capability.VIDEO_RECORDER
32 // Append the app-specific capabilities.
33 this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities);
35 /** @protected {remoting.SessionConnector} */
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_);
43 /** @protected {remoting.Application.Mode} */
44 this.connectionMode_ = remoting.Application.Mode.ME2ME;
46 /** @private {base.Disposable} */
47 this.sessionConnectedHooks_ = null;
50 /**
51 * The current application mode (IT2Me, Me2Me or AppRemoting).
53 * TODO(kelvinp): Remove this when Me2Me and It2Me are abstracted into its
54 * own flow objects.
56 * @enum {number}
58 remoting.Application.Mode = {
59 IT2ME: 0,
60 ME2ME: 1,
61 APP_REMOTING: 2
64 /**
65 * @return {remoting.SessionConnector} The session connector.
67 remoting.Application.prototype.getSessionConnector = function() {
68 return this.sessionConnector_;
71 /**
72 * Get the connection mode (Me2Me, IT2Me or AppRemoting).
74 * @return {remoting.Application.Mode}
76 remoting.Application.prototype.getConnectionMode = function() {
77 return this.connectionMode_;
80 /**
81 * Set the connection mode (Me2Me, IT2Me or AppRemoting).
83 * @param {remoting.Application.Mode} mode
85 remoting.Application.prototype.setConnectionMode = function(mode) {
86 this.connectionMode_ = mode;
89 /**
90 * @param {remoting.ClientSession.Capability} capability
91 * @return {boolean}
93 remoting.Application.prototype.hasCapability = function(capability) {
94 var capabilities = this.appCapabilities_;
95 return capabilities.indexOf(capability) != -1;
98 /* Disconnect the remoting client. */
99 remoting.Application.prototype.disconnect = function() {
100 if (remoting.clientSession) {
101 remoting.clientSession.disconnect(remoting.Error.none());
102 console.log('Disconnected.');
106 /* Public method to exit the application. */
107 remoting.Application.prototype.quit = function() {
108 this.exitApplication_();
112 * Close the main window when quitting the application. This should be called
113 * by exitApplication() in the subclass.
114 * @protected
116 remoting.Application.prototype.closeMainWindow_ = function() {
117 chrome.app.window.current().close();
121 * Initialize the application and register all event handlers. After this
122 * is called, the app is running and waiting for user events.
124 remoting.Application.prototype.start = function() {
125 // TODO(garykac): This should be owned properly rather than living in the
126 // global 'remoting' namespace.
127 remoting.settings = new remoting.Settings();
129 remoting.initGlobalObjects();
130 remoting.initIdentity();
132 this.initApplication_();
134 var that = this;
135 remoting.identity.getToken().
136 then(this.startApplication_.bind(this)).
137 catch(remoting.Error.handler(
138 function(/** !remoting.Error */ error) {
139 if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
140 that.exitApplication_();
141 } else {
142 that.signInFailed_(error);
150 * Called when a new session has been connected.
152 * @param {remoting.ConnectionInfo} connectionInfo
153 * @return {void} Nothing.
154 * @protected
156 remoting.Application.prototype.initSession_ = function(connectionInfo) {
157 this.sessionConnectedHooks_ = new base.Disposables(
158 new base.EventHook(connectionInfo.session(), 'stateChanged',
159 this.onSessionFinished_.bind(this)),
160 new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000)
162 remoting.clipboard.startSession();
166 * Callback function called when the state of the client plugin changes. The
167 * current and previous states are available via the |state| member variable.
169 * @param {remoting.ClientSession.StateEvent=} state
170 * @private
172 remoting.Application.prototype.onSessionFinished_ = function(state) {
173 switch (state.current) {
174 case remoting.ClientSession.State.CLOSED:
175 console.log('Connection closed by host');
176 this.onDisconnected_();
177 break;
178 case remoting.ClientSession.State.FAILED:
179 var error = remoting.clientSession.getError();
180 console.error('Client plugin reported connection failed: ' +
181 error.toString());
182 if (error === null) {
183 error = remoting.Error.unexpected();
185 this.onError_(error);
186 break;
188 default:
189 console.error('Unexpected client plugin state: ' + state.current);
190 // This should only happen if the web-app and client plugin get out of
191 // sync, so MISSING_PLUGIN is a suitable error.
192 this.onError_(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN));
193 break;
196 base.dispose(this.sessionConnectedHooks_);
197 this.sessionConnectedHooks_= null;
198 this.sessionConnector_.closeSession();
201 /** @private */
202 remoting.Application.prototype.updateStatistics_ = function() {
203 var perfstats = remoting.clientSession.getPerfStats();
204 remoting.stats.update(perfstats);
205 remoting.clientSession.logStatistics(perfstats);
210 * remoting.ApplicationInterface
211 * These functions must be overridden in the subclass.
214 /** @return {string} */
215 remoting.Application.prototype.getApplicationName = function() {
216 base.debug.assert(false, "Subclass must override");
220 * @param {!remoting.Error} error
221 * @protected
223 remoting.Application.prototype.signInFailed_ = function(error) {
224 base.debug.assert(false, "Subclass must override");
227 /** @protected */
228 remoting.Application.prototype.initApplication_ = function() {
229 base.debug.assert(false, "Subclass must override");
233 * @param {string} token
234 * @protected
236 remoting.Application.prototype.startApplication_ = function(token) {
237 base.debug.assert(false, "Subclass must override");
240 /** @protected */
241 remoting.Application.prototype.exitApplication_ = function() {
242 base.debug.assert(false, "Subclass must override");
246 * @param {remoting.ConnectionInfo} connectionInfo
247 * @protected
249 remoting.Application.prototype.onConnected_ = function(connectionInfo) {
250 base.debug.assert(false, "Subclass must override");
253 /** @protected */
254 remoting.Application.prototype.onDisconnected_ = function() {
255 base.debug.assert(false, "Subclass must override");
259 * @param {!remoting.Error} error
260 * @protected
262 remoting.Application.prototype.onConnectionFailed_ = function(error) {
263 base.debug.assert(false, "Subclass must override");
267 * @param {!remoting.Error} error The error to be localized and displayed.
268 * @protected
270 remoting.Application.prototype.onError_ = function(error) {
271 base.debug.assert(false, "Subclass must override");
276 * The interface specifies the methods that a subclass of remoting.Application
277 * is required implement to override the default behavior.
279 * @interface
281 remoting.ApplicationInterface = function() {};
284 * @return {string} Application product name to be used in UI.
286 remoting.ApplicationInterface.prototype.getApplicationName = function() {};
289 * Report an authentication error to the user. This is called in lieu of
290 * startApplication() if the user cannot be authenticated or if they decline
291 * the app permissions.
293 * @param {!remoting.Error} error The failure reason.
295 remoting.ApplicationInterface.prototype.signInFailed_ = function(error) {};
298 * Initialize the application. This is called before an OAuth token is requested
299 * and should be used for tasks such as initializing the DOM, registering event
300 * handlers, etc. After this is called, the app is running and waiting for
301 * user events.
303 remoting.ApplicationInterface.prototype.initApplication_ = function() {};
306 * Start the application. Once startApplication() is called, we can assume that
307 * the user has consented to all permissions specified in the manifest.
309 * @param {string} token An OAuth access token. The app should not cache
310 * this token, but can assume that it will remain valid during application
311 * start-up.
313 remoting.ApplicationInterface.prototype.startApplication_ = function(token) {};
316 * Close down the application before exiting.
318 remoting.ApplicationInterface.prototype.exitApplication_ = function() {};
321 * Called when a new session has been connected.
323 * @param {remoting.ConnectionInfo} connectionInfo
325 remoting.ApplicationInterface.prototype.onConnected_ =
326 function(connectionInfo) {};
329 * Called when the current session has been disconnected.
331 remoting.ApplicationInterface.prototype.onDisconnected_ = function() {};
334 * Called when the current session's connection has failed.
336 * @param {!remoting.Error} error
338 remoting.ApplicationInterface.prototype.onConnectionFailed_ =
339 function(error) {};
342 * Called when an error needs to be displayed to the user.
344 * @param {!remoting.Error} errorTag The error to be localized and displayed.
346 remoting.ApplicationInterface.prototype.onError_ = function(errorTag) {};
349 /** @type {remoting.Application} */
350 remoting.app = null;