Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / settings / internet_page / internet_detail_page.js
blobb9bfab7bafb5175929c89c72a4d7ddfaed9d56b5
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  * 'cr-settings-internet-detail' is the settings subpage containing details
8  * for a network.
9  *
10  * @group Chrome Settings Elements
11  * @element cr-settings-internet-detail
12  */
13 (function() {
14 'use strict';
16 /** @const */ var CARRIER_VERIZON = 'Verizon Wireless';
18 Polymer({
19   is: 'cr-settings-internet-detail-page',
21   properties: {
22     /**
23      * The network GUID to display details for.
24      */
25     guid: {
26       type: String,
27       value: '',
28       observer: 'guidChanged_',
29     },
31     /**
32      * The current state for the network matching |guid|. TODO(stevenjb): Use
33      * chrome.networkingProperties.NetworkPoperties once it is defined. This
34      * will be a super-set of NetworkStateProperties. Currently properties that
35      * are not defined in NetworkStateProperties are accessed through
36      * CrOnc.getActive* which uses [] to access the property, which avoids any
37      * type checking (see CrOnc.getProperty for more info).
38      * @type {?CrOnc.NetworkStateProperties}
39      */
40     networkState: {
41       type: Object,
42       value: null,
43       observer: 'networkStateChanged_'
44     },
46     /**
47      * The network AutoConnect state.
48      */
49     autoConnect: {
50       type: Boolean,
51       value: false,
52       observer: 'autoConnectChanged_'
53     },
55     /**
56      * The network preferred state.
57      */
58     preferNetwork: {
59       type: Boolean,
60       value: false,
61       observer: 'preferNetworkChanged_'
62     },
64     /**
65      * The network IP Address.
66      */
67     IPAddress: {
68       type: String,
69       value: ''
70     },
72     /**
73      * Object providing network type values for data binding.
74      * @const
75      */
76     NetworkType: {
77       type: Object,
78       value: {
79         CELLULAR: CrOnc.Type.CELLULAR,
80         ETHERNET: CrOnc.Type.ETHERNET,
81         VPN: CrOnc.Type.VPN,
82         WIFI: CrOnc.Type.WI_FI,
83         WIMAX: CrOnc.Type.WI_MAX,
84       },
85       readOnly: true
86     },
87   },
89   /**
90    * Listener function for chrome.networkingPrivate.onNetworksChanged event.
91    * @type {function(!Array<string>)}
92    * @private
93    */
94   networksChangedListener_: function() {},
96   /** @override */
97   attached: function() {
98     this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
99     chrome.networkingPrivate.onNetworksChanged.addListener(
100         this.networksChangedListener_);
101   },
103   /** @override */
104   detached: function() {
105     chrome.networkingPrivate.onNetworksChanged.removeListener(
106         this.networksChangedListener_);
107   },
109   /**
110    * Polymer guid changed method.
111    */
112   guidChanged_: function() {
113     if (!this.guid)
114       return;
115     this.getNetworkDetails_();
116   },
118   /**
119    * Polymer networkState changed method.
120    */
121   networkStateChanged_: function() {
122     if (!this.networkState)
123       return;
125     // Update autoConnect if it has changed. Default value is false.
126     var autoConnect = /** @type {boolean} */(
127         CrOnc.getActiveTypeValue(this.networkState, 'AutoConnect')) || false;
128     if (autoConnect != this.autoConnect)
129       this.autoConnect = autoConnect;
131     // Update preferNetwork if it has changed. Default value is false.
132     var preferNetwork = this.networkState.Priority > 0;
133     if (preferNetwork != this.preferNetwork)
134       this.preferNetwork = preferNetwork;
136     // Set the IPAddress property to the IPV4 Address.
137     var ipv4 = CrOnc.getIPConfigForType(this.networkState, CrOnc.IPType.IPV4);
138     this.IPAddress = (ipv4 && ipv4.IPAddress) || '';
139   },
141   /**
142    * Polymer autoConnect changed method.
143    */
144   autoConnectChanged_: function() {
145     if (!this.networkState || !this.guid)
146       return;
147     var onc = this.getEmptyNetworkProperties_();
148     CrOnc.setTypeProperty(onc, 'AutoConnect', this.autoConnect);
149     this.setNetworkProperties_(onc);
150   },
152   /**
153    * Polymer preferNetwork changed method.
154    */
155   preferNetworkChanged_: function() {
156     if (!this.networkState || !this.guid)
157       return;
158     var onc = this.getEmptyNetworkProperties_();
159     onc.Priority = this.preferNetwork ? 1 : 0;
160     this.setNetworkProperties_(onc);
161   },
163   /**
164    * networkingPrivate.onNetworksChanged event callback.
165    * @param {!Array<string>} networkIds The list of changed network GUIDs.
166    * @private
167    */
168   onNetworksChangedEvent_: function(networkIds) {
169     if (networkIds.indexOf(this.guid) != -1)
170       this.getNetworkDetails_();
171   },
173   /**
174    * Calls networkingPrivate.getProperties for this.guid.
175    * @private
176    */
177   getNetworkDetails_: function() {
178     if (!this.guid)
179       return;
180     chrome.networkingPrivate.getProperties(
181         this.guid, this.getPropertiesCallback_.bind(this));
182   },
184   /**
185    * networkingPrivate.getProperties callback.
186    * @param {Object} properties The network properties.
187    * @private
188    */
189   getPropertiesCallback_: function(properties) {
190     this.networkState = /** @type {CrOnc.NetworkStateProperties}*/(properties);
191     if (!properties) {
192       // If state becomes null (i.e. the network is no longer visible), close
193       // the page.
194       this.fire('close');
195     }
196   },
198   /**
199    * @param {!chrome.networkingPrivate.NetworkConfigProperties} onc The ONC
200    *     network properties.
201    * @private
202    */
203   setNetworkProperties_: function(onc) {
204     if (!this.guid)
205       return;
206     chrome.networkingPrivate.setProperties(this.guid, onc, function() {
207       if (chrome.runtime.lastError) {
208         // An error typically indicates invalid input; request the properties
209         // to update any invalid fields.
210         this.getNetworkDetails_();
211       }
212     }.bind(this));
213   },
215   /**
216    * @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC
217    *     dictionary with just the Type property set. Used for passing properties
218    *     to setNetworkProperties_.
219    * @private
220    */
221   getEmptyNetworkProperties_: function() {
222     return {Type: this.networkState.Type};
223   },
225   /**
226    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
227    * @return {string} The text to display for the network name.
228    * @private
229    */
230   getStateName_: function(state) {
231     return (state && state.Name) || '';
232   },
234   /**
235    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
236    * @return {string} The text to display for the network connection state.
237    * @private
238    */
239   getStateText_: function(state) {
240     // TODO(stevenjb): Localize.
241     return (state && state.ConnectionState) || '';
242   },
244   /**
245    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
246    * @return {boolean} True if the state is connected.
247    * @private
248    */
249   isConnectedState_: function(state) {
250     return !!state && state.ConnectionState == CrOnc.ConnectionState.CONNECTED;
251   },
253   /**
254    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
255    * @return {boolean} Whether or not to show the 'Connect' button.
256    * @private
257    */
258   showConnect_: function(state) {
259     return !!state && state.Type != CrOnc.Type.ETHERNET &&
260            state.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
261   },
263   /**
264    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
265    * @return {boolean} Whether or not to show the 'Activate' button.
266    * @private
267    */
268   showActivate_: function(state) {
269     if (!state || state.Type != CrOnc.Type.CELLULAR)
270       return false;
271     var activation = state.Cellular.ActivationState;
272     return activation == CrOnc.ActivationState.NOT_ACTIVATED ||
273            activation == CrOnc.ActivationState.PARTIALLY_ACTIVATED;
274   },
276   /**
277    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
278    * @return {boolean} Whether or not to show the 'View Account' button.
279    * @private
280    */
281   showViewAccount_: function(state) {
282     // Show either the 'Activate' or the 'View Account' button.
283     if (this.showActivate_(state))
284       return false;
286     if (!state || state.Type != CrOnc.Type.CELLULAR || !state.Cellular)
287       return false;
289     // Only show if online payment URL is provided or the carrier is Verizon.
290     var carrier = CrOnc.getActiveValue(state, 'Cellular.Carrier');
291     if (carrier != CARRIER_VERIZON) {
292       var paymentPortal = /** @type {CrOnc.PaymentPortal|undefined} */(
293           CrOnc.getActiveValue(state, 'Cellular.PaymentPortal'));
294       if (!paymentPortal || !paymentPortal.Url)
295         return false;
296     }
298     // Only show for connected networks or LTE networks with a valid MDN.
299     if (!this.isConnectedState_(state)) {
300       var technology = /** @type {CrOnc.NetworkTechnology|undefined} */(
301           CrOnc.getActiveValue(state, 'Cellular.NetworkTechnology'));
302       if (technology != CrOnc.NetworkTechnology.LTE &&
303           technology != CrOnc.NetworkTechnology.LTE_ADVANCED) {
304         return false;
305       }
306       if (!CrOnc.getActiveValue(state, 'Cellular.MDN'))
307         return false;
308     }
310     return true;
311   },
313   /**
314    * @return {boolean} Whether or not to enable the network connect button.
315    * @private
316    */
317   enableConnect_: function(state) {
318     if (!state || !this.showConnect_(state))
319       return false;
320     if (state.Type == CrOnc.Type.CELLULAR && CrOnc.isSimLocked(state))
321       return false;
322     // TODO(stevenjb): For VPN, check connected state of any network.
323     return true;
324   },
326   /**
327    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
328    * @return {boolean} Whether or not to show the 'Disconnect' button.
329    * @private
330    */
331   showDisconnect_: function(state) {
332     return !!state && state.Type != CrOnc.Type.ETHERNET &&
333            state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED;
334   },
336   /**
337    * Callback when the Connect button is clicked.
338    * @private
339    */
340   onConnectClicked_: function() {
341     chrome.networkingPrivate.startConnect(this.guid);
342   },
344   /**
345    * Callback when the Disconnect button is clicked.
346    * @private
347    */
348   onDisconnectClicked_: function() {
349     chrome.networkingPrivate.startDisconnect(this.guid);
350   },
352   /**
353    * Callback when the Activate button is clicked.
354    * @private
355    */
356   onActivateClicked_: function() {
357     chrome.networkingPrivate.startActivate(this.guid);
358   },
360   /**
361    * Callback when the View Account button is clicked.
362    * @private
363    */
364   onViewAccountClicked_: function() {
365     // startActivate() will show the account page for activated networks.
366     chrome.networkingPrivate.startActivate(this.guid);
367   },
369   /**
370    * Event triggered for elements associated with network properties.
371    * @param {!{detail: !{field: string, value: (string|!Object)}}} event
372    * @private
373    */
374   onNetworkPropertyChange_: function(event) {
375     if (!this.networkState)
376       return;
377     var field = event.detail.field;
378     var value = event.detail.value;
379     var onc = this.getEmptyNetworkProperties_();
380     if (field == 'APN') {
381       CrOnc.setTypeProperty(onc, 'APN', value);
382     } else if (field == 'SIMLockStatus') {
383       CrOnc.setTypeProperty(onc, 'SIMLockStatus', value);
384     } else {
385       console.error('Unexpected property change event: ', field);
386       return;
387     }
388     this.setNetworkProperties_(onc);
389   },
391   /**
392    * Event triggered when the IP Config or NameServers element changes.
393    * @param {!{detail: !{field: string,
394    *                     value: (string|!CrOnc.IPConfigProperties|
395    *                             !Array<string>)}}} event
396    *     The network-ip-config or network-nameservers change event.
397    * @private
398    */
399   onIPConfigChange_: function(event) {
400     if (!this.networkState)
401       return;
402     var field = event.detail.field;
403     var value = event.detail.value;
404     // Get an empty ONC dictionary and set just the IP Config properties that
405     // need to change.
406     var onc = this.getEmptyNetworkProperties_();
407     var ipConfigType =
408         /** @type {chrome.networkingPrivate.IPConfigType|undefined} */(
409             CrOnc.getActiveValue(this.networkState, 'IPAddressConfigType'));
410     if (field == 'IPAddressConfigType') {
411       var newIpConfigType =
412           /** @type {chrome.networkingPrivate.IPConfigType} */(value);
413       if (newIpConfigType == ipConfigType)
414         return;
415       onc.IPAddressConfigType = newIpConfigType;
416     } else if (field == 'NameServersConfigType') {
417       var nsConfigType =
418           /** @type {chrome.networkingPrivate.IPConfigType|undefined} */(
419               CrOnc.getActiveValue(this.networkState, 'NameServersConfigType'));
420       var newNsConfigType =
421           /** @type {chrome.networkingPrivate.IPConfigType} */(value);
422       if (newNsConfigType == nsConfigType)
423         return;
424       onc.NameServersConfigType = newNsConfigType;
425     } else if (field == 'StaticIPConfig') {
426       if (ipConfigType == CrOnc.IPConfigType.STATIC) {
427         var staticIpConfig = /** @type {CrOnc.IPConfigProperties|undefined} */(
428             CrOnc.getActiveValue(this.networkState, 'StaticIPConfig'));
429         if (staticIpConfig &&
430             this.allPropertiesMatch_(staticIpConfig,
431                                      /** @type {!Object} */(value))) {
432           return;
433         }
434       }
435       onc.IPAddressConfigType = CrOnc.IPConfigType.STATIC;
436       if (!onc.StaticIPConfig) {
437         onc.StaticIPConfig =
438             /** @type {!chrome.networkingPrivate.IPConfigProperties} */({});
439       }
440       for (let key in value)
441         onc.StaticIPConfig[key] = value[key];
442     } else if (field == 'NameServers') {
443       // If a StaticIPConfig property is specified and its NameServers value
444       // matches the new value, no need to set anything.
445       var nameServers = /** @type {!Array<string>} */(value);
446       if (onc.NameServersConfigType == CrOnc.IPConfigType.STATIC &&
447           onc.StaticIPConfig &&
448           onc.StaticIPConfig.NameServers == nameServers) {
449         return;
450       }
451       onc.NameServersConfigType = CrOnc.IPConfigType.STATIC;
452       if (!onc.StaticIPConfig) {
453         onc.StaticIPConfig =
454             /** @type {!chrome.networkingPrivate.IPConfigProperties} */({});
455       }
456       onc.StaticIPConfig.NameServers = nameServers;
457     } else {
458       console.error('Unexpected change field: ' + field);
459       return;
460     }
461     // setValidStaticIPConfig will fill in any other properties from
462     // networkState. This is necessary since we update IP Address and
463     // NameServers independently.
464     CrOnc.setValidStaticIPConfig(onc, this.networkState);
465     this.setNetworkProperties_(onc);
466   },
468   /**
469    * Event triggered when the Proxy configuration element changes.
470    * @param {!{detail: {field: string, value: !CrOnc.ProxySettings}}} event
471    *     The network-proxy change event.
472    * @private
473    */
474   onProxyChange_: function(event) {
475     if (!this.networkState)
476       return;
477     var field = event.detail.field;
478     var value = event.detail.value;
479     if (field != 'ProxySettings')
480       return;
481     var onc = this.getEmptyNetworkProperties_();
482     CrOnc.setProperty(onc, 'ProxySettings', /** @type {!Object} */(value));
483     this.setNetworkProperties_(onc);
484   },
486   /**
487    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
488    * @return {boolean} True if the shared message should be shown.
489    * @private
490    */
491   showShared_: function(state) {
492     return !!state &&
493            (state.Source == 'Device' || state.Source == 'DevicePolicy');
494   },
496   /**
497    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
498    * @return {boolean} True if the AutoConnect checkbox should be shown.
499    * @private
500    */
501   showAutoConnect_: function(state) {
502     return !!state && state.Type != CrOnc.Type.ETHERNET &&
503            state.Source != CrOnc.Source.NONE;
504   },
506   /**
507    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
508    * @return {boolean} True if the prefer network checkbox should be shown.
509    * @private
510    */
511   showPreferNetwork_: function(state) {
512     // TODO(stevenjb): Resolve whether or not we want to allow "preferred" for
513     // state.Type == CrOnc.Type.ETHERNET.
514     return !!state && state.Source != CrOnc.Source.NONE;
515   },
517   /**
518    * @param {boolean} preferNetwork
519    * @return {string} The icon to use for the preferred button.
520    * @private
521    */
522   getPreferredIcon_: function(preferNetwork) {
523     return preferNetwork ? 'star' : 'star-border';
524   },
526   /**
527    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
528    * @return {!Array<string>} The fields to display in the info section.
529    * @private
530    */
531   getInfoFields_: function(state) {
532     /** @type {!Array<string>} */ var fields = [];
533     if (!state)
534       return fields;
536     if (state.Type == CrOnc.Type.CELLULAR) {
537       fields.push('Cellular.ActivationState',
538                   'Cellular.RoamingState',
539                   'RestrictedConnectivity',
540                   'Cellular.ServingOperator.Name');
541     }
542     if (state.Type == CrOnc.Type.VPN) {
543       fields.push('VPN.Host', 'VPN.Type');
544       if (state.VPN.Type == 'OpenVPN')
545         fields.push('VPN.OpenVPN.Username');
546       else if (state.VPN.Type == 'L2TP-IPsec')
547         fields.push('VPN.L2TP.Username');
548       else if (state.VPN.Type == 'ThirdPartyVPN')
549         fields.push('VPN.ThirdPartyVPN.ProviderName');
550     }
551     if (state.Type == CrOnc.Type.WI_FI)
552       fields.push('RestrictedConnectivity');
553     if (state.Type == CrOnc.Type.WI_MAX) {
554       fields.push('RestrictedConnectivity', 'WiMAX.EAP.Identity');
555     }
556     return fields;
557   },
559   /**
560    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
561    * @return {!Array<string>} The fields to display in the Advanced section.
562    * @private
563    */
564   getAdvancedFields_: function(state) {
565     /** @type {!Array<string>} */ var fields = [];
566     if (!state)
567       return fields;
568     fields.push('MacAddress');
569     if (state.Type == CrOnc.Type.CELLULAR) {
570       fields.push('Cellular.Carrier',
571                   'Cellular.Family',
572                   'Cellular.NetworkTechnology',
573                   'Cellular.ServingOperator.Code');
574     }
575     if (state.Type == CrOnc.Type.WI_FI) {
576       fields.push('WiFi.SSID',
577                   'WiFi.BSSID',
578                   'WiFi.Security',
579                   'WiFi.SignalStrength',
580                   'WiFi.Frequency');
581     }
582     if (state.Type == CrOnc.Type.WI_MAX)
583       fields.push('WiFi.SignalStrength');
584     return fields;
585   },
587   /**
588    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
589    * @return {!Array<string>} The fields to display in the device section.
590    * @private
591    */
592   getDeviceFields_: function(state) {
593     /** @type {!Array<string>} */ var fields = [];
594     if (!state)
595       return fields;
596     if (state.Type == CrOnc.Type.CELLULAR) {
597       fields.push('Cellular.HomeProvider.Name',
598                   'Cellular.HomeProvider.Country',
599                   'Cellular.HomeProvider.Code',
600                   'Cellular.Manufacturer',
601                   'Cellular.ModelID',
602                   'Cellular.FirmwareRevision',
603                   'Cellular.HardwareRevision',
604                   'Cellular.ESN',
605                   'Cellular.ICCID',
606                   'Cellular.IMEI',
607                   'Cellular.IMSI',
608                   'Cellular.MDN',
609                   'Cellular.MEID',
610                   'Cellular.MIN',
611                   'Cellular.PRLVersion');
612     }
613     return fields;
614   },
616   /**
617    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
618    * @return {boolean} True if there are any advanced fields to display.
619    * @private
620    */
621   hasAdvancedOrDeviceFields_: function(state) {
622     return this.getAdvancedFields_(state).length > 0 ||
623            this.hasDeviceFields_(state);
624   },
626   /**
627    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
628    * @return {boolean} True if there are any device fields to display.
629    * @private
630    */
631   hasDeviceFields_: function(state) {
632     var fields = this.getDeviceFields_(state);
633     return fields.length > 0;
634   },
636   /**
637    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
638    * @return {boolean} True if the network section should be shown.
639    * @private
640    */
641   hasNetworkSection_: function(state) {
642     return !!state && state.Type != CrOnc.Type.VPN;
643   },
645   /**
646    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
647    * @param {string} type The network type.
648    * @return {boolean} True if the network type matches 'type'.
649    * @private
650    */
651   isType_: function(state, type) {
652     return !!state && state.Type == type;
653   },
655   /**
656    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
657    * @return {boolean} True if the Cellular SIM section should be shown.
658    * @private
659    */
660   showCellularSim_: function(state) {
661     if (!state || state.Type != 'Cellular')
662       return false;
663     return CrOnc.getActiveValue(state, 'Cellular.Family') == 'GSM';
664   },
666   /**
667    * @param {!Object} curValue
668    * @param {!Object} newValue
669    * @return {boolean} True if all properties set in |newValue| are equal to
670    *     the corresponding properties in |curValue|. Note: Not all properties
671    *     of |curValue| need to be specified in |newValue| for this to return
672    *     true.
673    * @private
674    */
675   allPropertiesMatch_: function(curValue, newValue) {
676     for (let key in newValue) {
677       if (newValue[key] != curValue[key])
678         return false;
679     }
680     return true;
681   }
683 })();