1 // Copyright (c) 2012 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.
6 * This class provides a "bridge" for communicating between the javascript and
9 var BrowserBridge = (function() {
13 * Delay in milliseconds between updates of certain browser information.
15 var POLL_INTERVAL_MS = 5000;
20 function BrowserBridge() {
21 assertFirstConstructorCall(BrowserBridge);
23 // List of observers for various bits of browser state.
24 this.connectionTestsObservers_ = [];
25 this.hstsObservers_ = [];
26 this.constantsObservers_ = [];
27 this.crosONCFileParseObservers_ = [];
28 this.storeDebugLogsObservers_ = [];
29 this.setNetworkDebugModeObservers_ = [];
30 // Unprocessed data received before the constants. This serves to protect
31 // against passing along data before having information on how to interpret
33 this.earlyReceivedData_ = [];
35 this.pollableDataHelpers_ = {};
36 this.pollableDataHelpers_.proxySettings =
37 new PollableDataHelper('onProxySettingsChanged',
38 this.sendGetProxySettings.bind(this));
39 this.pollableDataHelpers_.badProxies =
40 new PollableDataHelper('onBadProxiesChanged',
41 this.sendGetBadProxies.bind(this));
42 this.pollableDataHelpers_.httpCacheInfo =
43 new PollableDataHelper('onHttpCacheInfoChanged',
44 this.sendGetHttpCacheInfo.bind(this));
45 this.pollableDataHelpers_.hostResolverInfo =
46 new PollableDataHelper('onHostResolverInfoChanged',
47 this.sendGetHostResolverInfo.bind(this));
48 this.pollableDataHelpers_.socketPoolInfo =
49 new PollableDataHelper('onSocketPoolInfoChanged',
50 this.sendGetSocketPoolInfo.bind(this));
51 this.pollableDataHelpers_.sessionNetworkStats =
52 new PollableDataHelper('onSessionNetworkStatsChanged',
53 this.sendGetSessionNetworkStats.bind(this));
54 this.pollableDataHelpers_.historicNetworkStats =
55 new PollableDataHelper('onHistoricNetworkStatsChanged',
56 this.sendGetHistoricNetworkStats.bind(this));
57 this.pollableDataHelpers_.quicInfo =
58 new PollableDataHelper('onQuicInfoChanged',
59 this.sendGetQuicInfo.bind(this));
60 this.pollableDataHelpers_.spdySessionInfo =
61 new PollableDataHelper('onSpdySessionInfoChanged',
62 this.sendGetSpdySessionInfo.bind(this));
63 this.pollableDataHelpers_.spdyStatus =
64 new PollableDataHelper('onSpdyStatusChanged',
65 this.sendGetSpdyStatus.bind(this));
66 this.pollableDataHelpers_.spdyAlternateProtocolMappings =
67 new PollableDataHelper('onSpdyAlternateProtocolMappingsChanged',
68 this.sendGetSpdyAlternateProtocolMappings.bind(
71 this.pollableDataHelpers_.serviceProviders =
72 new PollableDataHelper('onServiceProvidersChanged',
73 this.sendGetServiceProviders.bind(this));
75 this.pollableDataHelpers_.prerenderInfo =
76 new PollableDataHelper('onPrerenderInfoChanged',
77 this.sendGetPrerenderInfo.bind(this));
78 this.pollableDataHelpers_.httpPipeliningStatus =
79 new PollableDataHelper('onHttpPipeliningStatusChanged',
80 this.sendGetHttpPipeliningStatus.bind(this));
81 this.pollableDataHelpers_.extensionInfo =
82 new PollableDataHelper('onExtensionInfoChanged',
83 this.sendGetExtensionInfo.bind(this));
85 this.pollableDataHelpers_.systemLog =
86 new PollableDataHelper('onSystemLogChanged',
87 this.getSystemLog.bind(this, 'syslog'));
90 // Setting this to true will cause messages from the browser to be ignored,
91 // and no messages will be sent to the browser, either. Intended for use
92 // when viewing log files.
93 this.disabled_ = false;
95 // Interval id returned by window.setInterval for polling timer.
96 this.pollIntervalId_ = null;
99 cr.addSingletonGetter(BrowserBridge);
101 BrowserBridge.prototype = {
103 //--------------------------------------------------------------------------
104 // Messages sent to the browser
105 //--------------------------------------------------------------------------
108 * Wraps |chrome.send|. Doesn't send anything when disabled.
110 send: function(value1, value2) {
111 if (!this.disabled_) {
112 if (arguments.length == 1) {
114 } else if (arguments.length == 2) {
115 chrome.send(value1, value2);
117 throw 'Unsupported number of arguments.';
122 sendReady: function() {
123 this.send('notifyReady');
124 this.setPollInterval(POLL_INTERVAL_MS);
128 * Some of the data we are interested is not currently exposed as a
129 * stream. This starts polling those with active observers (visible
130 * views) every |intervalMs|. Subsequent calls override previous calls
131 * to this function. If |intervalMs| is 0, stops polling.
133 setPollInterval: function(intervalMs) {
134 if (this.pollIntervalId_ !== null) {
135 window.clearInterval(this.pollIntervalId_);
136 this.pollIntervalId_ = null;
139 if (intervalMs > 0) {
140 this.pollIntervalId_ =
141 window.setInterval(this.checkForUpdatedInfo.bind(this, false),
146 sendGetProxySettings: function() {
147 // The browser will call receivedProxySettings on completion.
148 this.send('getProxySettings');
151 sendReloadProxySettings: function() {
152 this.send('reloadProxySettings');
155 sendGetBadProxies: function() {
156 // The browser will call receivedBadProxies on completion.
157 this.send('getBadProxies');
160 sendGetHostResolverInfo: function() {
161 // The browser will call receivedHostResolverInfo on completion.
162 this.send('getHostResolverInfo');
165 sendClearBadProxies: function() {
166 this.send('clearBadProxies');
169 sendClearHostResolverCache: function() {
170 this.send('clearHostResolverCache');
173 sendClearBrowserCache: function() {
174 this.send('clearBrowserCache');
177 sendClearAllCache: function() {
178 this.sendClearHostResolverCache();
179 this.sendClearBrowserCache();
182 sendStartConnectionTests: function(url) {
183 this.send('startConnectionTests', [url]);
186 sendHSTSQuery: function(domain) {
187 this.send('hstsQuery', [domain]);
190 sendHSTSAdd: function(domain, sts_include_subdomains,
191 pkp_include_subdomains, pins) {
192 this.send('hstsAdd', [domain, sts_include_subdomains,
193 pkp_include_subdomains, pins]);
196 sendHSTSDelete: function(domain) {
197 this.send('hstsDelete', [domain]);
200 sendGetHttpCacheInfo: function() {
201 this.send('getHttpCacheInfo');
204 sendGetSocketPoolInfo: function() {
205 this.send('getSocketPoolInfo');
208 sendGetSessionNetworkStats: function() {
209 this.send('getSessionNetworkStats');
212 sendGetHistoricNetworkStats: function() {
213 this.send('getHistoricNetworkStats');
216 sendCloseIdleSockets: function() {
217 this.send('closeIdleSockets');
220 sendFlushSocketPools: function() {
221 this.send('flushSocketPools');
224 sendGetQuicInfo: function() {
225 this.send('getQuicInfo');
228 sendGetSpdySessionInfo: function() {
229 this.send('getSpdySessionInfo');
232 sendGetSpdyStatus: function() {
233 this.send('getSpdyStatus');
236 sendGetSpdyAlternateProtocolMappings: function() {
237 this.send('getSpdyAlternateProtocolMappings');
240 sendGetServiceProviders: function() {
241 this.send('getServiceProviders');
244 sendGetPrerenderInfo: function() {
245 this.send('getPrerenderInfo');
248 sendGetHttpPipeliningStatus: function() {
249 this.send('getHttpPipeliningStatus');
252 sendGetExtensionInfo: function() {
253 this.send('getExtensionInfo');
256 enableIPv6: function() {
257 this.send('enableIPv6');
260 setLogLevel: function(logLevel) {
261 this.send('setLogLevel', ['' + logLevel]);
264 refreshSystemLogs: function() {
265 this.send('refreshSystemLogs');
268 getSystemLog: function(log_key, cellId) {
269 this.send('getSystemLog', [log_key, cellId]);
272 importONCFile: function(fileContent, passcode) {
273 this.send('importONCFile', [fileContent, passcode]);
276 storeDebugLogs: function() {
277 this.send('storeDebugLogs');
280 setNetworkDebugMode: function(subsystem) {
281 this.send('setNetworkDebugMode', [subsystem]);
284 //--------------------------------------------------------------------------
285 // Messages received from the browser.
286 //--------------------------------------------------------------------------
288 receive: function(command, params) {
289 // Does nothing if disabled.
293 // If no constants have been received, and params does not contain the
294 // constants, delay handling the data.
295 if (Constants == null && command != 'receivedConstants') {
296 this.earlyReceivedData_.push({ command: command, params: params });
300 this[command](params);
302 // Handle any data that was received early in the order it was received,
303 // once the constants have been processed.
304 if (this.earlyReceivedData_ != null) {
305 for (var i = 0; i < this.earlyReceivedData_.length; i++) {
306 var command = this.earlyReceivedData_[i];
307 this[command.command](command.params);
309 this.earlyReceivedData_ = null;
313 receivedConstants: function(constants) {
314 for (var i = 0; i < this.constantsObservers_.length; i++)
315 this.constantsObservers_[i].onReceivedConstants(constants);
318 receivedLogEntries: function(logEntries) {
319 EventsTracker.getInstance().addLogEntries(logEntries);
322 receivedProxySettings: function(proxySettings) {
323 this.pollableDataHelpers_.proxySettings.update(proxySettings);
326 receivedBadProxies: function(badProxies) {
327 this.pollableDataHelpers_.badProxies.update(badProxies);
330 receivedHostResolverInfo: function(hostResolverInfo) {
331 this.pollableDataHelpers_.hostResolverInfo.update(hostResolverInfo);
334 receivedSocketPoolInfo: function(socketPoolInfo) {
335 this.pollableDataHelpers_.socketPoolInfo.update(socketPoolInfo);
338 receivedSessionNetworkStats: function(sessionNetworkStats) {
339 this.pollableDataHelpers_.sessionNetworkStats.update(sessionNetworkStats);
342 receivedHistoricNetworkStats: function(historicNetworkStats) {
343 this.pollableDataHelpers_.historicNetworkStats.update(
344 historicNetworkStats);
347 receivedQuicInfo: function(quicInfo) {
348 this.pollableDataHelpers_.quicInfo.update(quicInfo);
351 receivedSpdySessionInfo: function(spdySessionInfo) {
352 this.pollableDataHelpers_.spdySessionInfo.update(spdySessionInfo);
355 receivedSpdyStatus: function(spdyStatus) {
356 this.pollableDataHelpers_.spdyStatus.update(spdyStatus);
359 receivedSpdyAlternateProtocolMappings:
360 function(spdyAlternateProtocolMappings) {
361 this.pollableDataHelpers_.spdyAlternateProtocolMappings.update(
362 spdyAlternateProtocolMappings);
365 receivedServiceProviders: function(serviceProviders) {
366 this.pollableDataHelpers_.serviceProviders.update(serviceProviders);
369 receivedStartConnectionTestSuite: function() {
370 for (var i = 0; i < this.connectionTestsObservers_.length; i++)
371 this.connectionTestsObservers_[i].onStartedConnectionTestSuite();
374 receivedStartConnectionTestExperiment: function(experiment) {
375 for (var i = 0; i < this.connectionTestsObservers_.length; i++) {
376 this.connectionTestsObservers_[i].onStartedConnectionTestExperiment(
381 receivedCompletedConnectionTestExperiment: function(info) {
382 for (var i = 0; i < this.connectionTestsObservers_.length; i++) {
383 this.connectionTestsObservers_[i].onCompletedConnectionTestExperiment(
384 info.experiment, info.result);
388 receivedCompletedConnectionTestSuite: function() {
389 for (var i = 0; i < this.connectionTestsObservers_.length; i++)
390 this.connectionTestsObservers_[i].onCompletedConnectionTestSuite();
393 receivedHSTSResult: function(info) {
394 for (var i = 0; i < this.hstsObservers_.length; i++)
395 this.hstsObservers_[i].onHSTSQueryResult(info);
398 receivedONCFileParse: function(error) {
399 for (var i = 0; i < this.crosONCFileParseObservers_.length; i++)
400 this.crosONCFileParseObservers_[i].onONCFileParse(error);
403 receivedStoreDebugLogs: function(status) {
404 for (var i = 0; i < this.storeDebugLogsObservers_.length; i++)
405 this.storeDebugLogsObservers_[i].onStoreDebugLogs(status);
408 receivedSetNetworkDebugMode: function(status) {
409 for (var i = 0; i < this.setNetworkDebugModeObservers_.length; i++)
410 this.setNetworkDebugModeObservers_[i].onSetNetworkDebugMode(status);
413 receivedHttpCacheInfo: function(info) {
414 this.pollableDataHelpers_.httpCacheInfo.update(info);
417 receivedPrerenderInfo: function(prerenderInfo) {
418 this.pollableDataHelpers_.prerenderInfo.update(prerenderInfo);
421 receivedHttpPipeliningStatus: function(httpPipeliningStatus) {
422 this.pollableDataHelpers_.httpPipeliningStatus.update(
423 httpPipeliningStatus);
426 receivedExtensionInfo: function(extensionInfo) {
427 this.pollableDataHelpers_.extensionInfo.update(extensionInfo);
430 getSystemLogCallback: function(systemLog) {
431 this.pollableDataHelpers_.systemLog.update(systemLog);
434 //--------------------------------------------------------------------------
437 * Prevents receiving/sending events to/from the browser.
439 disable: function() {
440 this.disabled_ = true;
441 this.setPollInterval(0);
445 * Returns true if the BrowserBridge has been disabled.
447 isDisabled: function() {
448 return this.disabled_;
452 * Adds a listener of the proxy settings. |observer| will be called back
453 * when data is received, through:
455 * observer.onProxySettingsChanged(proxySettings)
457 * |proxySettings| is a dictionary with (up to) two properties:
459 * "original" -- The settings that chrome was configured to use
460 * (i.e. system settings.)
461 * "effective" -- The "effective" proxy settings that chrome is using.
462 * (decides between the manual/automatic modes of the
465 * Each of these two configurations is formatted as a string, and may be
466 * omitted if not yet initialized.
468 * If |ignoreWhenUnchanged| is true, data is only sent when it changes.
469 * If it's false, data is sent whenever it's received from the browser.
471 addProxySettingsObserver: function(observer, ignoreWhenUnchanged) {
472 this.pollableDataHelpers_.proxySettings.addObserver(observer,
473 ignoreWhenUnchanged);
477 * Adds a listener of the proxy settings. |observer| will be called back
478 * when data is received, through:
480 * observer.onBadProxiesChanged(badProxies)
482 * |badProxies| is an array, where each entry has the property:
483 * badProxies[i].proxy_uri: String identify the proxy.
484 * badProxies[i].bad_until: The time when the proxy stops being considered
485 * bad. Note the time is in time ticks.
487 addBadProxiesObserver: function(observer, ignoreWhenUnchanged) {
488 this.pollableDataHelpers_.badProxies.addObserver(observer,
489 ignoreWhenUnchanged);
493 * Adds a listener of the host resolver info. |observer| will be called back
494 * when data is received, through:
496 * observer.onHostResolverInfoChanged(hostResolverInfo)
498 addHostResolverInfoObserver: function(observer, ignoreWhenUnchanged) {
499 this.pollableDataHelpers_.hostResolverInfo.addObserver(
500 observer, ignoreWhenUnchanged);
504 * Adds a listener of the socket pool. |observer| will be called back
505 * when data is received, through:
507 * observer.onSocketPoolInfoChanged(socketPoolInfo)
509 addSocketPoolInfoObserver: function(observer, ignoreWhenUnchanged) {
510 this.pollableDataHelpers_.socketPoolInfo.addObserver(observer,
511 ignoreWhenUnchanged);
515 * Adds a listener of the network session. |observer| will be called back
516 * when data is received, through:
518 * observer.onSessionNetworkStatsChanged(sessionNetworkStats)
520 addSessionNetworkStatsObserver: function(observer, ignoreWhenUnchanged) {
521 this.pollableDataHelpers_.sessionNetworkStats.addObserver(
522 observer, ignoreWhenUnchanged);
526 * Adds a listener of persistent network session data. |observer| will be
527 * called back when data is received, through:
529 * observer.onHistoricNetworkStatsChanged(historicNetworkStats)
531 addHistoricNetworkStatsObserver: function(observer, ignoreWhenUnchanged) {
532 this.pollableDataHelpers_.historicNetworkStats.addObserver(
533 observer, ignoreWhenUnchanged);
537 * Adds a listener of the QUIC info. |observer| will be called back
538 * when data is received, through:
540 * observer.onQuicInfoChanged(quicInfo)
542 addQuicInfoObserver: function(observer, ignoreWhenUnchanged) {
543 this.pollableDataHelpers_.quicInfo.addObserver(
544 observer, ignoreWhenUnchanged);
548 * Adds a listener of the SPDY info. |observer| will be called back
549 * when data is received, through:
551 * observer.onSpdySessionInfoChanged(spdySessionInfo)
553 addSpdySessionInfoObserver: function(observer, ignoreWhenUnchanged) {
554 this.pollableDataHelpers_.spdySessionInfo.addObserver(
555 observer, ignoreWhenUnchanged);
559 * Adds a listener of the SPDY status. |observer| will be called back
560 * when data is received, through:
562 * observer.onSpdyStatusChanged(spdyStatus)
564 addSpdyStatusObserver: function(observer, ignoreWhenUnchanged) {
565 this.pollableDataHelpers_.spdyStatus.addObserver(observer,
566 ignoreWhenUnchanged);
570 * Adds a listener of the AlternateProtocolMappings. |observer| will be
571 * called back when data is received, through:
573 * observer.onSpdyAlternateProtocolMappingsChanged(
574 * spdyAlternateProtocolMappings)
576 addSpdyAlternateProtocolMappingsObserver: function(observer,
577 ignoreWhenUnchanged) {
578 this.pollableDataHelpers_.spdyAlternateProtocolMappings.addObserver(
579 observer, ignoreWhenUnchanged);
583 * Adds a listener of the service providers info. |observer| will be called
584 * back when data is received, through:
586 * observer.onServiceProvidersChanged(serviceProviders)
588 * Will do nothing if on a platform other than Windows, as service providers
589 * are only present on Windows.
591 addServiceProvidersObserver: function(observer, ignoreWhenUnchanged) {
592 if (this.pollableDataHelpers_.serviceProviders) {
593 this.pollableDataHelpers_.serviceProviders.addObserver(
594 observer, ignoreWhenUnchanged);
599 * Adds a listener for the progress of the connection tests.
600 * The observer will be called back with:
602 * observer.onStartedConnectionTestSuite();
603 * observer.onStartedConnectionTestExperiment(experiment);
604 * observer.onCompletedConnectionTestExperiment(experiment, result);
605 * observer.onCompletedConnectionTestSuite();
607 addConnectionTestsObserver: function(observer) {
608 this.connectionTestsObservers_.push(observer);
612 * Adds a listener for the http cache info results.
613 * The observer will be called back with:
615 * observer.onHttpCacheInfoChanged(info);
617 addHttpCacheInfoObserver: function(observer, ignoreWhenUnchanged) {
618 this.pollableDataHelpers_.httpCacheInfo.addObserver(
619 observer, ignoreWhenUnchanged);
623 * Adds a listener for the results of HSTS (HTTPS Strict Transport Security)
624 * queries. The observer will be called back with:
626 * observer.onHSTSQueryResult(result);
628 addHSTSObserver: function(observer) {
629 this.hstsObservers_.push(observer);
633 * Adds a listener for ONC file parse status. The observer will be called
636 * observer.onONCFileParse(error);
638 addCrosONCFileParseObserver: function(observer) {
639 this.crosONCFileParseObservers_.push(observer);
643 * Adds a listener for storing log file status. The observer will be called
646 * observer.onStoreDebugLogs(status);
648 addStoreDebugLogsObserver: function(observer) {
649 this.storeDebugLogsObservers_.push(observer);
653 * Adds a listener for network debugging mode status. The observer
654 * will be called back with:
656 * observer.onSetNetworkDebugMode(status);
658 addSetNetworkDebugModeObserver: function(observer) {
659 this.setNetworkDebugModeObservers_.push(observer);
663 * Adds a listener for the received constants event. |observer| will be
664 * called back when the constants are received, through:
666 * observer.onReceivedConstants(constants);
668 addConstantsObserver: function(observer) {
669 this.constantsObservers_.push(observer);
673 * Adds a listener for updated prerender info events
674 * |observer| will be called back with:
676 * observer.onPrerenderInfoChanged(prerenderInfo);
678 addPrerenderInfoObserver: function(observer, ignoreWhenUnchanged) {
679 this.pollableDataHelpers_.prerenderInfo.addObserver(
680 observer, ignoreWhenUnchanged);
684 * Adds a listener of HTTP pipelining status. |observer| will be called
685 * back when data is received, through:
687 * observer.onHttpPipelineStatusChanged(httpPipeliningStatus)
689 addHttpPipeliningStatusObserver: function(observer, ignoreWhenUnchanged) {
690 this.pollableDataHelpers_.httpPipeliningStatus.addObserver(
691 observer, ignoreWhenUnchanged);
695 * Adds a listener of extension information. |observer| will be called
696 * back when data is received, through:
698 * observer.onExtensionInfoChanged(extensionInfo)
700 addExtensionInfoObserver: function(observer, ignoreWhenUnchanged) {
701 this.pollableDataHelpers_.extensionInfo.addObserver(
702 observer, ignoreWhenUnchanged);
706 * Adds a listener of system log information. |observer| will be called
707 * back when data is received, through:
709 * observer.onSystemLogChanged(systemLogInfo)
711 addSystemLogObserver: function(observer, ignoreWhenUnchanged) {
712 if (this.pollableDataHelpers_.systemLog) {
713 this.pollableDataHelpers_.systemLog.addObserver(
714 observer, ignoreWhenUnchanged);
719 * If |force| is true, calls all startUpdate functions. Otherwise, just
720 * runs updates with active observers.
722 checkForUpdatedInfo: function(force) {
723 for (var name in this.pollableDataHelpers_) {
724 var helper = this.pollableDataHelpers_[name];
725 if (force || helper.hasActiveObserver())
726 helper.startUpdate();
731 * Calls all startUpdate functions and, if |callback| is non-null,
732 * calls it with the results of all updates.
734 updateAllInfo: function(callback) {
736 new UpdateAllObserver(callback, this.pollableDataHelpers_);
737 this.checkForUpdatedInfo(true);
742 * This is a helper class used by BrowserBridge, to keep track of:
743 * - the list of observers interested in some piece of data.
744 * - the last known value of that piece of data.
745 * - the name of the callback method to invoke on observers.
746 * - the update function.
749 function PollableDataHelper(observerMethodName, startUpdateFunction) {
750 this.observerMethodName_ = observerMethodName;
751 this.startUpdate = startUpdateFunction;
752 this.observerInfos_ = [];
755 PollableDataHelper.prototype = {
756 getObserverMethodName: function() {
757 return this.observerMethodName_;
760 isObserver: function(object) {
761 for (var i = 0; i < this.observerInfos_.length; i++) {
762 if (this.observerInfos_[i].observer === object)
769 * If |ignoreWhenUnchanged| is true, we won't send data again until it
772 addObserver: function(observer, ignoreWhenUnchanged) {
773 this.observerInfos_.push(new ObserverInfo(observer, ignoreWhenUnchanged));
776 removeObserver: function(observer) {
777 for (var i = 0; i < this.observerInfos_.length; i++) {
778 if (this.observerInfos_[i].observer === observer) {
779 this.observerInfos_.splice(i, 1);
786 * Helper function to handle calling all the observers, but ONLY if the data
787 * has actually changed since last time or the observer has yet to receive
788 * any data. This is used for data we received from browser on an update
791 update: function(data) {
792 var prevData = this.currentData_;
795 // If the data hasn't changed since last time, will only need to notify
796 // observers that have not yet received any data.
797 if (!prevData || JSON.stringify(prevData) != JSON.stringify(data)) {
799 this.currentData_ = data;
802 // Notify the observers of the change, as needed.
803 for (var i = 0; i < this.observerInfos_.length; i++) {
804 var observerInfo = this.observerInfos_[i];
805 if (changed || !observerInfo.hasReceivedData ||
806 !observerInfo.ignoreWhenUnchanged) {
807 observerInfo.observer[this.observerMethodName_](this.currentData_);
808 observerInfo.hasReceivedData = true;
814 * Returns true if one of the observers actively wants the data
817 hasActiveObserver: function() {
818 for (var i = 0; i < this.observerInfos_.length; i++) {
819 if (this.observerInfos_[i].observer.isActive())
827 * This is a helper class used by PollableDataHelper, to keep track of
828 * each observer and whether or not it has received any data. The
829 * latter is used to make sure that new observers get sent data on the
830 * update following their creation.
833 function ObserverInfo(observer, ignoreWhenUnchanged) {
834 this.observer = observer;
835 this.hasReceivedData = false;
836 this.ignoreWhenUnchanged = ignoreWhenUnchanged;
840 * This is a helper class used by BrowserBridge to send data to
841 * a callback once data from all polls has been received.
843 * It works by keeping track of how many polling functions have
844 * yet to receive data, and recording the data as it it received.
848 function UpdateAllObserver(callback, pollableDataHelpers) {
849 this.callback_ = callback;
850 this.observingCount_ = 0;
851 this.updatedData_ = {};
853 for (var name in pollableDataHelpers) {
854 ++this.observingCount_;
855 var helper = pollableDataHelpers[name];
856 helper.addObserver(this);
857 this[helper.getObserverMethodName()] =
858 this.onDataReceived_.bind(this, helper, name);
862 UpdateAllObserver.prototype = {
863 isActive: function() {
867 onDataReceived_: function(helper, name, data) {
868 helper.removeObserver(this);
869 --this.observingCount_;
870 this.updatedData_[name] = data;
871 if (this.observingCount_ == 0)
872 this.callback_(this.updatedData_);
876 return BrowserBridge;