OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 * Implements a basic UX control for a connected app remoting session. | 7 * Implements a basic UX control for a connected app remoting session. |
8 */ | 8 */ |
9 | 9 |
10 /** @suppress {duplicate} */ | 10 /** @suppress {duplicate} */ |
11 var remoting = remoting || {}; | 11 var remoting = remoting || {}; |
12 | 12 |
13 (function() { | 13 (function() { |
14 | 14 |
15 'use strict'; | 15 'use strict'; |
16 | 16 |
17 /** | 17 /** |
| 18 * Interval to test the connection speed. |
| 19 * @const {number} |
| 20 */ |
| 21 var CONNECTION_SPEED_PING_INTERVAL_MS = 10 * 1000; |
| 22 |
| 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; |
| 28 |
| 29 /** |
18 * @param {HTMLElement} containerElement | 30 * @param {HTMLElement} containerElement |
19 * @param {remoting.ConnectionInfo} connectionInfo | 31 * @param {remoting.ConnectionInfo} connectionInfo |
20 * | 32 * |
21 * @constructor | 33 * @constructor |
22 * @implements {base.Disposable} | 34 * @implements {base.Disposable} |
| 35 * @implements {remoting.ProtocolExtension} |
23 */ | 36 */ |
24 remoting.AppConnectedView = function(containerElement, connectionInfo) { | 37 remoting.AppConnectedView = function(containerElement, connectionInfo) { |
25 | |
26 /** @private */ | 38 /** @private */ |
27 this.plugin_ = connectionInfo.plugin(); | 39 this.plugin_ = connectionInfo.plugin(); |
28 | 40 |
29 /** @private */ | 41 /** @private */ |
30 this.host_ = connectionInfo.host(); | 42 this.host_ = connectionInfo.host(); |
31 | 43 |
| 44 /** @private {remoting.ContextMenuAdapter} */ |
| 45 var menuAdapter = new remoting.ContextMenuChrome(); |
| 46 |
| 47 // Initialize the context menus. |
| 48 if (!remoting.platformIsChromeOS()) { |
| 49 menuAdapter = |
| 50 new remoting.ContextMenuDom(document.getElementById('context-menu')); |
| 51 } |
| 52 |
| 53 this.contextMenu_ = new remoting.ApplicationContextMenu(menuAdapter); |
| 54 this.contextMenu_.setHostId(connectionInfo.host().hostId); |
| 55 |
| 56 /** @private */ |
| 57 this.keyboardLayoutsMenu_ = new remoting.KeyboardLayoutsMenu(menuAdapter); |
| 58 |
| 59 /** @private */ |
| 60 this.windowActivationMenu_ = new remoting.WindowActivationMenu(menuAdapter); |
| 61 |
32 var baseView = new remoting.ConnectedView( | 62 var baseView = new remoting.ConnectedView( |
33 this.plugin_, containerElement, | 63 this.plugin_, containerElement, |
34 containerElement.querySelector('.mouse-cursor-overlay')); | 64 containerElement.querySelector('.mouse-cursor-overlay')); |
35 | 65 |
36 var windowShapeHook = new base.EventHook( | 66 var windowShapeHook = new base.EventHook( |
37 this.plugin_.hostDesktop(), | 67 this.plugin_.hostDesktop(), |
38 remoting.HostDesktop.Events.shapeChanged, | 68 remoting.HostDesktop.Events.shapeChanged, |
39 remoting.windowShape.setDesktopRects.bind(remoting.windowShape)); | 69 remoting.windowShape.setDesktopRects.bind(remoting.windowShape)); |
40 | 70 |
41 var desktopSizeHook = new base.EventHook( | 71 var desktopSizeHook = new base.EventHook( |
42 this.plugin_.hostDesktop(), | 72 this.plugin_.hostDesktop(), |
43 remoting.HostDesktop.Events.sizeChanged, | 73 remoting.HostDesktop.Events.sizeChanged, |
44 this.onDesktopSizeChanged_.bind(this)); | 74 this.onDesktopSizeChanged_.bind(this)); |
45 | 75 |
46 /** @private */ | 76 /** @private */ |
47 this.disposables_ = new base.Disposables( | 77 this.disposables_ = new base.Disposables( |
48 baseView, windowShapeHook, desktopSizeHook); | 78 baseView, windowShapeHook, desktopSizeHook); |
49 | 79 |
| 80 /** @private */ |
| 81 this.supportsGoogleDrive_ = connectionInfo.session().hasCapability( |
| 82 remoting.ClientSession.Capability.GOOGLE_DRIVE); |
| 83 |
50 this.resizeHostToClientArea_(); | 84 this.resizeHostToClientArea_(); |
| 85 this.plugin_.extensions().register(this); |
51 }; | 86 }; |
52 | 87 |
53 /** | 88 /** |
54 * @return {void} Nothing. | 89 * @return {void} Nothing. |
55 */ | 90 */ |
56 remoting.AppConnectedView.prototype.dispose = function() { | 91 remoting.AppConnectedView.prototype.dispose = function() { |
| 92 this.windowActivationMenu_.setExtensionMessageSender(base.doNothing); |
| 93 this.keyboardLayoutsMenu_.setExtensionMessageSender(base.doNothing); |
57 base.dispose(this.disposables_); | 94 base.dispose(this.disposables_); |
58 }; | 95 }; |
59 | 96 |
60 /** | 97 /** |
61 * Resize the host to the dimensions of the current window. | 98 * Resize the host to the dimensions of the current window. |
62 * @private | 99 * @private |
63 */ | 100 */ |
64 remoting.AppConnectedView.prototype.resizeHostToClientArea_ = function() { | 101 remoting.AppConnectedView.prototype.resizeHostToClientArea_ = function() { |
65 var hostDesktop = this.plugin_.hostDesktop(); | 102 var hostDesktop = this.plugin_.hostDesktop(); |
66 var desktopScale = this.host_.options.desktopScale; | 103 var desktopScale = this.host_.options.desktopScale; |
(...skipping 19 matching lines...) Expand all Loading... |
86 var clientArea = { width: window.innerWidth, height: window.innerHeight }; | 123 var clientArea = { width: window.innerWidth, height: window.innerHeight }; |
87 var newSize = remoting.DesktopViewport.choosePluginSize( | 124 var newSize = remoting.DesktopViewport.choosePluginSize( |
88 clientArea, window.devicePixelRatio, | 125 clientArea, window.devicePixelRatio, |
89 hostSize, hostDpi, this.host_.options.desktopScale, | 126 hostSize, hostDpi, this.host_.options.desktopScale, |
90 true /* fullscreen */ , true /* shrinkToFit */ ); | 127 true /* fullscreen */ , true /* shrinkToFit */ ); |
91 | 128 |
92 this.plugin_.element().style.width = newSize.width + 'px'; | 129 this.plugin_.element().style.width = newSize.width + 'px'; |
93 this.plugin_.element().style.height = newSize.height + 'px'; | 130 this.plugin_.element().style.height = newSize.height + 'px'; |
94 }; | 131 }; |
95 | 132 |
| 133 /** |
| 134 * @return {Array<string>} |
| 135 * @override {remoting.ProtocolExtension} |
| 136 */ |
| 137 remoting.AppConnectedView.prototype.getExtensionTypes = function() { |
| 138 return ['openURL', 'onWindowRemoved', 'onWindowAdded', |
| 139 'onAllWindowsMinimized', 'setKeyboardLayouts', 'pingResponse']; |
| 140 }; |
| 141 |
| 142 /** |
| 143 * @param {function(string,string)} sendMessageToHost Callback to send a message |
| 144 * to the host. |
| 145 * @override {remoting.ProtocolExtension} |
| 146 */ |
| 147 remoting.AppConnectedView.prototype.startExtension = function( |
| 148 sendMessageToHost) { |
| 149 this.windowActivationMenu_.setExtensionMessageSender(sendMessageToHost); |
| 150 this.keyboardLayoutsMenu_.setExtensionMessageSender(sendMessageToHost); |
| 151 |
| 152 remoting.identity.getUserInfo().then(function(userInfo) { |
| 153 sendMessageToHost('setUserDisplayInfo', |
| 154 JSON.stringify({fullName: userInfo.name})); |
| 155 }); |
| 156 |
| 157 var onRestoreHook = new base.ChromeEventHook( |
| 158 chrome.app.window.current().onRestored, function() { |
| 159 sendMessageToHost('restoreAllWindows', ''); |
| 160 }); |
| 161 |
| 162 var pingTimer = new base.RepeatingTimer(function() { |
| 163 var message = {timestamp: new Date().getTime()}; |
| 164 sendMessageToHost('pingRequest', JSON.stringify(message)); |
| 165 }, CONNECTION_SPEED_PING_INTERVAL_MS); |
| 166 |
| 167 this.disposables_.add(onRestoreHook, pingTimer); |
| 168 |
| 169 if (this.supportsGoogleDrive_) { |
| 170 this.disposables_.add(new base.RepeatingTimer( |
| 171 this.sendGoogleDriveAccessToken_.bind(this, sendMessageToHost), |
| 172 DRIVE_ACCESS_TOKEN_REFRESH_INTERVAL_MS, true)); |
| 173 } |
| 174 }; |
| 175 |
| 176 /** |
| 177 * @param {string} type The message type. |
| 178 * @param {Object} message The parsed extension message data. |
| 179 * @override {remoting.ProtocolExtension} |
| 180 */ |
| 181 remoting.AppConnectedView.prototype.onExtensionMessage = |
| 182 function(type, message) { |
| 183 switch (type) { |
| 184 case 'openURL': |
| 185 // URL requests from the hosted app are untrusted, so disallow anything |
| 186 // other than HTTP or HTTPS. |
| 187 var url = base.getStringAttr(message, 'url'); |
| 188 if (url.indexOf('http:') != 0 && url.indexOf('https:') != 0) { |
| 189 console.error('Bad URL: ' + url); |
| 190 } else { |
| 191 window.open(url); |
| 192 } |
| 193 return true; |
| 194 |
| 195 case 'onWindowRemoved': |
| 196 var id = base.getNumberAttr(message, 'id'); |
| 197 this.windowActivationMenu_.remove(id); |
| 198 return true; |
| 199 |
| 200 case 'onWindowAdded': |
| 201 var id = base.getNumberAttr(message, 'id'); |
| 202 var title = base.getStringAttr(message, 'title'); |
| 203 this.windowActivationMenu_.add(id, title); |
| 204 return true; |
| 205 |
| 206 case 'onAllWindowsMinimized': |
| 207 chrome.app.window.current().minimize(); |
| 208 return true; |
| 209 |
| 210 case 'setKeyboardLayouts': |
| 211 var supportedLayouts = base.getArrayAttr(message, 'supportedLayouts'); |
| 212 var currentLayout = base.getStringAttr(message, 'currentLayout'); |
| 213 console.log('Current host keyboard layout: ' + currentLayout); |
| 214 console.log('Supported host keyboard layouts: ' + supportedLayouts); |
| 215 this.keyboardLayoutsMenu_.setLayouts(supportedLayouts, currentLayout); |
| 216 return true; |
| 217 |
| 218 case 'pingResponse': |
| 219 var then = base.getNumberAttr(message, 'timestamp'); |
| 220 var now = new Date().getTime(); |
| 221 this.contextMenu_.updateConnectionRTT(now - then); |
| 222 return true; |
| 223 } |
| 224 |
| 225 return false; |
| 226 }; |
| 227 |
| 228 /** |
| 229 * Timer callback to send the access token to the host. |
| 230 * @param {function(string, string)} sendExtensionMessage |
| 231 * @private |
| 232 */ |
| 233 remoting.AppConnectedView.prototype.sendGoogleDriveAccessToken_ = |
| 234 function(sendExtensionMessage) { |
| 235 var googleDriveScopes = [ |
| 236 'https://docs.google.com/feeds/', |
| 237 'https://www.googleapis.com/auth/drive' |
| 238 ]; |
| 239 remoting.identity.getNewToken(googleDriveScopes).then( |
| 240 function(/** string */ token){ |
| 241 sendExtensionMessage('accessToken', token); |
| 242 }).catch(remoting.Error.handler(function(/** remoting.Error */ error) { |
| 243 console.log('Failed to refresh access token: ' + error.toString()); |
| 244 })); |
| 245 }; |
| 246 |
96 })(); | 247 })(); |
OLD | NEW |