| OLD | NEW | 
|---|
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> | 
| 2 <script src="../resources/testharness.js"></script> | 2 <script src="../resources/testharness.js"></script> | 
| 3 <script src="../resources/testharness-helpers.js"></script> | 3 <script src="../resources/testharness-helpers.js"></script> | 
| 4 <script src="../resources/testharnessreport.js"></script> | 4 <script src="../resources/testharnessreport.js"></script> | 
| 5 <script src="resources/bluetooth-helpers.js"></script> | 5 <script src="resources/bluetooth-helpers.js"></script> | 
| 6 <script> | 6 <script> | 
| 7 'use strict'; | 7 'use strict'; | 
| 8 | 8 | 
| 9 test(t => { assert_true(window.testRunner instanceof Object); t.done(); }, | 9 test(t => { assert_true(window.testRunner instanceof Object); t.done(); }, | 
| 10      'window.testRunner is required for the following tests.'); | 10      'window.testRunner is required for the following tests.'); | 
| 11 | 11 | 
| 12 promise_test(() => { | 12 promise_test(() => { | 
| 13   testRunner.setBluetoothMockDataSet('FailStartDiscoveryAdapter'); | 13   testRunner.setBluetoothManualChooser(true); | 
| 14   testRunner.setBluetoothManualChooser(); |  | 
| 15   let requestDevicePromise = | 14   let requestDevicePromise = | 
| 16       requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}); | 15       setBluetoothFakeAdapter('FailStartDiscoveryAdapter') | 
|  | 16         .then(() => requestDeviceWithKeyDown({ | 
|  | 17           filters: [{services: ['generic_access']}]})); | 
| 17   return getBluetoothManualChooserEvents(3) | 18   return getBluetoothManualChooserEvents(3) | 
| 18     .then(events => { | 19     .then(events => { | 
| 19       assert_array_equals(events, | 20       assert_array_equals(events, | 
| 20                           ['chooser-opened(file://)', | 21                           ['chooser-opened(file://)', | 
| 21                            'discovering', | 22                            'discovering', | 
| 22                            'discovery-failed-to-start'], | 23                            'discovery-failed-to-start'], | 
| 23                           events); | 24                           events); | 
| 24       testRunner.sendBluetoothManualChooserEvent('cancelled', ''); | 25       testRunner.sendBluetoothManualChooserEvent('cancelled', ''); | 
| 25       return assert_promise_rejects_with_message( | 26       return assert_promise_rejects_with_message( | 
| 26         requestDevicePromise, | 27         requestDevicePromise, | 
| 27         new DOMException('User cancelled the requestDevice() chooser.', | 28         new DOMException('User cancelled the requestDevice() chooser.', | 
| 28                          'NotFoundError'), | 29                          'NotFoundError'), | 
| 29         'The adapter failed to start a discovery session.'); | 30         'The adapter failed to start a discovery session.'); | 
| 30     }); | 31     }); | 
| 31 }, 'Discovery session fails to start.'); | 32 }, 'Discovery session fails to start.'); | 
| 32 | 33 | 
| 33 promise_test(() => { | 34 promise_test(() => { | 
| 34   testRunner.setBluetoothMockDataSet('NotPresentAdapter'); | 35   return setBluetoothFakeAdapter('NotPresentAdapter') | 
| 35   return assert_promise_rejects_with_message( | 36     .then(() => assert_promise_rejects_with_message( | 
| 36     requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}), | 37       requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}), | 
| 37     new DOMException('Bluetooth adapter not available.', 'NotFoundError'), | 38       new DOMException('Bluetooth adapter not available.', 'NotFoundError'), | 
| 38     'Bluetooth adapter is not present.'); | 39       'Bluetooth adapter is not present.')); | 
| 39 }, 'Reject with NotFoundError if the adapter is not present.'); | 40 }, 'Reject with NotFoundError if the adapter is not present.'); | 
| 40 | 41 | 
| 41 promise_test(() => { | 42 promise_test(() => { | 
| 42   testRunner.setBluetoothMockDataSet('NotPoweredAdapter'); | 43   testRunner.setBluetoothManualChooser(true); | 
| 43   testRunner.setBluetoothManualChooser(); |  | 
| 44   let requestDevicePromise = | 44   let requestDevicePromise = | 
| 45       requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}); | 45     setBluetoothFakeAdapter('NotPoweredAdapter') | 
|  | 46       .then(() => requestDeviceWithKeyDown({ | 
|  | 47         filters: [{services: ['generic_access']}]})); | 
| 46   return getBluetoothManualChooserEvents(2) | 48   return getBluetoothManualChooserEvents(2) | 
| 47     .then(events => { | 49     .then(events => { | 
| 48       assert_array_equals(events, | 50       assert_array_equals(events, | 
| 49                           ['chooser-opened(file://)', | 51                           ['chooser-opened(file://)', | 
| 50                            'adapter-disabled'], | 52                            'adapter-disabled'], | 
| 51                           events); | 53                           events); | 
| 52       testRunner.sendBluetoothManualChooserEvent('cancelled', ''); | 54       testRunner.sendBluetoothManualChooserEvent('cancelled', ''); | 
| 53       return assert_promise_rejects_with_message( | 55       return assert_promise_rejects_with_message( | 
| 54         requestDevicePromise, | 56         requestDevicePromise, | 
| 55         new DOMException('User cancelled the requestDevice() chooser.', | 57         new DOMException('User cancelled the requestDevice() chooser.', | 
| 56                          'NotFoundError'), | 58                          'NotFoundError'), | 
| 57         'Bluetooth adapter is not powered.'); | 59         'Bluetooth adapter is not powered.'); | 
| 58     }); | 60     }); | 
| 59 }, 'Reject with NotFoundError if the adapter is off.'); | 61 }, 'Reject with NotFoundError if the adapter is off.'); | 
| 60 | 62 | 
| 61 promise_test(() => { | 63 promise_test(() => { | 
| 62   testRunner.setBluetoothMockDataSet('EmptyAdapter'); | 64   return setBluetoothFakeAdapter('EmptyAdapter') | 
| 63   return assert_promise_rejects_with_message( | 65     .then(() => assert_promise_rejects_with_message( | 
| 64     requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}), | 66       requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}), | 
| 65     new DOMException('User cancelled the requestDevice() chooser.', | 67       new DOMException('User cancelled the requestDevice() chooser.', | 
| 66                      'NotFoundError'), | 68                        'NotFoundError'), | 
| 67     'No Bluetooth devices in range.'); | 69       'No Bluetooth devices in range.')); | 
| 68 }, 'Reject with NotFoundError if there are no devices around.'); | 70 }, 'Reject with NotFoundError if there are no devices around.'); | 
| 69 | 71 | 
| 70 promise_test(() => { | 72 promise_test(() => { | 
| 71   testRunner.setBluetoothMockDataSet('HeartRateAdapter'); | 73   return setBluetoothFakeAdapter('HeartRateAdapter') | 
| 72   return Promise.all([ | 74     .then(() => Promise.all([ | 
| 73     requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}), | 75       requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}), | 
| 74     requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}), | 76       requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}), | 
| 75     requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]}) | 77       requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]}) | 
| 76   ]).then(devices => { | 78   ])).then(devices => { | 
| 77     devices.forEach(device => { | 79     devices.forEach(device => { | 
| 78       assert_equals(device.constructor.name, 'BluetoothDevice'); | 80       assert_equals(device.constructor.name, 'BluetoothDevice'); | 
| 79     }); | 81     }); | 
| 80   }); | 82   }); | 
| 81 }, 'Mock will resolve.'); | 83 }, 'Mock will resolve.'); | 
| 82 | 84 | 
| 83 promise_test(() => { | 85 promise_test(() => { | 
| 84   testRunner.setBluetoothMockDataSet('HeartRateAdapter'); | 86   return setBluetoothFakeAdapter('HeartRateAdapter') | 
| 85   return assert_promise_rejects( | 87     .then(() => assert_promise_rejects( | 
| 86     navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}), | 88       navigator.bluetooth.requestDevice({ | 
| 87     new DOMException('', 'SecurityError')); | 89         filters: [{services: ['heart_rate']}]}), | 
|  | 90       new DOMException('', 'SecurityError'))); | 
| 88 }, 'Requires a user gesture.'); | 91 }, 'Requires a user gesture.'); | 
| 89 | 92 | 
| 90 promise_test(() => { | 93 promise_test(() => { | 
| 91   testRunner.setBluetoothMockDataSet('HeartRateAdapter'); | 94   return setBluetoothFakeAdapter('HeartRateAdapter') | 
| 92   return callWithKeyDown(() => { | 95     .then(() => callWithKeyDown(() => { | 
| 93     var first = navigator.bluetooth.requestDevice({filters: [{services: ['heart_
     rate']}]}); | 96       var first = navigator.bluetooth.requestDevice({ | 
| 94     var second = navigator.bluetooth.requestDevice({filters: [{services: ['heart
     _rate']}]}); | 97         filters: [{services: ['heart_rate']}]}); | 
| 95     return Promise.all([ | 98       var second = navigator.bluetooth.requestDevice({ | 
| 96       first.then(device => assert_equals(device.constructor.name, 'BluetoothDevi
     ce')), | 99         filters: [{services: ['heart_rate']}]}); | 
| 97       assert_promise_rejects(second, new DOMException('', 'SecurityError')), | 100       return Promise.all([ | 
| 98     ]); | 101         first.then(device => assert_equals( | 
| 99   }); | 102           device.constructor.name, 'BluetoothDevice')), | 
|  | 103         assert_promise_rejects(second, new DOMException('', 'SecurityError')), | 
|  | 104       ]); | 
|  | 105     })); | 
| 100 }, 'Consumes a user gesture.'); | 106 }, 'Consumes a user gesture.'); | 
| 101 | 107 | 
| 102 promise_test(() => { | 108 promise_test(() => { | 
| 103   testRunner.setBluetoothMockDataSet('HeartRateAdapter'); | 109   return setBluetoothFakeAdapter('HeartRateAdapter') | 
| 104   return Promise.all([ | 110     .then(() => Promise.all([ | 
| 105     requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}), | 111       requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}), | 
| 106     requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}), | 112       requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}), | 
| 107     requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]}) | 113       requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]}) | 
| 108   ]).then(devices => { | 114   ])).then(devices => { | 
| 109     // requestDevice should return the same object if it was created | 115     // requestDevice should return the same object if it was created | 
| 110     // earlier. https://crbug.com/495270 | 116     // earlier. https://crbug.com/495270 | 
| 111     // TODO(ortuno): Change to assert_equals. | 117     // TODO(ortuno): Change to assert_equals. | 
| 112     assert_not_equals(devices[0], devices[1]); | 118     assert_not_equals(devices[0], devices[1]); | 
| 113     assert_not_equals(devices[1], devices[2]); | 119     assert_not_equals(devices[1], devices[2]); | 
| 114   }); | 120   }); | 
| 115 }, 'Returned device should always be the same.'); | 121 }, 'Returned device should always be the same.'); | 
| 116 | 122 | 
| 117 promise_test(() => { | 123 promise_test(() => { | 
| 118   testRunner.setBluetoothMockDataSet('ScanFilterCheckingAdapter'); |  | 
| 119   // The work of this test is done in the ScanFilterCheckingAdapter. It asserts | 124   // The work of this test is done in the ScanFilterCheckingAdapter. It asserts | 
| 120   // that this requestDevice() call tells the platform to scan for only devices | 125   // that this requestDevice() call tells the platform to scan for only devices | 
| 121   // that include the Battery, Glucose, or Heart Rate services. | 126   // that include the Battery, Glucose, or Heart Rate services. | 
| 122   return requestDeviceWithKeyDown({ | 127   return setBluetoothFakeAdapter('ScanFilterCheckingAdapter') | 
| 123     filters: [ | 128     .then(() => requestDeviceWithKeyDown({ | 
| 124       {services: ['battery_service']}, | 129       filters: [{services: ['battery_service']}, | 
| 125       {services: ['glucose', 'heart_rate']} | 130                 {services: ['glucose', 'heart_rate']}], | 
| 126     ], | 131       // The optionalServices shouldn't affect the platform's scan. | 
| 127     // The optionalServices shouldn't affect the platform's scan. | 132       optionalServices: ['generic_access'] | 
| 128     optionalServices: ['generic_access'] | 133     })); | 
| 129   }); |  | 
| 130 }, 'Filters restrict the platform\'s Bluetooth scan.'); | 134 }, 'Filters restrict the platform\'s Bluetooth scan.'); | 
| 131 | 135 | 
| 132 promise_test(() => { | 136 promise_test(() => { | 
| 133   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); | 137   testRunner.setBluetoothManualChooser(true); | 
| 134   testRunner.setBluetoothManualChooser(); | 138   let requestDevicePromise = | 
| 135   let requestDevicePromise = requestDeviceWithKeyDown({ | 139     setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
| 136     filters: [{services: ['glucose']}, | 140       .then(() => requestDeviceWithKeyDown({ | 
| 137               {services: ['heart_rate']}] | 141         filters: [{services: ['glucose']}, | 
| 138   }); | 142                   {services: ['heart_rate']}] | 
|  | 143       })); | 
| 139   return getBluetoothManualChooserEvents(5) | 144   return getBluetoothManualChooserEvents(5) | 
| 140     .then(events => { | 145     .then(events => { | 
| 141       assert_equals(events.length, 5, events); | 146       assert_equals(events.length, 5, events); | 
| 142       assert_equals(events[0], 'chooser-opened(file://)', 'events[0]'); | 147       assert_equals(events[0], 'chooser-opened(file://)', 'events[0]'); | 
| 143       let idsByName = new AddDeviceEventSet(); | 148       let idsByName = new AddDeviceEventSet(); | 
| 144       for (let addedDevice of [events[1], events[2]]) { | 149       for (let addedDevice of [events[1], events[2]]) { | 
| 145         idsByName.assert_add_device_event(addedDevice); | 150         idsByName.assert_add_device_event(addedDevice); | 
| 146       } | 151       } | 
| 147       assert_true(idsByName.has('Heart Rate Device')); | 152       assert_true(idsByName.has('Heart Rate Device')); | 
| 148       assert_true(idsByName.has('Glucose Device')); | 153       assert_true(idsByName.has('Glucose Device')); | 
| 149       assert_equals(events[3], 'discovering'); | 154       assert_equals(events[3], 'discovering'); | 
| 150       assert_equals(events[4], 'discovery-idle'); | 155       assert_equals(events[4], 'discovery-idle'); | 
| 151       testRunner.sendBluetoothManualChooserEvent('selected', | 156       testRunner.sendBluetoothManualChooserEvent('selected', | 
| 152                                                  idsByName.get('Glucose Device')
     ); | 157                                                  idsByName.get('Glucose Device')
     ); | 
| 153       return requestDevicePromise; | 158       return requestDevicePromise; | 
| 154     }).then(device => assert_equals(device.name, 'Glucose Device')); | 159     }).then(device => assert_equals(device.name, 'Glucose Device')); | 
| 155 }, 'The chooser includes all devices.'); | 160 }, 'The chooser includes all devices.'); | 
| 156 | 161 | 
| 157 promise_test(() => { | 162 promise_test(() => { | 
| 158   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); | 163   return setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
| 159   return requestDeviceWithKeyDown({filters: [{services: ['glucose']}]}) | 164     .then(() => requestDeviceWithKeyDown({ | 
|  | 165       filters: [{services: ['glucose']}]})) | 
| 160     .then(device => assert_equals(device.name, 'Glucose Device')); | 166     .then(device => assert_equals(device.name, 'Glucose Device')); | 
| 161 }, 'Simple filter selects matching device.'); | 167 }, 'Simple filter selects matching device.'); | 
| 162 | 168 | 
| 163 promise_test(() => { | 169 promise_test(() => { | 
| 164   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); | 170   return setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
| 165   return requestDeviceWithKeyDown({ | 171     .then(() => requestDeviceWithKeyDown({ | 
| 166     filters: [{services: ['glucose', 'tx_power']}] | 172       filters: [{services: ['glucose', 'tx_power']}] | 
| 167   }).then(device => assert_equals(device.name, 'Glucose Device')); | 173     })).then(device => assert_equals(device.name, 'Glucose Device')); | 
| 168 }, 'Filter with 2 services returns a matching device.'); | 174 }, 'Filter with 2 services returns a matching device.'); | 
| 169 | 175 | 
| 170 promise_test(() => { | 176 promise_test(() => { | 
| 171   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); | 177   return setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
| 172   return requestDeviceWithKeyDown({ | 178     .then(() => requestDeviceWithKeyDown({ | 
| 173     filters: [{services: ['battery_service']}, | 179       filters: [{services: ['battery_service']}, | 
| 174               {services: ['heart_rate']}] | 180                 {services: ['heart_rate']}] | 
| 175   }).then(device => assert_equals(device.name, 'Heart Rate Device')); | 181     })).then(device => assert_equals(device.name, 'Heart Rate Device')); | 
| 176 }, 'An extra filter doesn\'t prevent matching.'); | 182 }, 'An extra filter doesn\'t prevent matching.'); | 
| 177 | 183 | 
| 178 promise_test(() => { | 184 promise_test(() => { | 
| 179   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); | 185   return setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
| 180   return requestDeviceWithKeyDown({filters: [{services: ['glucose']}], | 186     .then(() => requestDeviceWithKeyDown({ | 
| 181                                    optionalServices: ['tx_power']}) | 187       filters: [{services: ['glucose']}], | 
|  | 188       optionalServices: ['tx_power']})) | 
| 182     .then(device => { | 189     .then(device => { | 
| 183       assert_equals(device.uuids.length, 2); | 190       assert_equals(device.uuids.length, 2); | 
| 184       assert_in_array(BluetoothUUID.getService('glucose'), device.uuids); | 191       assert_in_array(BluetoothUUID.getService('glucose'), device.uuids); | 
| 185       assert_in_array(BluetoothUUID.getService('tx_power'), device.uuids); | 192       assert_in_array(BluetoothUUID.getService('tx_power'), device.uuids); | 
| 186     }); | 193     }); | 
| 187 }, 'We should only see UUID\'s that we\'ve been given permission for.') | 194 }, 'We should only see UUID\'s that we\'ve been given permission for.') | 
| 188 | 195 | 
| 189 | 196 | 
| 190 promise_test(() => { | 197 promise_test(() => { | 
| 191   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter'); |  | 
| 192   // Both devices support the Generic Access service, but things need to | 198   // Both devices support the Generic Access service, but things need to | 
| 193   // support both services to pass the filter, and neither has a Battery | 199   // support both services to pass the filter, and neither has a Battery | 
| 194   // service. | 200   // service. | 
| 195   return assert_promise_rejects(requestDeviceWithKeyDown({ | 201   return setBluetoothFakeAdapter('GlucoseHeartRateAdapter') | 
|  | 202     .then(() => assert_promise_rejects( | 
|  | 203       requestDeviceWithKeyDown({ | 
| 196     filters: [{services: ['heart_rate', 'battery_service']}] | 204     filters: [{services: ['heart_rate', 'battery_service']}] | 
| 197   }), new DOMException('', 'NotFoundError')); | 205       }), new DOMException('', 'NotFoundError'))); | 
| 198 }, 'Too-strict filters do prevent matching.'); | 206 }, 'Too-strict filters do prevent matching.'); | 
| 199 | 207 | 
| 200 promise_test(() => { | 208 promise_test(() => { | 
| 201   testRunner.setBluetoothMockDataSet('SecondDiscoveryFindsHeartRateAdapter'); | 209   testRunner.setBluetoothManualChooser(true); | 
| 202   testRunner.setBluetoothManualChooser(); |  | 
| 203 | 210 | 
| 204   // Open the chooser, looking for a Heart Rate device. | 211   // Open the chooser, looking for a Heart Rate device. | 
| 205   let requestDevicePromise = requestDeviceWithKeyDown({ | 212   let requestDevicePromise = | 
| 206     filters: [{services: ['heart_rate']}] | 213     setBluetoothFakeAdapter('SecondDiscoveryFindsHeartRateAdapter') | 
| 207   }); | 214       .then(() => requestDeviceWithKeyDown({ | 
|  | 215         filters: [{services: ['heart_rate']}] | 
|  | 216       })); | 
| 208 | 217 | 
| 209   // The adapter finds nothing, so we just see discovery start and stop. | 218   // The adapter finds nothing, so we just see discovery start and stop. | 
| 210   return getBluetoothManualChooserEvents(3).then(events => { | 219   return getBluetoothManualChooserEvents(3).then(events => { | 
| 211     assert_array_equals(events, | 220     assert_array_equals(events, | 
| 212                         ['chooser-opened(file://)', | 221                         ['chooser-opened(file://)', | 
| 213                          'discovering', | 222                          'discovering', | 
| 214                          'discovery-idle', | 223                          'discovery-idle', | 
| 215                         ]); | 224                         ]); | 
| 216 | 225 | 
| 217     // On the second discovery, the adapter finds the Heart Rate device. | 226     // On the second discovery, the adapter finds the Heart Rate device. | 
| 218     testRunner.sendBluetoothManualChooserEvent('rescan', ''); | 227     testRunner.sendBluetoothManualChooserEvent('rescan', ''); | 
| 219     return getBluetoothManualChooserEvents(3); | 228     return getBluetoothManualChooserEvents(3); | 
| 220   }).then(events => { | 229   }).then(events => { | 
| 221     assert_equals(events.length, 3, events); | 230     assert_equals(events.length, 3, events); | 
| 222     assert_equals(events[0], 'discovering', 'events[0]'); | 231     assert_equals(events[0], 'discovering', 'events[0]'); | 
| 223     let idsByName = new AddDeviceEventSet(); | 232     let idsByName = new AddDeviceEventSet(); | 
| 224     idsByName.assert_add_device_event(events[1]); | 233     idsByName.assert_add_device_event(events[1]); | 
| 225     assert_true(idsByName.has('Heart Rate Device')); | 234     assert_true(idsByName.has('Heart Rate Device')); | 
| 226     assert_equals(events[2], 'discovery-idle'); | 235     assert_equals(events[2], 'discovery-idle'); | 
| 227 | 236 | 
| 228     // Select it and let the test complete. | 237     // Select it and let the test complete. | 
| 229     testRunner.sendBluetoothManualChooserEvent('selected', | 238     testRunner.sendBluetoothManualChooserEvent('selected', | 
| 230                                                idsByName.get('Heart Rate Device'
     )); | 239                                                idsByName.get('Heart Rate Device'
     )); | 
| 231     return requestDevicePromise; | 240     return requestDevicePromise; | 
| 232   }).then(device => assert_equals(device.name, 'Heart Rate Device')); | 241   }).then(device => assert_equals(device.name, 'Heart Rate Device')); | 
| 233 }, 'The chooser can restart the BT scan.'); | 242 }, 'The chooser can restart the BT scan.'); | 
| 234 </script> | 243 </script> | 
| OLD | NEW | 
|---|