Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / remoting / webapp / app_remoting / js / app_connected_view.js
blob5ed85ed3b0c4365f6e47fb7da5e451adfa7d4c92
1 // Copyright 2015 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  * Implements a basic UX control for a connected app remoting session.
8  */
10 /** @suppress {duplicate} */
11 var remoting = remoting || {};
13 (function() {
15 'use strict';
17 /**
18  * Interval to test the connection speed.
19  * @const {number}
20  */
21 var CONNECTION_SPEED_PING_INTERVAL_MS = 10 * 1000;
23 /**
24  * Interval to refresh the google drive access token.
25  * @const {number}
26  */
27 var DRIVE_ACCESS_TOKEN_REFRESH_INTERVAL_MS = 15 * 60 * 1000;
29 /**
30  * @param {HTMLElement} containerElement
31  * @param {remoting.ConnectionInfo} connectionInfo
32  *
33  * @constructor
34  * @implements {base.Disposable}
35  * @implements {remoting.ProtocolExtension}
36  */
37 remoting.AppConnectedView = function(containerElement, connectionInfo) {
38   /** @private */
39   this.plugin_ = connectionInfo.plugin();
41   /** @private */
42   this.host_ = connectionInfo.host();
44   var menuAdapter = new remoting.ContextMenuChrome();
46   // Initialize the context menus.
47   if (!remoting.platformIsChromeOS()) {
48     menuAdapter =
49         new remoting.ContextMenuDom(document.getElementById('context-menu'));
50   }
52   this.contextMenu_ = new remoting.ApplicationContextMenu(
53       menuAdapter, this.plugin_, connectionInfo.session());
54   this.contextMenu_.setHostId(connectionInfo.host().hostId);
56   /** @private */
57   this.keyboardLayoutsMenu_ = new remoting.KeyboardLayoutsMenu(menuAdapter);
59   /** @private */
60   this.windowActivationMenu_ = new remoting.WindowActivationMenu(menuAdapter);
62   var baseView = new remoting.ConnectedView(
63       this.plugin_, containerElement,
64       containerElement.querySelector('.mouse-cursor-overlay'));
66   var windowShapeHook = new base.EventHook(
67       this.plugin_.hostDesktop(),
68       remoting.HostDesktop.Events.shapeChanged,
69       remoting.windowShape.setDesktopRects.bind(remoting.windowShape));
71   var desktopSizeHook = new base.EventHook(
72       this.plugin_.hostDesktop(),
73       remoting.HostDesktop.Events.sizeChanged,
74       this.onDesktopSizeChanged_.bind(this));
76   /** @private */
77   this.disposables_ =
78       new base.Disposables(baseView, windowShapeHook, desktopSizeHook,
79                            this.contextMenu_, menuAdapter);
81   /** @private */
82   this.supportsGoogleDrive_ = this.plugin_.hasCapability(
83       remoting.ClientSession.Capability.GOOGLE_DRIVE);
85   this.resizeHostToClientArea_();
86   this.plugin_.extensions().register(this);
89 /**
90  * @return {void} Nothing.
91  */
92 remoting.AppConnectedView.prototype.dispose = function() {
93   this.windowActivationMenu_.setExtensionMessageSender(base.doNothing);
94   this.keyboardLayoutsMenu_.setExtensionMessageSender(base.doNothing);
95   base.dispose(this.disposables_);
98 /**
99  * Resize the host to the dimensions of the current window.
100  * @private
101  */
102 remoting.AppConnectedView.prototype.resizeHostToClientArea_ = function() {
103   var hostDesktop = this.plugin_.hostDesktop();
104   var desktopScale = this.host_.options.desktopScale;
105   hostDesktop.resize(window.innerWidth * desktopScale,
106                      window.innerHeight * desktopScale,
107                      window.devicePixelRatio);
111  * Adjust the size of the plugin according to the dimensions of the hostDesktop.
113  * @param {{width:number, height:number, xDpi:number, yDpi:number}} hostDesktop
114  * @private
115  */
116 remoting.AppConnectedView.prototype.onDesktopSizeChanged_ =
117     function(hostDesktop) {
118   // The first desktop size change indicates that we can close the loading
119   // window.
120   remoting.LoadingWindow.close();
122   var hostSize = { width: hostDesktop.width, height: hostDesktop.height };
123   var hostDpi = { x: hostDesktop.xDpi, y: hostDesktop.yDpi };
124   var clientArea = { width: window.innerWidth, height: window.innerHeight };
125   var newSize = remoting.Viewport.choosePluginSize(
126       clientArea, window.devicePixelRatio,
127       hostSize, hostDpi, this.host_.options.desktopScale,
128       true /* fullscreen */ , true /* shrinkToFit */ );
130   this.plugin_.element().style.width = newSize.width + 'px';
131   this.plugin_.element().style.height = newSize.height + 'px';
135  * @return {Array<string>}
136  * @override {remoting.ProtocolExtension}
137  */
138 remoting.AppConnectedView.prototype.getExtensionTypes = function() {
139   return ['openURL', 'onWindowRemoved', 'onWindowAdded',
140           'onAllWindowsMinimized', 'setKeyboardLayouts', 'pingResponse'];
144  * @param {function(string,string)} sendMessageToHost Callback to send a message
145  *     to the host.
146  * @override {remoting.ProtocolExtension}
147  */
148 remoting.AppConnectedView.prototype.startExtension = function(
149     sendMessageToHost) {
150   this.windowActivationMenu_.setExtensionMessageSender(sendMessageToHost);
151   this.keyboardLayoutsMenu_.setExtensionMessageSender(sendMessageToHost);
153   remoting.identity.getUserInfo().then(function(userInfo) {
154     sendMessageToHost('setUserDisplayInfo',
155                       JSON.stringify({fullName: userInfo.name}));
156   });
158   var onRestoreHook = new base.ChromeEventHook(
159       chrome.app.window.current().onRestored, function() {
160         sendMessageToHost('restoreAllWindows', '');
161       });
163   var pingTimer = new base.RepeatingTimer(function() {
164     var message = {timestamp: new Date().getTime()};
165     sendMessageToHost('pingRequest', JSON.stringify(message));
166   }, CONNECTION_SPEED_PING_INTERVAL_MS);
168   this.disposables_.add(onRestoreHook, pingTimer);
170   if (this.supportsGoogleDrive_) {
171     this.disposables_.add(new base.RepeatingTimer(
172         this.sendGoogleDriveAccessToken_.bind(this, sendMessageToHost),
173         DRIVE_ACCESS_TOKEN_REFRESH_INTERVAL_MS, true));
174   }
178  * @param {string} type The message type.
179  * @param {Object} message The parsed extension message data.
180  * @override {remoting.ProtocolExtension}
181  */
182 remoting.AppConnectedView.prototype.onExtensionMessage =
183     function(type, message) {
184   switch (type) {
185     case 'openURL':
186       // URL requests from the hosted app are untrusted, so disallow anything
187       // other than HTTP or HTTPS.
188       var url = base.getStringAttr(message, 'url');
189       if (url.indexOf('http:') != 0 && url.indexOf('https:') != 0) {
190         console.error('Bad URL: ' + url);
191       } else {
192         window.open(url);
193       }
194       return true;
196     case 'onWindowRemoved':
197       var id = base.getNumberAttr(message, 'id');
198       this.windowActivationMenu_.remove(id);
199       return true;
201     case 'onWindowAdded':
202       var id = base.getNumberAttr(message, 'id');
203       var title = base.getStringAttr(message, 'title');
204       this.windowActivationMenu_.add(id, title);
205       return true;
207     case 'onAllWindowsMinimized':
208       chrome.app.window.current().minimize();
209       return true;
211     case 'setKeyboardLayouts':
212       var supportedLayouts = base.getArrayAttr(message, 'supportedLayouts');
213       var currentLayout = base.getStringAttr(message, 'currentLayout');
214       console.log('Current host keyboard layout: ' + currentLayout);
215       console.log('Supported host keyboard layouts: ' + supportedLayouts);
216       this.keyboardLayoutsMenu_.setLayouts(supportedLayouts, currentLayout);
217       return true;
219     case 'pingResponse':
220       var then = base.getNumberAttr(message, 'timestamp');
221       var now = new Date().getTime();
222       this.contextMenu_.updateConnectionRTT(now - then);
223       return true;
224   }
226   return false;
230  * Timer callback to send the access token to the host.
231  * @param {function(string, string)} sendExtensionMessage
232  * @private
233  */
234 remoting.AppConnectedView.prototype.sendGoogleDriveAccessToken_ =
235     function(sendExtensionMessage) {
236   var googleDriveScopes = [
237     'https://docs.google.com/feeds/',
238     'https://www.googleapis.com/auth/drive'
239   ];
240   remoting.identity.getNewToken(googleDriveScopes).then(
241     function(/** string */ token){
242       base.debug.assert(token !== previousToken_);
243       previousToken_ = token;
244       sendExtensionMessage('accessToken', token);
245   }).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
246     console.log('Failed to refresh access token: ' + error.toString());
247   }));
250 // The access token last received from getNewToken. Saved to ensure that we
251 // get a fresh token each time.
252 var previousToken_ = '';
254 })();