1 /* global Configuration, Settings, hideLoadingSpinner, showLoadingSpinner, ko, $, loadTemplate */
4 * Bluetooth class provides list view of nearby and known Bluetooth devices, detailed information view about Bluetooth device,
5 * functionality to pair and unpair remote Bluetooth device, mark phone as selected for incoming calls, contacts and
6 * call history, turn on and off Bluetooth adapter.
8 * This class requires following components:
10 * * {{#crossLink "Tabs"}}{{/crossLink}} component
11 * * {{#crossLink "Configuration"}}{{/crossLink}} component
12 * * {{#crossLink "Settings"}}{{/crossLink}} component
18 var Bluetooth = function() {
22 self.loadDefaultAdapter();
23 self.registerDefaultAdapterChangeListener();
25 self.loadBluetoothConfig();
26 Configuration.addUpdateListener(function() {
27 self.loadBluetoothConfig();
30 self.registerSelectedRemoteDeviceChangeListener();
31 self.loadSelectedRemoteDevice();
33 self._setRefreshDevicesInterval();
35 Settings.domElement.on('eventClick_hidePage', function() {
36 self.isVisible(false);
38 function stopScanning() {
39 console.log("attempts: ", attempts);
42 self.stopScan(function(err) {
44 setTimeout(function() {
54 Settings.domElement.on('eventClick_showPage', function() {
55 if ($(".bluetoothContent").length || $(".deviceInfoContent").length) {
58 if (!!self.lastSync()) {
59 diff = new Date().getTime() - self.lastSync();
61 if (!self.scanning() && (diff === -1 || diff > 600000 || !self.devices().length)) {
65 if (self.scanning()) {
66 self.showBluetoothLoadingSpinner();
72 * Sets the state of a Bluetooth adapter to on or off by sending a request to Bluetooth hardware to change the power state.
73 * After Bluetooth adapter is enabled it starts scanning for nearby and known Bluetooth devices.
77 this.togglePower = function() {
78 console.log("Bluetooth: toggle power called.");
79 //self.loadDefaultAdapter();
80 if (!!self.adapter() && !self.togglePowerLocked()) {
81 self.togglePowerLocked(true);
82 if (self.adapter().powered) {
83 showLoadingSpinner("Turning off");
84 self.stopScan(function(err) {
85 console.log('setPowered(false) called');
86 self.adapter().setPowered(false, function() {
87 console.log('Successfully disable bluetooth subsystem.');
88 self.togglePowerLocked(false);
89 //self.loadDefaultAdapter();
90 hideLoadingSpinner("Turning off");
92 var error = "An error occured while turning bluetooth off.";
93 console.log(error, err);
95 self.togglePowerLocked(false);
96 //self.loadDefaultAdapter();
97 hideLoadingSpinner("Turning off");
101 showLoadingSpinner("Turning on");
102 self.stopScan(function(err) {
103 console.log('setPowered(true) called');
104 self.adapter().setPowered(true, function() {
105 console.log('Successfully enable bluetooth subsystem');
106 self.togglePowerLocked(false);
107 //self.loadDefaultAdapter();
109 self.scanning(false);
110 setTimeout(function() {
111 hideLoadingSpinner("Turning on");
115 var error = "An error occured while turning bluetooth on.";
116 console.log(error, err);
118 self.togglePowerLocked(false);
119 //self.loadDefaultAdapter();
120 hideLoadingSpinner("Turning on");
128 * Creates a bond with a remote device by initiating the bonding process with peer device using the given device's MAC address or destroys
129 * the bond with a remote device (initiates the process of removing the specified address from the
130 * list of bonded devices).
133 * @param device {Object} Object representing remote Bluetooth device to be paired or unpaired according to current device state.
135 this.togglePair = function(device) {
136 console.log("Bluetooth: toggle connection called.");
139 //self.loadDefaultAdapter();
140 self._clearRefreshDevicesInterval();
141 if (!device.isBonded) {
142 console.log('bluetooth pair to device: ' + device.address);
143 showLoadingSpinner("Pairing");
144 self.adapter().createBonding(device.address, function() {
145 console.log('bluetooth paired with ' + device.address);
146 self._restartRefreshDevicesInterval();
147 hideLoadingSpinner("Pairing");
149 console.log('Error: bluetooth pair failed: ', e);
150 self._restartRefreshDevicesInterval();
151 //alert("An error occured while pairing with " + device.name);
152 hideLoadingSpinner("Pairing");
155 console.log('Bluetooth disconnect from device: ' + device.address);
156 showLoadingSpinner("Unpairing");
157 self.adapter().destroyBonding(device.address, function() {
158 console.log('bluetooth unpaired from ' + device.address);
159 self._restartRefreshDevicesInterval();
160 hideLoadingSpinner("Unpairing");
162 console.log('Error: bluetooth unpairing failed: ' + e);
163 self._restartRefreshDevicesInterval();
164 //alert("An error occured while unpairing from " + device.name);
165 hideLoadingSpinner("Unpairing");
172 * Starts discovering nearby and known remote Bluetooth devices or stops an active discovery session.
174 * @method toogleScanDevices
176 this.toogleScanDevices = function() {
177 console.log("Bluetooth: toggle scan devices called.");
178 if (self.scanning()) {
179 console.log("Bluetooth: stop scan called.");
180 self.stopScan(function(err) {
182 alert("An error occured while stopping bluetooth discovery.");
186 console.log("Bluetooth: scan called.");
193 * Shows more information about given remote Bluetooth device (like name, address, device class, bond, trusted, connection state) in a new view.
194 * That in addition allows to mark phone as selected for incoming calls and pair/unpair remote
197 * @method openDeviceDetails
198 * @param device {Object} Object representing remote Bluetooth device to be showed in detailed information view.
200 this.openDeviceDetails = function(device) {
201 console.log("Bluetooth: open device details called: ", device);
202 self.selectedDevice(null);
204 self.selectedDevice(device);
205 var subpanelModel = {
206 textTitle : "DEVICE INFO",
207 textSubtitle : device.name.toUpperCase(),
209 action : function() {
210 console.log("bluetooth openDeviceDetails");
211 Settings.openSetting(Settings.selectedSetting);
215 var createDeviceInfoElement = function(key, value, deviceInfoContent) {
216 var deviceInfoElement = '<div class="wifiNetworkInfoElement fontSizeLarge fontWeightBold fontColorNormal">';
217 deviceInfoElement += '<span>';
218 deviceInfoElement += key;
219 deviceInfoElement += ": ";
220 deviceInfoElement += '</span>';
221 deviceInfoElement += '<span data-bind="text:' + value + '">';
222 deviceInfoElement += '</span>';
223 deviceInfoElement += '</div>';
224 return deviceInfoElement;
227 var loadDeviceInfoUI = function() {
228 if (!$("#bluetoothDeviceInfoBox").length) {
230 button += '<div id="wifiAutoConnectButton" class="toggleButton subPanelToggleButton subPanelToggleButtonWide" data-bind="with: Settings.Bluetooth.selectedDevice, click: Settings.Bluetooth.toggleSelectionOfSelectedDevice, style: { display: Settings.Bluetooth.isSelectedDeviceSelectable() ? \'block\' : \'none\'}">';
231 button += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
232 button += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: \'SELECTED\', css: { fontColorSelected: Settings.Bluetooth.isDeviceSelected($data) }"></div>';
234 $(button).appendTo($('.tabsTopSubPanel'));
236 var deviceInfo = '<div id="bluetoothDeviceInfoBox" data-bind="with: Settings.Bluetooth.selectedDevice">';
237 deviceInfo += createDeviceInfoElement("Device name", "name");
238 deviceInfo += createDeviceInfoElement("Device address", "address");
239 deviceInfo += createDeviceInfoElement("Device class", "Settings.Bluetooth.getDeviceClassStr(deviceClass)");
240 deviceInfo += createDeviceInfoElement("Paired", "isBonded ? 'Yes' : 'No'");
241 deviceInfo += createDeviceInfoElement("Connected", "isConnected ? 'Yes' : 'No'");
242 deviceInfo += createDeviceInfoElement("Trusted", "isTrusted ? 'Yes' : 'No'");
243 deviceInfo += '<div id="networkConnectButton" class="toggleButton networkConnectButton" data-bind="click: Settings.Bluetooth.togglePair">';
244 deviceInfo += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
245 deviceInfo += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: isBonded ? \'UNPAIR\' : \'PAIR\'"></div>';
246 deviceInfo += '</div>';
247 deviceInfo += '</div>';
248 $(deviceInfo).appendTo($('.' + deviceInfoContent));
249 ko.applyBindings(window.Settings);
253 var deviceInfoContent = "deviceInfoContent";
254 Settings.domElement.tabs("clearContent");
255 Settings.domElement.tabs("changeContentClass", deviceInfoContent);
256 Settings.domElement.tabs("subpanelContentTemplateCompile", subpanelModel, loadDeviceInfoUI);
261 * Returns major Bluetooth device class in human readable form.
263 * @method getDeviceClassStr
264 * @param deviceClass {Object} Object representing Bluetooth device class information.
265 * @return {String} Major Bluetooth device class.
267 this.getDeviceClassStr = function(deviceClass) {
269 switch (deviceClass.major) {
270 case tizen.bluetooth.deviceMajor.MISC:
273 case tizen.bluetooth.deviceMajor.COMPUTER:
274 classStr = "COMPUTER";
276 case tizen.bluetooth.deviceMajor.PHONE:
279 case tizen.bluetooth.deviceMajor.NETWORK:
280 classStr = "NETWORK";
282 case tizen.bluetooth.deviceMajor.AUDIO_VIDEO:
283 classStr = "AUDIO/VIDEO";
285 case tizen.bluetooth.deviceMajor.PERIPHERAL:
286 classStr = "PERIPHERAL";
288 case tizen.bluetooth.deviceMajor.IMAGING:
289 classStr = "IMAGING";
291 case tizen.bluetooth.deviceMajor.WEARABLE:
292 classStr = "WEARABLE";
294 case tizen.bluetooth.deviceMajor.TOY:
297 case tizen.bluetooth.deviceMajor.HEALTH:
300 case tizen.bluetooth.deviceMajor.UNCATEGORIZED:
301 classStr = "UNCATEGORIZED";
304 classStr = "UNKNOWN";
311 * Tests if supplied remote Bluetooth device is marked as selected for incoming calls.
313 * @method isDeviceSelected
314 * @param device {Object} Object representing remote Bluetooth device to be checked for selection state.
315 * @return {Boolean} True if Bluetooth device is selected otherwise false.
317 this.isDeviceSelected = function(device) {
318 if (!!device && !!self.selectedPhone() && self.selectedPhone() === device.address) {
325 * Tests if remote Bluetooth device opened in detail view is selectable for incoming calls (only Bluetooth devices of class Phone can be selected).
327 * @method isSelectedDeviceSelectable
328 * @return {Boolean} True if remote Bluetooth device is selectable otherwise false.
330 this.isSelectedDeviceSelectable = function() {
331 if (!!self.selectedDevice()) {
332 if (self.isDeviceSelected(self.selectedDevice())) {
335 if (!!self.selectedDevice().isBonded && !!self.selectedDevice().address && !!self.selectedDevice().deviceClass && self.selectedDevice().deviceClass.major === tizen.bluetooth.deviceMajor.PHONE) {
343 * Marks and unmarks remote Bluetooth device opened in detail view as selected for incoming calls.
345 * @method toggleSelectionOfSelectedDevice
347 this.toggleSelectionOfSelectedDevice = function() {
348 console.log("Wifi: toggle select device called", self.selectedDevice());
349 if (self.isDeviceSelected(self.selectedDevice())) {
350 self.unselectRemoteDevice();
352 if (!!self.selectedPhone()) {
353 self.unselectRemoteDevice();
355 self.selectRemoteDevice(self.selectedDevice());
361 * Contains array of nearby and known remote Bluetooth devices.
365 * @type ko.observableArray
368 Bluetooth.prototype.devices = ko.observableArray([]);
370 * Provides access to control the device's Bluetooth adapter.
374 * @type ko.observable
377 Bluetooth.prototype.adapter = ko.observable(null);
379 * Represents remote Bluetooth device showed in detail view.
381 * @property selectedDevice
383 * @type ko.observable
386 Bluetooth.prototype.selectedDevice = ko.observable(null);
388 * Indicates if there is active discovery session for nearby and known remote Bluetooth devices.
392 * @type ko.observable
395 Bluetooth.prototype.scanning = ko.observable(false);
397 * Indicates if Bluetooth settings view is visible (in a viewport).
399 * @property isVisible
401 * @type ko.observable
404 Bluetooth.prototype.isVisible = ko.observable(false);
406 * Defines Bluetooth hardware address of phone marked as selected for incoming calls, contacts and call history.
408 * @property selectedPhone
410 * @type ko.observable
413 Bluetooth.prototype.selectedPhone = ko.observable(null);
415 * Holds information about last synchronisation of nearby and known remote Bluetooth devices with local offline storage.
419 * @type ko.observable
422 Bluetooth.prototype.lastSync = ko.observable(null);
424 * Indicates if Bluetooth power button is clickable.
426 * @property togglePowerLocked
428 * @type ko.observable
431 Bluetooth.prototype.togglePowerLocked = ko.observable(false);
433 Bluetooth.prototype._refreshDevicesInterval = null;
434 Bluetooth.prototype._setRefreshDevicesInterval = function() {
437 self._clearRefreshDevicesInterval();
438 self._refreshDevicesInterval = setInterval(function() {
439 if (!!self.adapter() && self.isVisible() && !self.scanning() && !document.webkitHidden) {
440 self.refreshDevices();
444 Bluetooth.prototype._clearRefreshDevicesInterval = function() {
447 if (!!self._refreshDevicesInterval) {
448 clearInterval(self._refreshDevicesInterval);
449 self._refreshDevicesInterval = null;
454 * Loads saved remote Bluetooth devices from local offline storage.
456 * @method loadBluetoothConfig
458 Bluetooth.prototype.loadBluetoothConfig = function() {
461 self._clearRefreshDevicesInterval();
462 var bluetooth = Configuration.get("bluetooth");
463 console.log("loaded bluetooth config: ", JSON.stringify(bluetooth));
464 //self.loadDefaultAdapter();
466 self.lastSync(bluetooth.lastSync);
467 if (!!self.adapter() && self.adapter().powered && !!bluetooth.devices) {
469 self.refreshDevices();
470 self._setRefreshDevicesInterval();
476 * Updates or adds Bluetooth device for a given device's hardware address.
479 * @param device {Object} Object representing Bluetooth device information to be updated or added.
481 Bluetooth.prototype.getDevice = function(device) {
484 if (!self.adapter()) {
485 console.log ("Device is null");
486 console.log ("removing device:", device.address);
487 self.removeDevice(device.address);
489 self.saveBluetooth();
492 self.adapter().getDevice(device.address, function(dev) {
493 // console.log("getDevice ", dev);
494 self.addUpdateDevice(dev, false);
496 self.saveBluetooth();
497 if (!!self.selectedDevice() && self.selectedDevice().address === dev.address) {
498 self.selectedDevice(dev);
501 console.log ("Could not get device info:", error);
502 console.log ("removing device:", device.address);
503 self.removeDevice(device.address);
505 self.saveBluetooth();
510 * Loads the default local Bluetooth adapter.
512 * @method loadDefaultAdapter
514 Bluetooth.prototype.loadDefaultAdapter = function() {
517 if (typeof (tizen.bluetooth) !== 'undefined' && typeof (tizen.bluetooth.getDefaultAdapter) !== 'undefined') {
519 var adapter = tizen.bluetooth.getDefaultAdapter();
520 if (adapter === null) {
521 console.log('Error: Bluetooth adapter not found');
523 self.adapter(adapter);
529 console.log("Bluetooth API is not available.");
534 * Sets the listener to receivce notifications about changes of Bluetooth adapter.
536 * @method registerDefaultAdapterChangeListener
538 Bluetooth.prototype.registerDefaultAdapterChangeListener = function() {
541 if (!!self.adapter() && typeof (self.adapter().setChangeListener) !== 'undefined') {
543 self.adapter().setChangeListener({
544 onstatechanged : function(powered) {
545 console.log("Power state is changed into: " + powered);
546 self.loadDefaultAdapter();
549 self.scanning(false);
550 self.hideBluetoothLoadingSpinner();
551 hideLoadingSpinner("Scanning");
552 self.saveBluetooth();
555 onnamechanged : function(name) {
556 console.log("Name is changed to: " + name);
557 //self.loadDefaultAdapter();
559 onvisibilitychanged : function(visible) {
560 console.log("Visibility is changed into: " + visible);
561 //self.loadDefaultAdapter();
568 console.log("adapter.setChangeListener API not available.");
573 * Shows list view of nearby and known remote Bluetooth devices and allows to trigger rediscovering, open detail view, pair on unpair selected Bluetooth device, turn on or off Bluetooth adapter.
577 Bluetooth.prototype.show = function(successCallback) {
580 console.log("Bluetooth show called");
581 self.isVisible(true);
582 var subpanelModel = {
583 textTitle : "SETTINGS",
584 textSubtitle : "BLUETOOTH",
586 action : function() {
587 self.isVisible(false);
588 Settings.renderSettingsView();
592 var loadBluetoothDevicesUI = function() {
593 if (!$("#bluetoothDevicesList").length) {
594 var bluetoothDevicesList = '<div id="bluetoothDevicesList" data-bind="template: { name: \'';
595 bluetoothDevicesList += templateName;
596 bluetoothDevicesList += '\', foreach: Settings.Bluetooth.devices }"></div>';
597 $(bluetoothDevicesList).prependTo($('.' + bluetoothContent));
600 button += '<div class="buttonsArea">';
601 button += '<div id="bluetoothRefreshButton" class="toggleButton bluetoothRefreshButton" data-bind="click: Settings.Bluetooth.toogleScanDevices, style: { display: Settings.Bluetooth.adapter().powered ? \'block\' : \'none\' }">';
602 button += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
603 button += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: Settings.Bluetooth.scanning() ? \'STOP\' : \'SCAN\'"></div>';
606 $(button).appendTo($('.' + bluetoothContent));
608 button = '<div id="wifiPowerButton" class="toggleButton subPanelToggleButton subPanelToggleButtonWide" data-bind="with: Settings.Bluetooth.adapter, click: Settings.Bluetooth.togglePower">';
609 button += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
610 button += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: powered ? \'TURN OFF\' : \'TURN ON\'"></div>';
612 $(button).appendTo($('.tabsTopSubPanel'));
613 ko.applyBindings(window.Settings);
616 if (!!self.lastSync()) {
617 diff = new Date().getTime() - self.lastSync();
619 if (!self.scanning() && (diff === -1 || diff > 600000 || !self.devices().length)) {
623 if (self.scanning()) {
624 self.showBluetoothLoadingSpinner();
629 var bluetoothContent = "bluetoothContent";
630 var templateName = "template-bluetooth";
631 Settings.domElement.tabs("clearContent");
632 Settings.domElement.tabs("changeContentClass", bluetoothContent);
633 Settings.domElement.tabs("subpanelContentTemplateCompile", subpanelModel, function() {
634 loadTemplate(Settings.SETTINGS_TEMPLATES_PATH, templateName, loadBluetoothDevicesUI);
636 if (!Settings.domElement.find(".bluetoothPINCode").length) {
637 var pinCode = "<div class='bluetoothPINCode fontSizeXXSmall fontWeightBold fontColorTheme'>Default bluetooth pincode / passkey: 123456</div>";
638 $(pinCode).appendTo(Settings.domElement);
643 * Shows small loading spinner in header during active discovery session.
645 * @method showBluetoothLoadingSpinner
647 Bluetooth.prototype.showBluetoothLoadingSpinner = function() {
649 if ($(".bluetoothContent").length) {
650 if (!$("#loadingSpinnerBluetooth").length) {
652 spinner += '<div id="loadingSpinnerBluetooth" class="loadingSpinnerBluetooth loading-container loading-container-small">';
653 spinner += '<div class="loading loading-small"></div>';
655 $(spinner).appendTo($(".tabsTopSubPanel"));
657 $("#loadingSpinnerBluetooth").show();
662 * Hides small loading spinner in header.
664 * @method hideBluetoothLoadingSpinner
666 Bluetooth.prototype.hideBluetoothLoadingSpinner = function() {
668 if ($("#loadingSpinnerBluetooth").length) {
669 $("#loadingSpinnerBluetooth").hide();
674 * Discovers nearby Bluetooth devices if any, that is, devices within proximity to the local device and gets all the known devices that have information stored in the local Bluetooth adapter.
677 * @param showSpinner? {Boolean} Indicates if full screen loading spinner should be visible during active discovery session.
679 Bluetooth.prototype.scan = function(showSpinner) {
682 showSpinner = typeof (showSpinner) === 'undefined' ? true : showSpinner;
683 if (self.scanning()) {
684 self.showBluetoothLoadingSpinner();
686 showLoadingSpinner("Scanning");
690 //self.loadDefaultAdapter();
691 self.stopScan(function(err) {
692 if (!!self.adapter() && self.adapter().powered) {
693 console.log("Bluetooth: discoverDevices called");
695 showLoadingSpinner("Scanning");
697 self.showBluetoothLoadingSpinner();
699 self.lastSync(new Date().getTime());
701 self.adapter().getKnownDevices(function(devices) {
702 if (devices.length) {
703 for ( var i = 0; i < devices.length; ++i) {
704 console.log("Known device name: " + devices[i].name + ", Address: " + devices[i].address);
705 self.addUpdateDevice(devices[i]);
708 self.saveBluetooth();
709 hideLoadingSpinner("Scanning");
712 console.log("Could not get known devices: ", error);
715 var discoveryTimeout = null;
716 var clearDiscoveryTimeout = function() {
717 if (!!discoveryTimeout) {
718 clearTimeout(discoveryTimeout);
719 discoveryTimeout = null;
722 var errorDiscoveryCallback = function(error) {
723 console.log('An error occured while discovering bluetooth devices: ', error);
724 self.stopScan(function() {
725 clearDiscoveryTimeout();
726 self.scanning(false);
727 hideLoadingSpinner("Scanning");
728 self.hideBluetoothLoadingSpinner();
732 // Workaround due to https://bugs.tizen.org/jira/browse/TIVI-2565
733 discoveryTimeout = setTimeout(function() {
734 errorDiscoveryCallback("Bluetooth adapter busy.");
737 self.adapter().discoverDevices({
738 onstarted : function() {
739 console.log("Device discovery started.");
741 ondevicefound : function(device) {
742 console.log("Found device - name: " + device.name + ", Address: " + device.address);
743 clearDiscoveryTimeout();
744 self.addUpdateDevice(device);
746 self.saveBluetooth();
747 hideLoadingSpinner("Scanning");
749 ondevicedisappeared : function(address) {
750 console.log("Device disappeared: " + address);
751 clearDiscoveryTimeout();
752 self.removeDevice(address);
754 self.saveBluetooth();
756 onfinished : function(devices) {
757 console.log("Device discovery finished.");
758 clearDiscoveryTimeout();
759 for ( var i = 0; i < devices.length; ++i) {
760 console.log("Name: " + devices[i].name + ", Address: " + devices[i].address);
761 self.addUpdateDevice(devices[i]);
764 self.scanning(false);
765 hideLoadingSpinner("Scanning");
766 self.hideBluetoothLoadingSpinner();
769 errorDiscoveryCallback(err);
776 * Stops an active device discovery session.
779 * @param callback {Function(error)} Callback function to be invoked when stopping ends.
780 * @param showSpinner? {Boolean} Indicates if full screen spinner should be visible during stopping process.
782 Bluetooth.prototype.stopScan = function(callback, showSpinner) {
785 //self.loadDefaultAdapter();
786 if (!!self.adapter() && self.adapter().powered) {
787 showSpinner = typeof (showSpinner) === 'undefined' ? false : showSpinner;
789 showLoadingSpinner("Stopping");
791 self.adapter().stopDiscovery(function() {
792 console.log("Stop discovery success.");
793 self.scanning(false);
794 hideLoadingSpinner("Stopping");
795 self.hideBluetoothLoadingSpinner();
800 console.log("An error occured while stopping bluetooth discovery.", err);
801 hideLoadingSpinner("Stopping");
814 * Adds or updates remote Bluetooth device in list of nearby and known remote Bluetooth devices.
816 * @method addUpdateDevice
817 * @param device {Object} Object representing Bluetooth device to be added or updated.
818 * @param addDevice? {Boolean} Indicates if device should be added if it is not yet in the list of available and known Bluetooth devices.
820 Bluetooth.prototype.addUpdateDevice = function(device, addDevice) {
823 // console.log("Device to be added/updated");
824 // console.log(device);
826 if (!!device && !!self.devices()) {
827 var deviceExists = false;
828 for ( var i = 0; i < self.devices().length; ++i) {
829 var dev = self.devices()[i];
830 if (dev.address === device.address) {
831 self.devices()[i] = device;
836 addDevice = typeof (addDevice) === 'undefined' ? true : addDevice;
837 if (!deviceExists && addDevice) {
838 self.devices.push(device);
844 * Removes remote Bluetooth device from list of nearby and known remote Bluetooth devices.
846 * @method removeDevice
847 * @param deviceAddress {String} Bluetooth device hardware address to be removed.
849 Bluetooth.prototype.removeDevice = function(deviceAddress) {
852 if (!!deviceAddress && deviceAddress !== "" && !!self.devices() && self.devices().length) {
853 self.devices.remove(function(device) {
854 return device.address === deviceAddress;
860 * Clears list of nearby and known remote Bluetooth devices.
862 * @method clearDevices
864 Bluetooth.prototype.clearDevices = function() {
866 this.devices.removeAll();
871 * Sorts nearby and known remote Bluetooth devices by attribute representing the bond state of remote device with the local device (paired firts).
873 * @method sortDevices
875 Bluetooth.prototype.sortDevices = function() {
878 if (!!self.devices() && self.devices().length) {
879 self.devices.sort(function(left, right) {
880 return left.isBonded === right.isBonded ? 0 : left.isBonded ? -1 : 1;
886 * Saves Bluetooth adapter power state and nearby and known remote Bluetooth devices to local offline storage in order to keep same list of devices accross all the applications.
888 * @method saveBluetooth
890 Bluetooth.prototype.saveBluetooth = function() {
892 var devs = ko.toJS(this.devices().slice(0));
894 // clean bluetooth device objects from properties that do not need to be saved
895 for ( var i = 0; i < devs.length; ++i) {
896 delete devs[i].connectToServiceByUUID;
897 delete devs[i].uuids;
898 var deviceClass = devs[i].deviceClass;
899 delete devs[i].deviceClass;
900 devs[i].deviceClass = {};
902 devs[i].deviceClass.major = deviceClass.major;
903 devs[i].deviceClass.minor = deviceClass.minor;
906 var newBluetoothConf = {
908 lastSync : this.lastSync()
910 var savedBluetoothConf = Configuration.get("bluetooth");
911 var savedBluetoothConfStr = JSON.stringify(savedBluetoothConf);
912 //console.log(savedBluetoothConfStr);
913 var newBluetoothConfStr = JSON.stringify(newBluetoothConf);
914 //console.log(newBluetoothConfStr);
915 //console.log("SAME: ", savedBluetoothConfStr == newBluetoothConfStr ? "YES" : "NO");
916 if (!savedBluetoothConf || newBluetoothConfStr !== savedBluetoothConfStr) {
917 Configuration.set("bluetooth", newBluetoothConf, false);
922 * Loads Bluetooth device hardware address of phone marked as selected for incoming calls.
924 * @method loadSelectedRemoteDevice
926 Bluetooth.prototype.loadSelectedRemoteDevice = function() {
929 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.getSelectedRemoteDevice) !== 'undefined') {
931 tizen.phone.getSelectedRemoteDevice(function(selectedRemoteDev) {
932 console.log("selected remote device: ", selectedRemoteDev);
933 if (!!selectedRemoteDev && selectedRemoteDev !== "") {
934 self.selectedPhone(selectedRemoteDev);
936 self.selectedPhone(null);
940 console.log("An error occured while loading selected remote device ", err);
941 self.selectedPhone(null);
947 * Marks a given remote Bluetooth device as selected for incoming calls.
949 * @method selectRemoteDevice
950 * @param device {Object} Object representing remote Bluetooth device to be selected.
952 Bluetooth.prototype.selectRemoteDevice = function(device) {
955 console.log("selectRemoteDevice called", device);
956 if (!!device && !!device.address && !!device.deviceClass && device.deviceClass.major === tizen.bluetooth.deviceMajor.PHONE && typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.selectRemoteDevice) !== 'undefined') {
957 showLoadingSpinner("Selecting");
959 tizen.phone.selectRemoteDevice(device.address);
961 console.log("An error occured while selecting remote device ", err);
964 console.log("tizen.phone.selectRemoteDevice API not available or supplied device is not valid.");
969 * Unmarks previously selected remote Bluetooth device for incoming calls.
971 * @method unselectRemoteDevice
973 Bluetooth.prototype.unselectRemoteDevice = function() {
976 console.log("unselectRemoteDevice called");
977 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.unselectRemoteDevice) !== 'undefined') {
979 tizen.phone.unselectRemoteDevice();
981 console.log("An error occured while unselecting remote device ", err);
984 console.log("tizen.phone.unselectRemoteDevice API not available.");
989 * Sets the listener to receivce notifications when new remote Bluetooth device was marked as selected for incoming calls.
990 * @method registerSelectedRemoteDeviceChangeListener
992 Bluetooth.prototype.registerSelectedRemoteDeviceChangeListener = function() {
996 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.addRemoteDeviceSelectedListener) !== 'undefined') {
998 tizen.phone.addRemoteDeviceSelectedListener(function(result) {
999 console.log("addRemoteDeviceSelectedListener: ", result);
1000 if (!!result && !!result.error) {
1001 console.log("An error occured while selecting remote device: ", result.error);
1002 self.selectedPhone(null);
1003 } else if (!!result && !!result.value && result.value.toString().trim() !== "") {
1004 self.selectedPhone(result.value.toString().trim());
1006 self.selectedPhone(null);
1008 self._restartRefreshDevicesInterval();
1009 hideLoadingSpinner("Selecting");
1012 console.log("An error occured while registering remote device selected listener ", err);
1015 console.log("tizen.phone.addRemoteDeviceSelectedListener API not available.");
1020 * Reloads list of nearby and knwon remote Bluetooth devices and default local Bluetooth adapter.
1022 * @method refreshDevices
1024 Bluetooth.prototype.refreshDevices = function() {
1027 console.log("refreshDevices called");
1028 var devices = self.devices().slice(0);
1029 self.clearDevices();
1030 //self.loadDefaultAdapter();
1031 if (!!self.adapter() && self.adapter().powered) {
1032 self.devices(devices);
1035 function updateDeviceInfo() {
1036 for ( var i = 0; i < self.devices().length; ++i) {
1037 var dev = self.devices()[i];
1038 if (!!self.selectedDevice() && self.selectedDevice().address === dev.address) {
1039 self.selectedDevice(dev);
1041 if (dev.toString().indexOf("BluetoothDevice") === -1) {
1042 self.getDevice(dev);
1046 self.saveBluetooth();
1049 if (self.devices().length) {
1050 self.adapter().getKnownDevices(function(devs) {
1052 for ( var i = 0; i < devs.length; ++i) {
1053 self.addUpdateDevice(devs[i], false);
1057 }, function(error) {
1058 console.log("Could not get known devices: ", error);
1066 Bluetooth.prototype._restartRefreshDevicesInterval = function() {
1069 self._clearRefreshDevicesInterval();
1070 self.refreshDevices();
1071 self._setRefreshDevicesInterval();