Chromium Code Reviews| Index: remoting/webapp/client_plugin.js |
| diff --git a/remoting/webapp/client_plugin.js b/remoting/webapp/client_plugin.js |
| index 197eeffd743adc58c351534895344d6494181be2..106fc78d82c84f89831786978af3443d8cd48067 100644 |
| --- a/remoting/webapp/client_plugin.js |
| +++ b/remoting/webapp/client_plugin.js |
| @@ -1,14 +1,10 @@ |
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
Sergey Ulanov
2014/09/20 00:35:24
this is not a new file, so keep 2012 here?
|
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /** |
| * @fileoverview |
| - * Class that wraps low-level details of interacting with the client plugin. |
| - * |
| - * This abstracts a <embed> element and controls the plugin which does |
| - * the actual remoting work. It also handles differences between |
| - * client plugins versions when it is necessary. |
| + * Interface abstracting the ClientPlugin functionality. |
|
Sergey Ulanov
2014/09/20 00:35:24
Please update this comment - it's confusing after
Jamie
2014/09/20 00:54:22
Done.
|
| */ |
| 'use strict'; |
| @@ -17,493 +13,40 @@ |
| var remoting = remoting || {}; |
| /** |
| - * @param {Element} container The container for the embed element. |
| - * @param {function(string, string):boolean} onExtensionMessage The handler for |
| - * protocol extension messages. Returns true if a message is recognized; |
| - * false otherwise. |
| - * @constructor |
| - */ |
| -remoting.ClientPlugin = function(container, onExtensionMessage) { |
| - this.plugin_ = remoting.ClientPlugin.createPluginElement_(); |
| - this.plugin_.id = 'session-client-plugin'; |
| - container.appendChild(this.plugin_); |
| - |
| - this.onExtensionMessage_ = onExtensionMessage; |
| - |
| - this.desktopWidth = 0; |
| - this.desktopHeight = 0; |
| - this.desktopXDpi = 96; |
| - this.desktopYDpi = 96; |
| - |
| - /** @param {string} iq The Iq stanza received from the host. */ |
| - this.onOutgoingIqHandler = function (iq) {}; |
| - /** @param {string} message Log message. */ |
| - this.onDebugMessageHandler = function (message) {}; |
| - /** |
| - * @param {number} state The connection state. |
| - * @param {number} error The error code, if any. |
| - */ |
| - this.onConnectionStatusUpdateHandler = function(state, error) {}; |
| - /** @param {boolean} ready Connection ready state. */ |
| - this.onConnectionReadyHandler = function(ready) {}; |
| - |
| - /** |
| - * @param {string} tokenUrl Token-request URL, received from the host. |
| - * @param {string} hostPublicKey Public key for the host. |
| - * @param {string} scope OAuth scope to request the token for. |
| - */ |
| - this.fetchThirdPartyTokenHandler = function( |
| - tokenUrl, hostPublicKey, scope) {}; |
| - this.onDesktopSizeUpdateHandler = function () {}; |
| - /** @param {!Array.<string>} capabilities The negotiated capabilities. */ |
| - this.onSetCapabilitiesHandler = function (capabilities) {}; |
| - this.fetchPinHandler = function (supportsPairing) {}; |
| - /** @param {string} data Remote gnubbyd data. */ |
| - this.onGnubbyAuthHandler = function(data) {}; |
| - /** |
| - * @param {string} url |
| - * @param {number} hotspotX |
| - * @param {number} hotspotY |
| - */ |
| - this.updateMouseCursorImage = function(url, hotspotX, hotspotY) {}; |
| - |
| - /** @param {string} data Remote cast extension message. */ |
| - this.onCastExtensionHandler = function(data) {}; |
| - |
| - /** @type {remoting.MediaSourceRenderer} */ |
| - this.mediaSourceRenderer_ = null; |
| - |
| - /** @type {number} */ |
| - this.pluginApiVersion_ = -1; |
| - /** @type {Array.<string>} */ |
| - this.pluginApiFeatures_ = []; |
| - /** @type {number} */ |
| - this.pluginApiMinVersion_ = -1; |
| - /** @type {!Array.<string>} */ |
| - this.capabilities_ = []; |
| - /** @type {boolean} */ |
| - this.helloReceived_ = false; |
| - /** @type {function(boolean)|null} */ |
| - this.onInitializedCallback_ = null; |
| - /** @type {function(string, string):void} */ |
| - this.onPairingComplete_ = function(clientId, sharedSecret) {}; |
| - /** @type {remoting.ClientSession.PerfStats} */ |
| - this.perfStats_ = new remoting.ClientSession.PerfStats(); |
| - |
| - /** @type {remoting.ClientPlugin} */ |
| - var that = this; |
| - /** @param {Event} event Message event from the plugin. */ |
| - this.plugin_.addEventListener('message', function(event) { |
| - that.handleMessage_(event.data); |
| - }, false); |
| - |
| - if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') { |
| - window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500); |
| - } |
| -}; |
| - |
| -/** |
| - * Creates plugin element without adding it to a container. |
| - * |
| - * @return {remoting.ViewerPlugin} Plugin element |
| - */ |
| -remoting.ClientPlugin.createPluginElement_ = function() { |
| - var plugin = /** @type {remoting.ViewerPlugin} */ |
| - document.createElement('embed'); |
| - if (remoting.settings.CLIENT_PLUGIN_TYPE == 'pnacl') { |
| - plugin.src = 'remoting_client_pnacl.nmf'; |
| - plugin.type = 'application/x-pnacl'; |
| - } else if (remoting.settings.CLIENT_PLUGIN_TYPE == 'nacl') { |
| - plugin.src = 'remoting_client_nacl.nmf'; |
| - plugin.type = 'application/x-nacl'; |
| - } else { |
| - plugin.src = 'about://none'; |
| - plugin.type = 'application/vnd.chromium.remoting-viewer'; |
| - } |
| - plugin.width = 0; |
| - plugin.height = 0; |
| - plugin.tabIndex = 0; // Required, otherwise focus() doesn't work. |
| - return plugin; |
| -} |
| - |
| -/** |
| - * Preloads the plugin to make instantiation faster when the user tries |
| - * to connect. |
| - */ |
| -remoting.ClientPlugin.preload = function() { |
| - if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') { |
| - return; |
| - } |
| - |
| - var plugin = remoting.ClientPlugin.createPluginElement_(); |
| - plugin.addEventListener( |
| - 'loadend', function() { document.body.removeChild(plugin); }, false); |
| - document.body.appendChild(plugin); |
| -} |
| - |
| -/** |
| - * Set of features for which hasFeature() can be used to test. |
| - * |
| - * @enum {string} |
| - */ |
| -remoting.ClientPlugin.Feature = { |
| - INJECT_KEY_EVENT: 'injectKeyEvent', |
| - NOTIFY_CLIENT_RESOLUTION: 'notifyClientResolution', |
| - ASYNC_PIN: 'asyncPin', |
| - PAUSE_VIDEO: 'pauseVideo', |
| - PAUSE_AUDIO: 'pauseAudio', |
| - REMAP_KEY: 'remapKey', |
| - SEND_CLIPBOARD_ITEM: 'sendClipboardItem', |
| - THIRD_PARTY_AUTH: 'thirdPartyAuth', |
| - TRAP_KEY: 'trapKey', |
| - PINLESS_AUTH: 'pinlessAuth', |
| - EXTENSION_MESSAGE: 'extensionMessage', |
| - MEDIA_SOURCE_RENDERING: 'mediaSourceRendering', |
| - VIDEO_CONTROL: 'videoControl' |
| -}; |
| - |
| -/** |
| - * Chromoting session API version (for this javascript). |
| - * This is compared with the plugin API version to verify that they are |
| - * compatible. |
| - * |
| - * @const |
| - * @private |
| + * @interface |
| + * @extends {base.Disposable} |
| */ |
| -remoting.ClientPlugin.prototype.API_VERSION_ = 6; |
| - |
| -/** |
| - * The oldest API version that we support. |
| - * This will differ from the |API_VERSION_| if we maintain backward |
| - * compatibility with older API versions. |
| - * |
| - * @const |
| - * @private |
| - */ |
| -remoting.ClientPlugin.prototype.API_MIN_VERSION_ = 5; |
| - |
| -/** |
| - * @param {string|{method:string, data:Object.<string,*>}} |
| - * rawMessage Message from the plugin. |
| - * @private |
| - */ |
| -remoting.ClientPlugin.prototype.handleMessage_ = function(rawMessage) { |
| - var message = |
| - /** @type {{method:string, data:Object.<string,*>}} */ |
| - ((typeof(rawMessage) == 'string') ? jsonParseSafe(rawMessage) |
| - : rawMessage); |
| - if (!message || !('method' in message) || !('data' in message)) { |
| - console.error('Received invalid message from the plugin:', rawMessage); |
| - return; |
| - } |
| - |
| - try { |
| - this.handleMessageMethod_(message); |
| - } catch(e) { |
| - console.error(/** @type {*} */ (e)); |
| - } |
| -} |
| - |
| -/** |
| - * @param {{method:string, data:Object.<string,*>}} |
| - * message Parsed message from the plugin. |
| - * @private |
| - */ |
| -remoting.ClientPlugin.prototype.handleMessageMethod_ = function(message) { |
| - /** |
| - * Splits a string into a list of words delimited by spaces. |
| - * @param {string} str String that should be split. |
| - * @return {!Array.<string>} List of words. |
| - */ |
| - var tokenize = function(str) { |
| - /** @type {Array.<string>} */ |
| - var tokens = str.match(/\S+/g); |
| - return tokens ? tokens : []; |
| - }; |
| - |
| - if (message.method == 'hello') { |
| - // Resize in case we had to enlarge it to support click-to-play. |
| - this.hidePluginForClickToPlay_(); |
| - this.pluginApiVersion_ = getNumberAttr(message.data, 'apiVersion'); |
| - this.pluginApiMinVersion_ = getNumberAttr(message.data, 'apiMinVersion'); |
| - |
| - if (this.pluginApiVersion_ >= 7) { |
| - this.pluginApiFeatures_ = |
| - tokenize(getStringAttr(message.data, 'apiFeatures')); |
| - |
| - // Negotiate capabilities. |
| - |
| - /** @type {!Array.<string>} */ |
| - var requestedCapabilities = []; |
| - if ('requestedCapabilities' in message.data) { |
| - requestedCapabilities = |
| - tokenize(getStringAttr(message.data, 'requestedCapabilities')); |
| - } |
| - |
| - /** @type {!Array.<string>} */ |
| - var supportedCapabilities = []; |
| - if ('supportedCapabilities' in message.data) { |
| - supportedCapabilities = |
| - tokenize(getStringAttr(message.data, 'supportedCapabilities')); |
| - } |
| - |
| - // At the moment the webapp does not recognize any of |
| - // 'requestedCapabilities' capabilities (so they all should be disabled) |
| - // and do not care about any of 'supportedCapabilities' capabilities (so |
| - // they all can be enabled). |
| - this.capabilities_ = supportedCapabilities; |
| - |
| - // Let the host know that the webapp can be requested to always send |
| - // the client's dimensions. |
| - this.capabilities_.push( |
| - remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION); |
| - |
| - // Let the host know that we're interested in knowing whether or not |
| - // it rate-limits desktop-resize requests. |
| - this.capabilities_.push( |
| - remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS); |
| - |
| - // Let the host know that we can use the video framerecording extension. |
| - this.capabilities_.push( |
| - remoting.ClientSession.Capability.VIDEO_RECORDER); |
| - |
| - // Let the host know that we can support casting of the screen. |
| - // TODO(aiguha): Add this capability based on a gyp/command-line flag, |
| - // rather than by default. |
| - this.capabilities_.push( |
| - remoting.ClientSession.Capability.CAST); |
| - |
| - } else if (this.pluginApiVersion_ >= 6) { |
| - this.pluginApiFeatures_ = ['highQualityScaling', 'injectKeyEvent']; |
| - } else { |
| - this.pluginApiFeatures_ = ['highQualityScaling']; |
| - } |
| - this.helloReceived_ = true; |
| - if (this.onInitializedCallback_ != null) { |
| - this.onInitializedCallback_(true); |
| - this.onInitializedCallback_ = null; |
| - } |
| - |
| - } else if (message.method == 'sendOutgoingIq') { |
| - this.onOutgoingIqHandler(getStringAttr(message.data, 'iq')); |
| - |
| - } else if (message.method == 'logDebugMessage') { |
| - this.onDebugMessageHandler(getStringAttr(message.data, 'message')); |
| - |
| - } else if (message.method == 'onConnectionStatus') { |
| - var state = remoting.ClientSession.State.fromString( |
| - getStringAttr(message.data, 'state')) |
| - var error = remoting.ClientSession.ConnectionError.fromString( |
| - getStringAttr(message.data, 'error')); |
| - this.onConnectionStatusUpdateHandler(state, error); |
| - |
| - } else if (message.method == 'onDesktopSize') { |
| - this.desktopWidth = getNumberAttr(message.data, 'width'); |
| - this.desktopHeight = getNumberAttr(message.data, 'height'); |
| - this.desktopXDpi = getNumberAttr(message.data, 'x_dpi', 96); |
| - this.desktopYDpi = getNumberAttr(message.data, 'y_dpi', 96); |
| - this.onDesktopSizeUpdateHandler(); |
| - |
| - } else if (message.method == 'onPerfStats') { |
| - // Return value is ignored. These calls will throw an error if the value |
| - // is not a number. |
| - getNumberAttr(message.data, 'videoBandwidth'); |
| - getNumberAttr(message.data, 'videoFrameRate'); |
| - getNumberAttr(message.data, 'captureLatency'); |
| - getNumberAttr(message.data, 'encodeLatency'); |
| - getNumberAttr(message.data, 'decodeLatency'); |
| - getNumberAttr(message.data, 'renderLatency'); |
| - getNumberAttr(message.data, 'roundtripLatency'); |
| - this.perfStats_ = |
| - /** @type {remoting.ClientSession.PerfStats} */ message.data; |
| - |
| - } else if (message.method == 'injectClipboardItem') { |
| - var mimetype = getStringAttr(message.data, 'mimeType'); |
| - var item = getStringAttr(message.data, 'item'); |
| - if (remoting.clipboard) { |
| - remoting.clipboard.fromHost(mimetype, item); |
| - } |
| - |
| - } else if (message.method == 'onFirstFrameReceived') { |
| - if (remoting.clientSession) { |
| - remoting.clientSession.onFirstFrameReceived(); |
| - } |
| - |
| - } else if (message.method == 'onConnectionReady') { |
| - var ready = getBooleanAttr(message.data, 'ready'); |
| - this.onConnectionReadyHandler(ready); |
| - |
| - } else if (message.method == 'fetchPin') { |
| - // The pairingSupported value in the dictionary indicates whether both |
| - // client and host support pairing. If the client doesn't support pairing, |
| - // then the value won't be there at all, so give it a default of false. |
| - var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', |
| - false) |
| - this.fetchPinHandler(pairingSupported); |
| - |
| - } else if (message.method == 'setCapabilities') { |
| - /** @type {!Array.<string>} */ |
| - var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); |
| - this.onSetCapabilitiesHandler(capabilities); |
| - |
| - } else if (message.method == 'fetchThirdPartyToken') { |
| - var tokenUrl = getStringAttr(message.data, 'tokenUrl'); |
| - var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); |
| - var scope = getStringAttr(message.data, 'scope'); |
| - this.fetchThirdPartyTokenHandler(tokenUrl, hostPublicKey, scope); |
| - |
| - } else if (message.method == 'pairingResponse') { |
| - var clientId = getStringAttr(message.data, 'clientId'); |
| - var sharedSecret = getStringAttr(message.data, 'sharedSecret'); |
| - this.onPairingComplete_(clientId, sharedSecret); |
| - |
| - } else if (message.method == 'extensionMessage') { |
| - var extMsgType = getStringAttr(message.data, 'type'); |
| - var extMsgData = getStringAttr(message.data, 'data'); |
| - switch (extMsgType) { |
| - case 'gnubby-auth': |
| - this.onGnubbyAuthHandler(extMsgData); |
| - break; |
| - case 'test-echo-reply': |
| - console.log('Got echo reply: ' + extMsgData); |
| - break; |
| - case 'cast_message': |
| - this.onCastExtensionHandler(extMsgData); |
| - break; |
| - default: |
| - this.onExtensionMessage_(extMsgType, extMsgData); |
| - break; |
| - } |
| - |
| - } else if (message.method == 'mediaSourceReset') { |
| - if (!this.mediaSourceRenderer_) { |
| - console.error('Unexpected mediaSourceReset.'); |
| - return; |
| - } |
| - this.mediaSourceRenderer_.reset(getStringAttr(message.data, 'format')) |
| - |
| - } else if (message.method == 'mediaSourceData') { |
| - if (!(message.data['buffer'] instanceof ArrayBuffer)) { |
| - console.error('Invalid mediaSourceData message:', message.data); |
| - return; |
| - } |
| - if (!this.mediaSourceRenderer_) { |
| - console.error('Unexpected mediaSourceData.'); |
| - return; |
| - } |
| - // keyframe flag may be absent from the message. |
| - var keyframe = !!message.data['keyframe']; |
| - this.mediaSourceRenderer_.onIncomingData( |
| - (/** @type {ArrayBuffer} */ message.data['buffer']), keyframe); |
| - |
| - } else if (message.method == 'unsetCursorShape') { |
| - this.updateMouseCursorImage('', 0, 0); |
| - |
| - } else if (message.method == 'setCursorShape') { |
| - var width = getNumberAttr(message.data, 'width'); |
| - var height = getNumberAttr(message.data, 'height'); |
| - var hotspotX = getNumberAttr(message.data, 'hotspotX'); |
| - var hotspotY = getNumberAttr(message.data, 'hotspotY'); |
| - var srcArrayBuffer = getObjectAttr(message.data, 'data'); |
| - |
| - var canvas = |
| - /** @type {HTMLCanvasElement} */ (document.createElement('canvas')); |
| - canvas.width = width; |
| - canvas.height = height; |
| - |
| - var context = |
| - /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')); |
| - var imageData = context.getImageData(0, 0, width, height); |
| - base.debug.assert(srcArrayBuffer instanceof ArrayBuffer); |
| - var src = new Uint8Array(/** @type {ArrayBuffer} */(srcArrayBuffer)); |
| - var dest = imageData.data; |
| - for (var i = 0; i < /** @type {number} */(dest.length); i += 4) { |
| - dest[i] = src[i + 2]; |
| - dest[i + 1] = src[i + 1]; |
| - dest[i + 2] = src[i]; |
| - dest[i + 3] = src[i + 3]; |
| - } |
| - |
| - context.putImageData(imageData, 0, 0); |
| - this.updateMouseCursorImage(canvas.toDataURL(), hotspotX, hotspotY); |
| - } |
| -}; |
| - |
| -/** |
| - * Deletes the plugin. |
| - */ |
| -remoting.ClientPlugin.prototype.cleanup = function() { |
| - if (this.plugin_) { |
| - this.plugin_.parentNode.removeChild(this.plugin_); |
| - this.plugin_ = null; |
| - } |
| -}; |
| +remoting.ClientPlugin = function() {}; |
| /** |
| - * @return {HTMLEmbedElement} HTML element that corresponds to the plugin. |
| + * @return {number} The width of the remote desktop, in pixels. |
| */ |
| -remoting.ClientPlugin.prototype.element = function() { |
| - return this.plugin_; |
| -}; |
| +remoting.ClientPlugin.prototype.getDesktopWidth = function() {}; |
| /** |
| - * @param {function(boolean): void} onDone |
| + * @return {number} The height of the remote desktop, in pixels. |
| */ |
| -remoting.ClientPlugin.prototype.initialize = function(onDone) { |
| - if (this.helloReceived_) { |
| - onDone(true); |
| - } else { |
| - this.onInitializedCallback_ = onDone; |
| - } |
| -}; |
| +remoting.ClientPlugin.prototype.getDesktopHeight = function() {}; |
| /** |
| - * @return {boolean} True if the plugin and web-app versions are compatible. |
| + * @return {number} The x-DPI of the remote desktop. |
| */ |
| -remoting.ClientPlugin.prototype.isSupportedVersion = function() { |
| - if (!this.helloReceived_) { |
| - console.error( |
| - "isSupportedVersion() is called before the plugin is initialized."); |
| - return false; |
| - } |
| - return this.API_VERSION_ >= this.pluginApiMinVersion_ && |
| - this.pluginApiVersion_ >= this.API_MIN_VERSION_; |
| -}; |
| +remoting.ClientPlugin.prototype.getDesktopXDpi = function() {}; |
| /** |
| - * @param {remoting.ClientPlugin.Feature} feature The feature to test for. |
| - * @return {boolean} True if the plugin supports the named feature. |
| + * @return {number} The y-DPI of the remote desktop. |
| */ |
| -remoting.ClientPlugin.prototype.hasFeature = function(feature) { |
| - if (!this.helloReceived_) { |
| - console.error( |
| - "hasFeature() is called before the plugin is initialized."); |
| - return false; |
| - } |
| - return this.pluginApiFeatures_.indexOf(feature) > -1; |
| -}; |
| +remoting.ClientPlugin.prototype.getDesktopYDpi = function() {}; |
| /** |
| - * @return {boolean} True if the plugin supports the injectKeyEvent API. |
| + * @return {HTMLElement} The DOM element representing the remote session. |
| */ |
| -remoting.ClientPlugin.prototype.isInjectKeyEventSupported = function() { |
| - return this.pluginApiVersion_ >= 6; |
| -}; |
| +remoting.ClientPlugin.prototype.element = function() {}; |
| /** |
| - * @param {string} iq Incoming IQ stanza. |
| + * @param {function():void} onDone Completion callback. |
| */ |
| -remoting.ClientPlugin.prototype.onIncomingIq = function(iq) { |
| - if (this.plugin_ && this.plugin_.postMessage) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'incomingIq', data: { iq: iq } })); |
| - } else { |
| - // plugin.onIq may not be set after the plugin has been shut |
| - // down. Particularly this happens when we receive response to |
| - // session-terminate stanza. |
| - console.warn('plugin.onIq is not set so dropping incoming message.'); |
| - } |
| -}; |
| +remoting.ClientPlugin.prototype.initialize = function(onDone) {}; |
| /** |
| * @param {string} hostJid The jid of the host to connect to. |
| @@ -524,209 +67,88 @@ remoting.ClientPlugin.prototype.onIncomingIq = function(iq) { |
| remoting.ClientPlugin.prototype.connect = function( |
| hostJid, hostPublicKey, localJid, sharedSecret, |
| authenticationMethods, authenticationTag, |
| - clientPairingId, clientPairedSecret) { |
| - var keyFilter = ''; |
| - if (remoting.platformIsMac()) { |
| - keyFilter = 'mac'; |
| - } else if (remoting.platformIsChromeOS()) { |
| - keyFilter = 'cros'; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'delegateLargeCursors', data: {} })); |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'connect', data: { |
| - hostJid: hostJid, |
| - hostPublicKey: hostPublicKey, |
| - localJid: localJid, |
| - sharedSecret: sharedSecret, |
| - authenticationMethods: authenticationMethods, |
| - authenticationTag: authenticationTag, |
| - capabilities: this.capabilities_.join(" "), |
| - clientPairingId: clientPairingId, |
| - clientPairedSecret: clientPairedSecret, |
| - keyFilter: keyFilter |
| - } |
| - })); |
| -}; |
| + clientPairingId, clientPairedSecret) {}; |
| /** |
| - * Release all currently pressed keys. |
| + * @param {number} key The keycode to inject. |
| + * @param {boolean} down True for press; false for a release. |
| */ |
| -remoting.ClientPlugin.prototype.releaseAllKeys = function() { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'releaseAllKeys', data: {} })); |
| -}; |
| +remoting.ClientPlugin.prototype.injectKeyEvent = |
| + function(key, down) {}; |
| /** |
| - * Send a key event to the host. |
| - * |
| - * @param {number} usbKeycode The USB-style code of the key to inject. |
| - * @param {boolean} pressed True to inject a key press, False for a release. |
| + * @param {number} from |
| + * @param {number} to |
| */ |
| -remoting.ClientPlugin.prototype.injectKeyEvent = |
| - function(usbKeycode, pressed) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'injectKeyEvent', data: { |
| - 'usbKeycode': usbKeycode, |
| - 'pressed': pressed} |
| - })); |
| -}; |
| +remoting.ClientPlugin.prototype.remapKey = function(from, to) {}; |
| /** |
| - * Remap one USB keycode to another in all subsequent key events. |
| - * |
| - * @param {number} fromKeycode The USB-style code of the key to remap. |
| - * @param {number} toKeycode The USB-style code to remap the key to. |
| - */ |
| -remoting.ClientPlugin.prototype.remapKey = |
| - function(fromKeycode, toKeycode) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'remapKey', data: { |
| - 'fromKeycode': fromKeycode, |
| - 'toKeycode': toKeycode} |
| - })); |
| -}; |
| + * Release all keys currently being pressed. |
| + */ |
| +remoting.ClientPlugin.prototype.releaseAllKeys = function() {}; |
| /** |
| - * Enable/disable redirection of the specified key to the web-app. |
| - * |
| - * @param {number} keycode The USB-style code of the key. |
| - * @param {Boolean} trap True to enable trapping, False to disable. |
| - */ |
| -remoting.ClientPlugin.prototype.trapKey = function(keycode, trap) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'trapKey', data: { |
| - 'keycode': keycode, |
| - 'trap': trap} |
| - })); |
| -}; |
| + * @param {number} width |
| + * @param {number} height |
| + * @param {number} dpi |
| + */ |
| +remoting.ClientPlugin.prototype.notifyClientResolution = |
| + function(width, height, dpi) {}; |
| /** |
| - * Returns an associative array with a set of stats for this connecton. |
| - * |
| - * @return {remoting.ClientSession.PerfStats} The connection statistics. |
| + * @param {string} iq |
| */ |
| -remoting.ClientPlugin.prototype.getPerfStats = function() { |
| - return this.perfStats_; |
| -}; |
| +remoting.ClientPlugin.prototype.onIncomingIq = function(iq) {}; |
| /** |
| - * Sends a clipboard item to the host. |
| - * |
| - * @param {string} mimeType The MIME type of the clipboard item. |
| - * @param {string} item The clipboard item. |
| + * @return {boolean} True if the web-app and plugin are compatible. |
| */ |
| -remoting.ClientPlugin.prototype.sendClipboardItem = |
| - function(mimeType, item) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.SEND_CLIPBOARD_ITEM)) |
| - return; |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'sendClipboardItem', |
| - data: { mimeType: mimeType, item: item }})); |
| -}; |
| +remoting.ClientPlugin.prototype.isSupportedVersion = function() {}; |
| /** |
| - * Notifies the host that the client has the specified size and pixel density. |
| - * |
| - * @param {number} width The available client width in DIPs. |
| - * @param {number} height The available client height in DIPs. |
| - * @param {number} device_scale The number of device pixels per DIP. |
| + * @param {remoting.ClientPlugin.Feature} feature |
| + * @return {boolean} True if the plugin support the specified feature. |
| */ |
| -remoting.ClientPlugin.prototype.notifyClientResolution = |
| - function(width, height, device_scale) { |
| - if (this.hasFeature(remoting.ClientPlugin.Feature.NOTIFY_CLIENT_RESOLUTION)) { |
| - var dpi = Math.floor(device_scale * 96); |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'notifyClientResolution', |
| - data: { width: Math.floor(width * device_scale), |
| - height: Math.floor(height * device_scale), |
| - x_dpi: dpi, y_dpi: dpi }})); |
| - } |
| -}; |
| +remoting.ClientPlugin.prototype.hasFeature = function(feature) {}; |
| /** |
| - * Requests that the host pause or resume sending video updates. |
| + * Enable MediaSource rendering via the specified renderer. |
| * |
| - * @param {boolean} pause True to suspend video updates, false otherwise. |
| - */ |
| -remoting.ClientPlugin.prototype.pauseVideo = |
| - function(pause) { |
| - if (this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'videoControl', data: { pause: pause }})); |
| - } else if (this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_VIDEO)) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'pauseVideo', data: { pause: pause }})); |
| - } |
| -}; |
| + * @param {remoting.MediaSourceRenderer} mediaSourceRenderer |
| + */ |
| +remoting.ClientPlugin.prototype.enableMediaSourceRendering = |
| + function(mediaSourceRenderer) {}; |
| /** |
| - * Requests that the host pause or resume sending audio updates. |
| + * Sends a clipboard item to the host. |
| * |
| - * @param {boolean} pause True to suspend audio updates, false otherwise. |
| - */ |
| -remoting.ClientPlugin.prototype.pauseAudio = |
| - function(pause) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_AUDIO)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'pauseAudio', data: { pause: pause }})); |
| -}; |
| + * @param {string} mimeType The MIME type of the clipboard item. |
| + * @param {string} item The clipboard item. |
| + */ |
| +remoting.ClientPlugin.prototype.sendClipboardItem = |
| + function(mimeType, item) {}; |
| /** |
| - * Requests that the host configure the video codec for lossless encode. |
| - * |
| - * @param {boolean} wantLossless True to request lossless encoding. |
| - */ |
| -remoting.ClientPlugin.prototype.setLosslessEncode = |
| - function(wantLossless) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'videoControl', data: { losslessEncode: wantLossless }})); |
| -}; |
| + * Tell the plugin to request a PIN asynchronously. |
| + */ |
| +remoting.ClientPlugin.prototype.useAsyncPinDialog = function() {}; |
| /** |
| - * Requests that the host configure the video codec for lossless color. |
| + * Request that this client be paired with the current host. |
| * |
| - * @param {boolean} wantLossless True to request lossless color. |
| - */ |
| -remoting.ClientPlugin.prototype.setLosslessColor = |
| - function(wantLossless) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'videoControl', data: { losslessColor: wantLossless }})); |
| -}; |
| + * @param {string} clientName The human-readable name of the client. |
| + * @param {function(string, string):void} onDone Callback to receive the |
| + * client id and shared secret when they are available. |
| + */ |
| +remoting.ClientPlugin.prototype.requestPairing = |
| + function(clientName, onDone) {}; |
| /** |
| * Called when a PIN is obtained from the user. |
| * |
| * @param {string} pin The PIN. |
| */ |
| -remoting.ClientPlugin.prototype.onPinFetched = |
| - function(pin) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'onPinFetched', data: { pin: pin }})); |
| -}; |
| - |
| -/** |
| - * Tells the plugin to ask for the PIN asynchronously. |
| - */ |
| -remoting.ClientPlugin.prototype.useAsyncPinDialog = |
| - function() { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'useAsyncPinDialog', data: {} })); |
| -}; |
| +remoting.ClientPlugin.prototype.onPinFetched = function(pin) {}; |
| /** |
| * Sets the third party authentication token and shared secret. |
| @@ -734,91 +156,160 @@ remoting.ClientPlugin.prototype.useAsyncPinDialog = |
| * @param {string} token The token received from the token URL. |
| * @param {string} sharedSecret Shared secret received from the token URL. |
| */ |
| -remoting.ClientPlugin.prototype.onThirdPartyTokenFetched = function( |
| - token, sharedSecret) { |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'onThirdPartyTokenFetched', |
| - data: { token: token, sharedSecret: sharedSecret}})); |
| -}; |
| +remoting.ClientPlugin.prototype.onThirdPartyTokenFetched = |
| + function(token, sharedSecret) {}; |
| /** |
| - * Request pairing with the host for PIN-less authentication. |
| - * |
| - * @param {string} clientName The human-readable name of the client. |
| - * @param {function(string, string):void} onDone, Callback to receive the |
| - * client id and shared secret when they are available. |
| + * @param {boolean} pause True to pause the audio stream; false to resume it. |
| */ |
| -remoting.ClientPlugin.prototype.requestPairing = |
| - function(clientName, onDone) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.PINLESS_AUTH)) { |
| - return; |
| - } |
| - this.onPairingComplete_ = onDone; |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'requestPairing', data: { clientName: clientName } })); |
| -}; |
| +remoting.ClientPlugin.prototype.pauseAudio = function(pause) {}; |
| + |
| +/** |
| + * @param {boolean} pause True to pause the video stream; false to resume it. |
| + */ |
| +remoting.ClientPlugin.prototype.pauseVideo = function(pause) {}; |
| + |
| +/** |
| + * @return {remoting.ClientSession.PerfStats} A summary of the connection |
| + * performance. |
| + */ |
| +remoting.ClientPlugin.prototype.getPerfStats = function() {}; |
| /** |
| * Send an extension message to the host. |
| * |
| - * @param {string} type The message type. |
| - * @param {string} message The message payload. |
| + * @param {string} name |
| + * @param {string} data |
| */ |
| remoting.ClientPlugin.prototype.sendClientMessage = |
| - function(type, message) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) { |
| - return; |
| - } |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'extensionMessage', |
| - data: { type: type, data: message } })); |
| + function(name, data) {}; |
| + |
| +/** |
| + * @param {function(string):void} handler Callback for sending an IQ stanza. |
| + */ |
| +remoting.ClientPlugin.prototype.setOnOutgoingIqHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(string):void} handler Callback for logging debug messages. |
| + */ |
| +remoting.ClientPlugin.prototype.setOnDebugMessageHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(number, number):void} handler Callback for connection status |
| + * update notifications. The first parameter is the connection state; the |
| + * second is the error code, if any. |
| + */ |
| +remoting.ClientPlugin.prototype.setConnectionStatusUpdateHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(boolean):void} handler Callback for connection readiness |
| + * notifications. |
| + */ |
| +remoting.ClientPlugin.prototype.setConnectionReadyHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function():void} handler Callback for desktop size change |
| + * notifications. |
| + */ |
| +remoting.ClientPlugin.prototype.setDesktopSizeUpdateHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(!Array.<string>):void} handler Callback to inform of |
| + * capabilities negotiated between host and client. |
| + */ |
| +remoting.ClientPlugin.prototype.setCapabilitiesHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(string):void} handler Callback for processing security key |
| + * (Gnubby) protocol messages. |
| + */ |
| +remoting.ClientPlugin.prototype.setGnubbyAuthHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(string):void} handler Callback for processing Cast protocol |
| + * messages. |
| + */ |
| +remoting.ClientPlugin.prototype.setCastExtensionHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(string, number, number):void} handler Callback for |
| + * processing large mouse cursor images. The first parameter is a data: |
| + * URL encoding the mouse cursor; the second and third parameters are |
| + * the cursor hotspot's x- and y-coordinates, respectively. |
| + */ |
| +remoting.ClientPlugin.prototype.setMouseCursorHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(string, string, string):void} handler Callback for |
| + * fetching third-party tokens. The first parameter is the token URL; the |
| + * second is the public key of the host; the third is the OAuth2 scope |
| + * being requested. |
| + */ |
| +remoting.ClientPlugin.prototype.setFetchThirdPartyTokenHandler = |
| + function(handler) {}; |
| + |
| +/** |
| + * @param {function(boolean):void} handler Callback for fetching a PIN from |
| + * the user. The parameter is true if PIN pairing is supported by the |
| + * host, or false otherwise. |
| + */ |
| +remoting.ClientPlugin.prototype.setFetchPinHandler = |
| + function(handler) {}; |
| -}; |
| /** |
| - * Request MediaStream-based rendering. |
| + * Set of features for which hasFeature() can be used to test. |
| * |
| - * @param {remoting.MediaSourceRenderer} mediaSourceRenderer |
| + * @enum {string} |
| */ |
| -remoting.ClientPlugin.prototype.enableMediaSourceRendering = |
| - function(mediaSourceRenderer) { |
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.MEDIA_SOURCE_RENDERING)) { |
| - return; |
| - } |
| - this.mediaSourceRenderer_ = mediaSourceRenderer; |
| - this.plugin_.postMessage(JSON.stringify( |
| - { method: 'enableMediaSourceRendering', data: {} })); |
| +remoting.ClientPlugin.Feature = { |
|
Jamie
2014/09/19 23:55:44
This enum was defined on the implementation in the
|
| + INJECT_KEY_EVENT: 'injectKeyEvent', |
| + NOTIFY_CLIENT_RESOLUTION: 'notifyClientResolution', |
| + ASYNC_PIN: 'asyncPin', |
| + PAUSE_VIDEO: 'pauseVideo', |
| + PAUSE_AUDIO: 'pauseAudio', |
| + REMAP_KEY: 'remapKey', |
| + SEND_CLIPBOARD_ITEM: 'sendClipboardItem', |
| + THIRD_PARTY_AUTH: 'thirdPartyAuth', |
| + TRAP_KEY: 'trapKey', |
| + PINLESS_AUTH: 'pinlessAuth', |
| + EXTENSION_MESSAGE: 'extensionMessage', |
| + MEDIA_SOURCE_RENDERING: 'mediaSourceRendering', |
| + VIDEO_CONTROL: 'videoControl' |
| }; |
| + |
| /** |
| - * If we haven't yet received a "hello" message from the plugin, change its |
| - * size so that the user can confirm it if click-to-play is enabled, or can |
| - * see the "this plugin is disabled" message if it is actually disabled. |
| - * @private |
| - */ |
| -remoting.ClientPlugin.prototype.showPluginForClickToPlay_ = function() { |
| - if (!this.helloReceived_) { |
| - var width = 200; |
| - var height = 200; |
| - this.plugin_.style.width = width + 'px'; |
| - this.plugin_.style.height = height + 'px'; |
| - // Center the plugin just underneath the "Connnecting..." dialog. |
| - var dialog = document.getElementById('client-dialog'); |
| - var dialogRect = dialog.getBoundingClientRect(); |
| - this.plugin_.style.top = (dialogRect.bottom + 16) + 'px'; |
| - this.plugin_.style.left = (window.innerWidth - width) / 2 + 'px'; |
| - this.plugin_.style.position = 'fixed'; |
| - } |
| -}; |
| + * @interface |
| + */ |
| +remoting.ClientPluginFactory = function() {}; |
| + |
| +/** |
| + * @param {Element} container The container for the embed element. |
| + * @param {function(string, string):boolean} onExtensionMessage The handler for |
| + * protocol extension messages. Returns true if a message is recognized; |
| + * false otherwise. |
| + * @return {remoting.ClientPlugin} A new client plugin instance. |
| + */ |
| +remoting.ClientPluginFactory.prototype.createPlugin = |
| + function(container, onExtensionMessage) {}; |
| /** |
| - * Undo the CSS rules needed to make the plugin clickable for click-to-play. |
| - * @private |
| + * Preload the plugin to make instantiation faster when the user tries |
| + * to connect. |
| */ |
| -remoting.ClientPlugin.prototype.hidePluginForClickToPlay_ = function() { |
| - this.plugin_.style.width = ''; |
| - this.plugin_.style.height = ''; |
| - this.plugin_.style.top = ''; |
| - this.plugin_.style.left = ''; |
| - this.plugin_.style.position = ''; |
| -}; |
| +remoting.ClientPluginFactory.prototype.preloadPlugin = function() {}; |
|
Jamie
2014/09/19 23:55:44
This was previously a static member of the impleme
|
| + |
| +/** |
| + * @type {remoting.ClientPluginFactory} |
| + */ |
| +remoting.ClientPlugin.factory = null; |