3e27cdd79400a66e64059e00b00d16b2c5b0f2a7
[profile/ivi/SettingsApp.git] / js / panel-connman.js
1 /*
2  * Copyright (c) 2013, Intel Corporation.
3  *
4  * This program is licensed under the terms and conditions of the
5  * Apache License, version 2.0.  The full text of the Apache License is at
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  */
9 var connmanScanInProgress = false;
10
11 function connmanPanelInit() {
12
13     /* Connman Settings Panel */
14     $('#page_connman').on('pageshow', function(event, data) {
15         if (data.prevPage.attr('id') === 'page_connman_service') return;
16
17         wsAPI.subscribeEvents(connmanEventReceived);
18
19         console.log('Get all the available technologies');
20         settings.connman.getTechnologies(function(technologies) {
21             for (var i = 0; i < technologies.length; i++) {
22                 var technology = technologies[i];
23                 console.log('Connman technology found: ' + technology.prop.Type);
24                 if (technology.prop.Type === 'bluetooth') {
25                     /* Do not show bluetooth */
26                     continue;
27                 }
28                 if (technology.prop.Powered === undefined) {
29                     (function(t) {
30                         t.getPowered(function(is_powered) {
31                             t.prop.Powered = is_powered;
32                             if ($('#toggle_connman_' + t.prop.Type).length <= 0) {
33                                 /* element doesn't exist, create it */
34                                 connmanConstructTechnologyElement(t);
35                             } else {
36                                 /* element already exist */
37                                 connmanToggleTechnology(t.prop.Type, is_powered);
38                             }
39                         }, function(e) {
40                             t.prop.Powered = false;
41                             connmanConstructTechnologyElement(t);
42                         });
43                     })(technology);
44                 } else {
45                     if ($('#toggle_connman_' + technology.prop.Type).length <= 0) {
46                         /* element doesn't exist, create it */
47                         connmanConstructTechnologyElement(technology);
48                     } else {
49                         /* element already exist */
50                         connmanToggleTechnology(technology.prop.Type, technology.prop.Powered);
51                     }
52                 }
53             }
54         }, function(e) {
55             showMsg('Error', e);
56         });
57     });
58
59     $('#button_connman_refresh').on('click', function() {
60         /* connman only supports wifi scan */
61         if ($('#toggle_connman_wifi').val() === 'on') {
62             connmanScan('/net/connman/technology/wifi');
63         } else {
64             connmanSync(null, function(e) {
65                 showMsg('Error', e);
66             });
67         }
68     });
69
70     $('#button_connman_wifi_add').on('click', function() {
71         if (connmanScanInProgress) return;
72
73         console.log('Enter add WiFi page');
74         $.mobile.changePage('#page_wifi_add');
75     });
76
77     /* Connman tethering page */
78     $('#page_connman_tethering').on('pageshow', function(event, data) {
79         connmanTetheringPageReload();
80     });
81
82     /* Connman service detail page */
83     $('#page_connman_service').on('pageshow', function(event, data) {
84         var service_id = localStorage.getItem('connman_service_id');
85         if (service_id == undefined) return;
86         var service = $(jqId(service_id)).data('service-object');
87         connmanConstructServicePanel(service);
88     });
89
90     /* WiFi connect page */
91     $('#page_wifi_connect').on('pagebeforeshow', function(event, data) {
92         $('#input_wifi_connect_passphrase').val('');
93     });
94
95     /* WiFi add new network page */
96     $('#page_wifi_add').on('pagebeforeshow', function(event, data) {
97         $('#input_wifi_add_ssid').val('');
98         $('#input_wifi_add_password').val('');
99         $('#radio_wifi_none').prop('checked', true);
100         $('input[name=radio_wifi_security]').checkboxradio('refresh');
101         $('#input_wifi_add_password').textinput('disable');
102     });
103
104     $('#button_wifi_add').on('click', function() {
105         var name = $('#input_wifi_add_ssid').val();
106         var security = $('input[name=radio_wifi_security]:checked').val();
107         var passcode = $('#input_wifi_add_password').val();
108
109         if (name === '') {
110             showMsg('Error', 'Enter SSID');
111             return;
112         }
113
114         if (security !== 'none' && passcode === '') {
115             showMsg('Error', 'Enter passphrase');
116             return;
117         }
118
119         showSpinner(false, 'Adding...');
120         connmanGetHiddenServicePath(security, function(service_path) {
121             var service = new settings.connman.ConnmanService('', {
122                 'Name': name,
123                 'EncryptionMode': security
124             });
125             service.connect(passcode, function() {
126                 /* success */
127                 connmanSync(function() {
128                     hideSpinner();
129                     console.log('Go back to Connman page');
130                     $.mobile.changePage('#page_connman');
131                 }, function(e) {
132                     showMsg('Error', e);
133                 });
134             }, function(e) {
135                 /* error */
136                 hideSpinner();
137                 showMsg('Error', 'Failed to add network: ' + e);
138             });
139         }, function(e) {
140             hideSpinner();
141             showMsg('Error', e);
142         });
143     });
144
145     $('[name="radio_wifi_security"]').on('change', function(event, data) {
146         var security = $('input[name=radio_wifi_security]:checked').val();
147
148         if (security === 'none') {
149             $('#input_wifi_add_password').textinput('disable');
150             $('#input_wifi_add_password').val('');
151         } else {
152             $('#input_wifi_add_password').textinput('enable');
153         }
154     });
155
156     $('#button_wifi_connect').on('click', function() {
157         var service_id = localStorage.getItem('connman_service_id');
158         if (service_id == undefined) return;
159         var service = $(jqId(service_id)).data('service-object');
160         var passcode = $('#input_wifi_connect_passphrase').val();
161         connmanConnectToService(service, passcode, function() {
162             console.log('Successfully connected to service: ' + service.prop.Name);
163             if ($.mobile.activePage.attr('id') !== 'page_connman') {
164                 console.log('Go back to Connman page');
165                 $.mobile.changePage('#page_connman');
166             }
167         }, function(e) {
168             showMsg('Error', 'Connect failed: ' + e);
169         });
170     });
171 }
172
173 function connmanEventReceived(event) {
174     if (event.type === WS_EVENT_TYPE.CONNMAN) {
175         if ($.mobile.activePage.attr('id') !== 'page_connman' && $.mobile.activePage.attr('id') !== 'page_connman_service') {
176             return;
177         }
178
179         if (event.name === 'ServicesChanged') {
180             connmanHandleServicesChanged(event.id, event.value);
181         } else if (event.name === 'PropertyChanged') {
182             connmanHandlePropertyChanged(event.id, event.value);
183         } else {
184             console.log('Unsupported event received: ' + event.name);
185         }
186     }
187 }
188
189 function connmanHandleServicesChanged(object_path, services) {
190     var servicesChanged = services[0];
191     var servicesRemoved = services[1];
192
193     console.log(servicesChanged.length + ' services changed');
194     for (var i = 0; i < servicesChanged.length; i++) {
195         if (servicesChanged[i][0] === undefined) {
196             console.log('Invalid parameters, missing object path');
197             continue;
198         }
199
200         var service = $(jqId(servicesChanged[i][0])).data('service-object');
201
202         if (service == null) {
203             console.log('could not find service object ' + servicesChanged[i][0]);
204             continue;
205         }
206
207         for (var prop in servicesChanged[i][1]) {
208             if (servicesChanged[i][1].hasOwnProperty(prop)) {
209                 service.prop.prop = servicesChanged[i][1].prop;
210                 connmanUpdateService(service);
211                 console.log('Service ' + service.prop.Name + ' updated: ' + prop);
212             }
213         }
214     }
215
216     console.log(servicesRemoved.length + ' services removed');
217     for (var i = 0; i < servicesRemoved.length; i++) {
218         if (servicesRemoved[i] === undefined) {
219             console.log('Invalid parameters, missing object path');
220             continue;
221         }
222
223         connmanRemoveFromAvailableList(servicesRemoved[i]);
224     }
225 }
226
227 function connmanHandlePropertyChanged(id, property) {
228     if (property[0] === 'Powered') {
229         var index = id.lastIndexOf('/');
230         var technology = id.substring(index + 1);
231         if (property[1] === true) {
232             connmanToggleTechnology(technology, true);
233             if (technology === 'wifi') {
234                 setTimeout(function() {
235                     /* add a 1 sec delay */
236                     connmanScan(id);
237                 }, 1000);
238             }
239         } else {
240             connmanToggleTechnology(technology, false);
241         }
242     }
243
244     if (property[0] === 'State') {
245         /* specific service has changed */
246         var service = $(jqId(id)).data('service-object');
247         if (service == null) {
248             console.error('Connman service not found ' + id);
249             return;
250         }
251
252         service.prop.State = property[1];
253         connmanUpdateService(service);
254     } else if (property[0] === 'Connected') {
255         /* unknown service has changed, sync Connman */
256         console.log('Unknown service connected property changed');
257         connmanSync(null, function(e) {
258             showMsg('Error', e);
259         });
260     }
261 }
262
263 function connmanClearAvailableList() {
264     $('#listview_services_available').html('');
265 }
266
267 function connmanScan(technology) {
268     if (technology !== '/net/connman/technology/wifi') {
269         /* Connman only supports wifi scan */
270         return;
271     }
272
273     if (connmanScanInProgress) {
274         console.log('Connman scan in progress...');
275         return;
276     }
277
278     console.log('Start connman scan');
279     connmanScanInProgress = true;
280
281     /* clear the services list with new scan */
282     connmanClearAvailableList();
283
284     showSpinner(false, 'Scanning...');
285     $('#toggle_connman_wifi').slider('disable');
286     $('#toggle_connman_wifi').slider('refresh');
287     settings.connman.scan(technology, function(services) {
288         hideSpinner();
289         connmanScanInProgress = false;
290         $('#toggle_connman_wifi').slider('enable');
291         $('#toggle_connman_wifi').slider('refresh');
292         console.log('found ' + services.length + ' connman services');
293         for (var i = 0; i < services.length; i++) {
294             var service = services[i];
295             if (service.prop.Type === undefined || service.prop.Type === 'bluetooth') {
296                 console.log('Ignore bluetooth or unknown services');
297                 continue;
298             }
299             if (service.prop.Name === undefined) {
300                 console.log('Ignore hidden service - ' + service.id);
301                 continue;
302             }
303
304             connmanUpdateService(service);
305         }
306     }, function(e) {
307         hideSpinner();
308         connmanScanInProgress = false;
309         $('#toggle_connman_wifi').slider('enable');
310         $('#toggle_connman_wifi').slider('refresh');
311         showMsg('Error', 'Cannot scan: ' + e);
312     });
313 }
314
315 function connmanSync(success_cb, error_cb) {
316     if (connmanScanInProgress) {
317         console.log('Connman scan in progress...');
318         return;
319     }
320
321     console.log('Start connman sync');
322     /* clear the services list with new scan */
323     connmanClearAvailableList();
324
325     wifiScanInProgress = true;
326     $('#toggle_connman_wifi').slider('disable');
327     $('#toggle_connman_wifi').slider('refresh');
328     settings.connman.getServices(function(services) {
329         connmanScanInProgress = false;
330         $('#toggle_connman_wifi').slider('enable');
331         $('#toggle_connman_wifi').slider('refresh');
332         console.log('found ' + services.length + ' connman services');
333         for (var i = 0; i < services.length; i++) {
334             var service = services[i];
335             if (service.prop.Type === undefined || service.prop.Type === 'bluetooth') {
336                 console.log('Ignore bluetooth or unknown services');
337                 continue;
338             }
339             if (service.prop.Name === undefined) {
340                 console.log('Ignore hidden service - ' + service.id);
341                 continue;
342             }
343
344             connmanUpdateService(service);
345         }
346         if (success_cb) {
347             success_cb();
348         }
349     }, function(e) {
350         connmanScanInProgress = false;
351         $('#toggle_connman_wifi').slider('enable');
352         $('#toggle_connman_wifi').slider('refresh');
353         if (error_cb) {
354             error_cb(e);
355         }
356     });
357 }
358
359 function connmanRefreshServicesList() {
360     $('#listview_services_available').listview('refresh');
361 }
362
363 function connmanAppendToAvailableList(service) {
364     if ($('#listview_services_available').find(jqId(service.id)).length != 0) return;
365
366     var parent = '#listview_services_available';
367     connmanConstructServiceElement(parent, service);
368     connmanUpdateServiceButton(service);
369     connmanRefreshServicesList();
370 }
371
372 function connmanRemoveFromAvailableList(service_id) {
373     var removeThis = $('#listview_services_available li').filter(function() {
374         return $(this).find(jqId(service_id)).length === 1;
375     });
376
377     if (removeThis.length !== 0) {
378         removeThis.remove();
379         connmanRefreshServicesList();
380     }
381 }
382
383 function getSignalStrengthStr(strength) {
384     var signal_strength = 'unknown';
385     if (strength > 0 && strength <= 20) {
386         strength = 'very poor';
387     } else if (strength > 20 && strength <= 40) {
388         signal_strength = 'poor';
389     } else if (strength > 40 && strength <= 70) {
390         signal_strength = 'average';
391     } else if (strength > 70 && strength <= 90) {
392         signal_strength = 'good';
393     } else if (strength > 90 && strength <= 100) {
394         signal_strength = 'excellent';
395     }
396     return signal_strength;
397 }
398
399 function connmanConstructTechnologyElement(technology) {
400     if (technology.prop.Type === undefined || technology.prop.Name == undefined) {
401         console.error('technology type or name missing ' + technology);
402         return;
403     }
404
405     var html = '<ul data-role="listview" data-inset="true" class="ui-listview ui-listview-inset">';
406     html += '<li data-role="fieldcontain">';
407     html += '<label for="toggle_connman_' + technology.prop.Type + '" class="ui-slider">' + technology.prop.Name + '</label>';
408     html += '<select data-role="slider" name="toggle_connman_' + technology.prop.Type + '" ';
409     html += 'id="toggle_connman_' + technology.prop.Type + '" class="ui-slider-switch">';
410     html += '<option value="off">Off</option>';
411     html += '<option value="on">On</option>';
412     html += '</select></li></ul>';
413     $('#connman_technologies').append(html).trigger('create');
414
415     console.log('Connman technology ' + technology.prop.Type + ' is powered: ' + technology.prop.Powered);
416     if (technology.prop.Powered) {
417         connmanToggleTechnology(technology.prop.Type, true);
418         if ($('ul#listview_services_available li').length === 0) {
419             /* connman only supports wifi scan */
420             if (technology.prop.Type === 'wifi') {
421                 connmanScan(technology.id);
422             } else {
423                 connmanSync(null, function(e) {
424                     showMsg('Error', e);
425                 });
426             }
427         }
428     } else {
429         connmanToggleTechnology(technology.prop.Type, false);
430     }
431
432     $('#toggle_connman_' + technology.prop.Type).change(function() {
433         console.log('toggle ' + technology.prop.Type + ' changed');
434
435         if (connmanScanInProgress) {
436             console.log('Connman scan in progress...');
437             return;
438         }
439
440         $('#toggle_connman_' + technology.prop.Type).slider('disable');
441         $('#toggle_connman_' + technology.prop.Type).slider('refresh');
442         if ($('#toggle_connman_' + technology.prop.Type).val() === 'off') {
443             technology.setPowered(false, function() {
444                 /* success */
445                 $('#toggle_connman_' + technology.prop.Type).slider('enable');
446                 $('#toggle_connman_' + technology.prop.Type).slider('refresh');
447                 console.log('Successfully disabled connman technology ' + technology.prop.Type);
448             }, function(e) {
449                 /* error */
450                 hideSpinner();
451                 $('#toggle_connman_' + technology.prop.Type).slider('enable');
452                 $('#toggle_connman_' + technology.prop.Type).val('on').slider('refresh');
453                 showMsg('Error', 'Cannot disable ' + technology.prop.Type);
454             });
455         } else {
456             technology.setPowered(true, function() {
457                 /* success */
458                 $('#toggle_connman_' + technology.prop.Type).slider('enable');
459                 $('#toggle_connman_' + technology.prop.Type).slider('refresh');
460                 console.log('Successfully enabled connman technology ' + technology.prop.Type);
461             }, function(e) {
462                 /* error */
463                 hideSpinner();
464                 $('#toggle_connman_' + technology.prop.Type).slider('enable');
465                 $('#toggle_connman_' + technology.prop.Type).val('off').slider('refresh');
466                 showMsg('Error', 'Cannot enable ' + technology.prop.Type);
467             });
468         }
469     });
470 }
471
472 function connmanConstructServiceElement(parent, service) {
473     if (service.id === undefined || service.prop.Type === undefined) {
474         console.error('service id or type missing ' + service);
475         return;
476     }
477
478     var html = '<li data-icon="false"><a href="#" id="' + jqId(service.id).replace('#', '') + '">';
479     html += '<div class="service-ssid">' + service.prop.Name + '</div>';
480
481     if (service.prop.Type === 'wifi') {
482         html += '<div class="service-encryption">Encryption: ' + service.prop.EncryptionMode + '</div>';
483         html += '<div class="service-strength">Signal: ' + getSignalStrengthStr(service.prop.Strength) + '</div>';
484     }
485     html += '<div class="service-status"></div>';
486     html += '<div data-role="button" class="service-action-button ui-li-aside" data-inline="true"></div>';
487     html += '</a></li>';
488     $(parent).append(html).trigger('create');
489
490     /* store service object in the element so we can reference it later */
491     $(jqId(service.id)).data('service-object', service);
492
493     $(jqId(service.id)).on('click', function() {
494         /* BUG in webruntime that cause click event when another page is rendered */
495         if ($.mobile.activePage.attr('id') === 'page_connman') {
496             localStorage.setItem('connman_service_id', service.id);
497             console.log('Enter Connman service page');
498             $.mobile.changePage('#page_connman_service');
499         }
500     });
501
502     $(jqId(service.id)).find('div.service-action-button').on('click', function(e) {
503         var parent = $(this).parent().attr('id');
504
505         /*
506          * prevent the click event to propagate up
507          */
508         e.stopImmediatePropagation();
509         e.preventDefault();
510
511         /* retrieve the service object from element */
512         var service = $(jqId(parent)).data('service-object');
513         if (service == null) {
514             console.error('Connman service object not found');
515             return;
516         }
517
518         if (service.prop.State === 'idle') {
519             if (service.prop.EncryptionMode === 'none') {
520                 connmanConnectToService(service, null);
521             } else {
522                 connmanConnectToService(service, null, null, function(e) {
523                     console.log('Connect failed, will ask for passphrase');
524                     localStorage.setItem('connman_service_id', service.id);
525                     console.log('Enter connect WiFi page');
526                     $.mobile.changePage('#page_wifi_connect');
527                 });
528             }
529         } else if (service.prop.State === 'ready') {
530             console.log('Disconnecting from service: ' + service.prop.Name);
531             showSpinner(false, 'Disconnecting...');
532             service.disconnect(function() {
533                 /* success */
534                 connmanSync(function() {
535                     hideSpinner();
536                 }, function(e) {
537                     showMsg('Error', e);
538                 })
539             }, function(e) {
540                 /* error */
541                 hideSpinner();
542                 showMsg('Error', 'Disconnect service failed: ' + e);
543             });
544         }
545     });
546 }
547
548 function connmanTetheringPageReload() {
549     $('#connman_tethering_technologies').html('');
550     settings.connman.getTechnologies(function(technologies) {
551         for (var i = 0; i < technologies.length; i++) {
552             var technology = technologies[i];
553             console.log('Connman technology available for tethering: ' + technology.prop.Name);
554             connmanConstructTetheringElement(technology);
555         }
556     }, function(e) {
557         showMsg('Error', e);
558     });
559 }
560
561 function connmanConstructTetheringElement(technology) {
562     if (technology.prop.Type === undefined || technology.prop.Name == undefined) {
563         console.error('technology type or name missing ' + technology);
564         return;
565     }
566
567     var html = '<ul data-role="listview" data-inset="true" class="ui-listview ui-listview-inset">';
568     html += '<li data-role="fieldcontain">';
569     html += '<label for="toggle_tethering_' + technology.prop.Type + '" class="ui-slider">Tether ' + technology.prop.Name + '</label>';
570     html += '<select data-role="slider" name="toggle_tethering_' + technology.prop.Type + '" ';
571     html += 'id="toggle_tethering_' + technology.prop.Type + '" class="ui-slider-switch">';
572     html += '<option value="off">Off</option>';
573     html += '<option value="on">On</option>';
574     html += '</select></li></ul>';
575     $('#connman_tethering_technologies').append(html).trigger('create');
576
577     console.log('Connman technology ' + technology.prop.Type + ' is tethered: ' + technology.prop.Tethering);
578
579     if (technology.prop.Powered === true && technology.prop.Connected === true) {
580         if (technology.prop.Tethering === true) {
581             $('#toggle_tethering_' + technology.prop.Type).val('on').slider('refresh');
582             $('#input_wifi_tethering_id').textinput('disable');
583             $('#input_wifi_tethering_passphrase').textinput('disable');
584             /* WiFi-only options */
585             if (technology.prop.Type === 'wifi') {
586                 $('#connman_wifi_tethering_options').show();
587                 if (technology.prop.TetheringIdentifier) {
588                     $('#input_wifi_tethering_id').val(technology.prop.TetheringIdentifier);
589                 }
590                 if (technology.prop.TetheringPassphrase) {
591                     $('#input_wifi_tethering_passphrase').val(technology.prop.TetheringPassphrase);
592                 }
593             }
594         } else {
595             $('#toggle_tethering_' + technology.prop.Type).val('off').slider('refresh');
596         }
597     } else {
598         if (technology.prop.Type === 'wifi') {
599             $('#input_wifi_tethering_id').textinput('disable');
600             $('#input_wifi_tethering_passphrase').textinput('disable');
601         }
602         $('#toggle_tethering_' + technology.prop.Type).slider('disable');
603         $('#toggle_tethering_' + technology.prop.Type).slider('refresh');
604     }
605
606     $('#toggle_tethering_' + technology.prop.Type).change(function() {
607         if ($('#toggle_tethering_' + technology.prop.Type).val() === 'on') {
608             if (technology.prop.Type === 'wifi') {
609                 var tethering_id = $('#input_wifi_tethering_id').val();
610                 var tethering_passphrase = $('#input_wifi_tethering_passphrase').val();
611                 if (tethering_id === '' || tethering_passphrase === '') {
612                     connmanTetheringPageReload();
613                     showMsg('Error', 'Please provide identifier and passphrase');
614                     return;
615                 }
616
617                 technology.setTethering(true, tethering_id, tethering_passphrase, function() {
618                     /* success */
619                     console.log('Successfully tethered connman technology ' + technology.prop.Type);
620                     connmanTetheringPageReload();
621                 }, function(e) {
622                     /* error */
623                     connmanTetheringPageReload();
624                     showMsg('Error', 'Cannot tether ' + technology.prop.Type + ': ' + e);
625                 });
626             } else {
627                 technology.setTethering(true, '', '', function() {
628                     /* success */
629                     console.log('Successfully tethered connman technology ' + technology.prop.Type);
630                     connmanTetheringPageReload();
631                 }, function(e) {
632                     /* error */
633                     connmanTetheringPageReload();
634                     showMsg('Error', 'Cannot tether ' + technology.prop.Type + ': ' + e);
635                 });
636             }
637         } else {
638             technology.setTethering(false, '', '', function() {
639                 /* success */
640                 console.log('Successfully untethered connman technology ' + technology.prop.Type);
641                 connmanTetheringPageReload();
642             }, function(e) {
643                 /* error */
644                 connmanTetheringPageReload();
645                 showMsg('Error', 'Cannot untether ' + technology.prop.Type + ': ' + e);
646             });
647         }
648     });
649 }
650
651 function connmanUpdateService(service) {
652     connmanAppendToAvailableList(service);
653
654     /* update service button for allowed action */
655     connmanUpdateServiceButton(service);
656
657     /* update service connection status */
658     connmanUpdateConnectionStatus(service);
659
660     /* update service detail panel */
661     if ($.mobile.activePage.attr('id') === 'page_connman_service') {
662         var service_id = localStorage.getItem('connman_service_id');
663         if (service_id == undefined) return;
664         var service_object = $(jqId(service_id)).data('service-object');
665         if (service.id === service_object.id) {
666             connmanConstructServicePanel(service);
667         }
668     }
669 }
670
671 function connmanUpdateServiceButton(service) {
672     if (service.prop.State === 'ready') {
673         $(jqId(service.id)).find('div.service-action-button').find('span').text('Disconnect');
674     } else if (service.prop.State === 'idle' || service.prop.State === 'online') {
675         $(jqId(service.id)).find('div.service-action-button').find('span').text('Connect');
676     }
677 }
678
679 function connmanUpdateConnectionStatus(service) {
680     var status = 'disconnected';
681     if (service.prop.State === 'ready') {
682         $(jqId(service.id)).addClass('service-connected');
683         status = 'connected';
684     } else if (service.prop.State === 'idle' || service.prop.State === 'online') {
685         status = 'disconnected';
686         $(jqId(service.id)).removeClass('service-connected');
687     }
688
689     connmanUpdateConnectionStatusText(service, status);
690 }
691
692 function connmanUpdateConnectionStatusText(service, status) {
693     $(jqId(service.id)).find('div.service-status').text(status);
694 }
695
696 function connmanConstructServicePanel(service) {
697     var status_connected = 'No';
698
699     if (service == null) return;
700     if (service.prop.State === 'ready') status_connected = 'Yes';
701
702     $('#page_connman_service_content').html('');
703     var html = '<ul data-role="listview" id="listview_connman_service" data-inset="true" ' + 'class="service-list ui-listview">';
704     html += '<li id="connman_service_name"><h2>Name: ' + service.prop.Name + '</h2></li>';
705     html += '<li id="connman_service_type"><h2>Type: ' + service.prop.Type + '</h2></li>';
706     html += '<li id="connman_service_type"><h2>State: ' + service.prop.State + '</h2></li>';
707     if (service.prop.Type === 'ethernet' || service.prop.Type === 'wifi') {
708         if (service.prop.Type === 'wifi') {
709             html += '<li id="connman_service_bssid"><h2>SSID: ' + service.prop.BSSID + '</h2></li>';
710             html += '<li id="connman_service_encryption"><h2>Encryption: ' + service.prop.EncryptionMode + '</h2></li>';
711             html += '<li id="connman_service_strength"><h2>Signal Strength: ' + service.prop.Strength + '</h2></li>';
712         }
713         if (service.prop.State === 'ready') {
714             html += '<li id="connman_service_ip_address"><h2>IP Address: ' + service.prop.IPv4.Address + '</h2></li>';
715             html += '<li id="connman_servicel_gateway"><h2>Gateway: ' + service.prop.IPv4.Gateway + '</h2></li>';
716             html += '<li id="connman_service_netmask"><h2>Netmask: ' + service.prop.IPv4.Netmask + '</h2></li>';
717         }
718     }
719     html += '<li id="connman_service_connected"><h2>Connected: ' + status_connected + '</h2></li>';
720     html += '</ul>';
721     $('#page_connman_service_content').append(html).trigger('create');
722     $('#listview_connman_services').listview('refresh');
723
724     var html = '<ul data-role="listview" data-inset="true" class="ui-listview ui-listview-inset">';
725     html += '<li data-role="fieldcontain">';
726     html += '<label for="toggle_autoconnect" class="ui-slider">Auto Connect</label>';
727     html += '<select data-role="slider" name="toggle_autoconnect" ';
728     html += 'id="toggle_autoconnect" class="ui-slider-switch">';
729     html += '<option value="off">Off</option>';
730     html += '<option value="on">On</option>';
731     html += '</select></li></ul>';
732     $('#page_connman_service_content').append(html).trigger('create');
733
734     if (service.prop.AutoConnect) {
735         $('#toggle_autoconnect').val('on').slider('refresh');
736     } else {
737         $('#toggle_autoconnect').val('off').slider('refresh');
738     }
739
740     $('#toggle_autoconnect').change(function() {
741         if ($('#toggle_autoconnect').val() === 'on') {
742             service.setAutoConnect(true, function() {
743                 /* success */
744                 console.log('Successfully enabled autoconnect for ' + service.prop.Name);
745             }, function(e) {
746                 /* error */
747                 console.log('Cannot enable autoconnect: ' + e);
748             });
749         } else {
750             service.setAutoConnect(false, function() {
751                 /* success */
752                 console.log('Successfully disabled autoconnect for ' + service.prop.Name);
753             }, function(e) {
754                 /* error */
755                 console.log('Cannot disable autoconnect: ' + e);
756             });
757         }
758     });
759 }
760
761 function connmanUpdateServicePanel(service) {
762     var status_connected = 'No';
763
764     if (service == null) return;
765     if (service.prop.State === 'ready') status_connected = 'Yes';
766     $('#connman_service_connected').text(status_connected);
767     $('#listview_connman_service').listview('refresh');
768 }
769
770 function connmanToggleTechnology(technology_type, powered) {
771     setTimeout(function() {
772         if (powered) {
773             $('#toggle_connman_' + technology_type).val('on').slider('refresh');
774             console.log('Turn on toggle #toggle_connman_' + technology_type);
775         } else {
776             $('#toggle_connman_' + technology_type).val('off').slider('refresh');
777             console.log('Turn off toggle #toggle_connman_' + technology_type);
778         }
779     }, 1000);
780 }
781
782 function connmanConnectToService(service, passphrase, success_cb, error_cb) {
783     console.log('Connect to service: ' + service.prop.Name);
784     showSpinner(false, 'Connecting...');
785     service.connect(passphrase, function() {
786         /* success */
787         connmanSync(function() {
788             hideSpinner();
789             if (success_cb) {
790                 success_cb();
791             }
792         }, function(e) {
793             hideSpinner();
794             if (error_cb) {
795                 error_cb(e);
796             }
797         });
798     }, function(e) {
799         /* error */
800         hideSpinner();
801         if (error_cb) {
802             if (e.indexOf('Invalid arguments') >= 0) {
803                 error_cb('Password incorrect');
804             } else {
805                 error_cb(e);
806             }
807         }
808     });
809 }
810
811 function connmanGetHiddenServicePath(security_type, success_cb, error_cb) {
812     if (security_type === undefined || success_cb === undefined || error_cb === undefined) return;
813     settings.connman.scan(function(services) {
814         connmanScanInProgress = false;
815         console.log('found ' + services.length + ' connman services');
816         for (var i = 0; i < services.length; i++) {
817             var service = services[i];
818             if (service.prop.Name === undefined && service.prop.Type === 'wifi') {
819                 console.log('Hidden network matched - ' + service.id);
820                 success_cb(service.id);
821                 return;
822             }
823         }
824         error_cb('No hidden network with security: ' + security_type);
825     }, function(e) {
826         connmanScanInProgress = false;
827         if (error_cb) {
828             error_cb(e);
829         }
830     });
831 }