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 self.adapter().getDevice(device.address, function(dev) {
485 // console.log("getDevice ", dev);
486 self.addUpdateDevice(dev, false);
488 self.saveBluetooth();
489 if (!!self.selectedDevice() && self.selectedDevice().address === dev.address) {
490 self.selectedDevice(dev);
493 console.log ("Could not get device info:", error);
494 console.log ("removing device:", device.address);
495 self.removeDevice(device.address);
497 self.saveBluetooth();
502 * Loads the default local Bluetooth adapter.
504 * @method loadDefaultAdapter
506 Bluetooth.prototype.loadDefaultAdapter = function() {
509 if (typeof (tizen.bluetooth) !== 'undefined' && typeof (tizen.bluetooth.getDefaultAdapter) !== 'undefined') {
511 var adapter = tizen.bluetooth.getDefaultAdapter();
512 if (adapter === null) {
513 console.log('Error: Bluetooth adapter not found');
515 self.adapter(adapter);
521 console.log("Bluetooth API is not available.");
526 * Sets the listener to receivce notifications about changes of Bluetooth adapter.
528 * @method registerDefaultAdapterChangeListener
530 Bluetooth.prototype.registerDefaultAdapterChangeListener = function() {
533 if (!!self.adapter() && typeof (self.adapter().setChangeListener) !== 'undefined') {
535 self.adapter().setChangeListener({
536 onstatechanged : function(powered) {
537 console.log("Power state is changed into: " + powered);
538 self.loadDefaultAdapter();
541 self.scanning(false);
542 self.hideBluetoothLoadingSpinner();
543 hideLoadingSpinner("Scanning");
544 self.saveBluetooth();
547 onnamechanged : function(name) {
548 console.log("Name is changed to: " + name);
549 //self.loadDefaultAdapter();
551 onvisibilitychanged : function(visible) {
552 console.log("Visibility is changed into: " + visible);
553 //self.loadDefaultAdapter();
560 console.log("adapter.setChangeListener API not available.");
565 * 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.
569 Bluetooth.prototype.show = function(successCallback) {
572 console.log("Bluetooth show called");
573 self.isVisible(true);
574 var subpanelModel = {
575 textTitle : "SETTINGS",
576 textSubtitle : "BLUETOOTH",
578 action : function() {
579 self.isVisible(false);
580 Settings.renderSettingsView();
584 var loadBluetoothDevicesUI = function() {
585 if (!$("#bluetoothDevicesList").length) {
586 var bluetoothDevicesList = '<div id="bluetoothDevicesList" data-bind="template: { name: \'';
587 bluetoothDevicesList += templateName;
588 bluetoothDevicesList += '\', foreach: Settings.Bluetooth.devices }"></div>';
589 $(bluetoothDevicesList).prependTo($('.' + bluetoothContent));
592 button += '<div class="buttonsArea">';
593 button += '<div id="bluetoothRefreshButton" class="toggleButton bluetoothRefreshButton" data-bind="click: Settings.Bluetooth.toogleScanDevices, style: { display: Settings.Bluetooth.adapter().powered ? \'block\' : \'none\' }">';
594 button += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
595 button += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: Settings.Bluetooth.scanning() ? \'STOP\' : \'SCAN\'"></div>';
598 $(button).appendTo($('.' + bluetoothContent));
600 button = '<div id="wifiPowerButton" class="toggleButton subPanelToggleButton subPanelToggleButtonWide" data-bind="with: Settings.Bluetooth.adapter, click: Settings.Bluetooth.togglePower">';
601 button += '<div class="bgColorThemeTransparent boxShadowInset toggleButtonBackground"></div>';
602 button += '<div class="fontColorNormal fontSizeMedium fontWeightBold toggleButtonText" data-bind="text: powered ? \'TURN OFF\' : \'TURN ON\'"></div>';
604 $(button).appendTo($('.tabsTopSubPanel'));
605 ko.applyBindings(window.Settings);
608 if (!!self.lastSync()) {
609 diff = new Date().getTime() - self.lastSync();
611 if (!self.scanning() && (diff === -1 || diff > 600000 || !self.devices().length)) {
615 if (self.scanning()) {
616 self.showBluetoothLoadingSpinner();
621 var bluetoothContent = "bluetoothContent";
622 var templateName = "template-bluetooth";
623 Settings.domElement.tabs("clearContent");
624 Settings.domElement.tabs("changeContentClass", bluetoothContent);
625 Settings.domElement.tabs("subpanelContentTemplateCompile", subpanelModel, function() {
626 loadTemplate(Settings.SETTINGS_TEMPLATES_PATH, templateName, loadBluetoothDevicesUI);
628 if (!Settings.domElement.find(".bluetoothPINCode").length) {
629 var pinCode = "<div class='bluetoothPINCode fontSizeXXSmall fontWeightBold fontColorTheme'>Default bluetooth pincode / passkey: 123456</div>";
630 $(pinCode).appendTo(Settings.domElement);
635 * Shows small loading spinner in header during active discovery session.
637 * @method showBluetoothLoadingSpinner
639 Bluetooth.prototype.showBluetoothLoadingSpinner = function() {
641 if ($(".bluetoothContent").length) {
642 if (!$("#loadingSpinnerBluetooth").length) {
644 spinner += '<div id="loadingSpinnerBluetooth" class="loadingSpinnerBluetooth loading-container loading-container-small">';
645 spinner += '<div class="loading loading-small"></div>';
647 $(spinner).appendTo($(".tabsTopSubPanel"));
649 $("#loadingSpinnerBluetooth").show();
654 * Hides small loading spinner in header.
656 * @method hideBluetoothLoadingSpinner
658 Bluetooth.prototype.hideBluetoothLoadingSpinner = function() {
660 if ($("#loadingSpinnerBluetooth").length) {
661 $("#loadingSpinnerBluetooth").hide();
666 * 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.
669 * @param showSpinner? {Boolean} Indicates if full screen loading spinner should be visible during active discovery session.
671 Bluetooth.prototype.scan = function(showSpinner) {
674 showSpinner = typeof (showSpinner) === 'undefined' ? true : showSpinner;
675 if (self.scanning()) {
676 self.showBluetoothLoadingSpinner();
678 showLoadingSpinner("Scanning");
682 //self.loadDefaultAdapter();
683 self.stopScan(function(err) {
684 if (!!self.adapter() && self.adapter().powered) {
685 console.log("Bluetooth: discoverDevices called");
687 showLoadingSpinner("Scanning");
689 self.showBluetoothLoadingSpinner();
691 self.lastSync(new Date().getTime());
693 self.adapter().getKnownDevices(function(devices) {
694 if (devices.length) {
695 for ( var i = 0; i < devices.length; ++i) {
696 console.log("Known device name: " + devices[i].name + ", Address: " + devices[i].address);
697 self.addUpdateDevice(devices[i]);
700 self.saveBluetooth();
701 hideLoadingSpinner("Scanning");
704 console.log("Could not get known devices: ", error);
707 var discoveryTimeout = null;
708 var clearDiscoveryTimeout = function() {
709 if (!!discoveryTimeout) {
710 clearTimeout(discoveryTimeout);
711 discoveryTimeout = null;
714 var errorDiscoveryCallback = function(error) {
715 console.log('An error occured while discovering bluetooth devices: ', error);
716 self.stopScan(function() {
717 clearDiscoveryTimeout();
718 self.scanning(false);
719 hideLoadingSpinner("Scanning");
720 self.hideBluetoothLoadingSpinner();
724 // Workaround due to https://bugs.tizen.org/jira/browse/TIVI-2565
725 discoveryTimeout = setTimeout(function() {
726 errorDiscoveryCallback("Bluetooth adapter busy.");
729 self.adapter().discoverDevices({
730 onstarted : function() {
731 console.log("Device discovery started.");
733 ondevicefound : function(device) {
734 console.log("Found device - name: " + device.name + ", Address: " + device.address);
735 clearDiscoveryTimeout();
736 self.addUpdateDevice(device);
738 self.saveBluetooth();
739 hideLoadingSpinner("Scanning");
741 ondevicedisappeared : function(address) {
742 console.log("Device disappeared: " + address);
743 clearDiscoveryTimeout();
744 self.removeDevice(address);
746 self.saveBluetooth();
748 onfinished : function(devices) {
749 console.log("Device discovery finished.");
750 clearDiscoveryTimeout();
751 for ( var i = 0; i < devices.length; ++i) {
752 console.log("Name: " + devices[i].name + ", Address: " + devices[i].address);
753 self.addUpdateDevice(devices[i]);
756 self.scanning(false);
757 hideLoadingSpinner("Scanning");
758 self.hideBluetoothLoadingSpinner();
761 errorDiscoveryCallback(err);
768 * Stops an active device discovery session.
771 * @param callback {Function(error)} Callback function to be invoked when stopping ends.
772 * @param showSpinner? {Boolean} Indicates if full screen spinner should be visible during stopping process.
774 Bluetooth.prototype.stopScan = function(callback, showSpinner) {
777 //self.loadDefaultAdapter();
778 if (!!self.adapter() && self.adapter().powered) {
779 showSpinner = typeof (showSpinner) === 'undefined' ? false : showSpinner;
781 showLoadingSpinner("Stopping");
783 self.adapter().stopDiscovery(function() {
784 console.log("Stop discovery success.");
785 self.scanning(false);
786 hideLoadingSpinner("Stopping");
787 self.hideBluetoothLoadingSpinner();
792 console.log("An error occured while stopping bluetooth discovery.", err);
793 hideLoadingSpinner("Stopping");
806 * Adds or updates remote Bluetooth device in list of nearby and known remote Bluetooth devices.
808 * @method addUpdateDevice
809 * @param device {Object} Object representing Bluetooth device to be added or updated.
810 * @param addDevice? {Boolean} Indicates if device should be added if it is not yet in the list of available and known Bluetooth devices.
812 Bluetooth.prototype.addUpdateDevice = function(device, addDevice) {
815 // console.log("Device to be added/updated");
816 // console.log(device);
818 if (!!device && !!self.devices()) {
819 var deviceExists = false;
820 for ( var i = 0; i < self.devices().length; ++i) {
821 var dev = self.devices()[i];
822 if (dev.address === device.address) {
823 self.devices()[i] = device;
828 addDevice = typeof (addDevice) === 'undefined' ? true : addDevice;
829 if (!deviceExists && addDevice) {
830 self.devices.push(device);
836 * Removes remote Bluetooth device from list of nearby and known remote Bluetooth devices.
838 * @method removeDevice
839 * @param deviceAddress {String} Bluetooth device hardware address to be removed.
841 Bluetooth.prototype.removeDevice = function(deviceAddress) {
844 if (!!deviceAddress && deviceAddress !== "" && !!self.devices() && self.devices().length) {
845 self.devices.remove(function(device) {
846 return device.address === deviceAddress;
852 * Clears list of nearby and known remote Bluetooth devices.
854 * @method clearDevices
856 Bluetooth.prototype.clearDevices = function() {
858 this.devices.removeAll();
863 * Sorts nearby and known remote Bluetooth devices by attribute representing the bond state of remote device with the local device (paired firts).
865 * @method sortDevices
867 Bluetooth.prototype.sortDevices = function() {
870 if (!!self.devices() && self.devices().length) {
871 self.devices.sort(function(left, right) {
872 return left.isBonded === right.isBonded ? 0 : left.isBonded ? -1 : 1;
878 * 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.
880 * @method saveBluetooth
882 Bluetooth.prototype.saveBluetooth = function() {
884 var devs = ko.toJS(this.devices().slice(0));
886 // clean bluetooth device objects from properties that do not need to be saved
887 for ( var i = 0; i < devs.length; ++i) {
888 delete devs[i].connectToServiceByUUID;
889 delete devs[i].uuids;
890 var deviceClass = devs[i].deviceClass;
891 delete devs[i].deviceClass;
892 devs[i].deviceClass = {};
894 devs[i].deviceClass.major = deviceClass.major;
895 devs[i].deviceClass.minor = deviceClass.minor;
898 var newBluetoothConf = {
900 lastSync : this.lastSync()
902 var savedBluetoothConf = Configuration.get("bluetooth");
903 var savedBluetoothConfStr = JSON.stringify(savedBluetoothConf);
904 //console.log(savedBluetoothConfStr);
905 var newBluetoothConfStr = JSON.stringify(newBluetoothConf);
906 //console.log(newBluetoothConfStr);
907 //console.log("SAME: ", savedBluetoothConfStr == newBluetoothConfStr ? "YES" : "NO");
908 if (!savedBluetoothConf || newBluetoothConfStr !== savedBluetoothConfStr) {
909 Configuration.set("bluetooth", newBluetoothConf, false);
914 * Loads Bluetooth device hardware address of phone marked as selected for incoming calls.
916 * @method loadSelectedRemoteDevice
918 Bluetooth.prototype.loadSelectedRemoteDevice = function() {
921 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.getSelectedRemoteDevice) !== 'undefined') {
923 tizen.phone.getSelectedRemoteDevice(function(selectedRemoteDev) {
924 console.log("selected remote device: ", selectedRemoteDev);
925 if (!!selectedRemoteDev && selectedRemoteDev !== "") {
926 self.selectedPhone(selectedRemoteDev);
928 self.selectedPhone(null);
932 console.log("An error occured while loading selected remote device ", err);
933 self.selectedPhone(null);
939 * Marks a given remote Bluetooth device as selected for incoming calls.
941 * @method selectRemoteDevice
942 * @param device {Object} Object representing remote Bluetooth device to be selected.
944 Bluetooth.prototype.selectRemoteDevice = function(device) {
947 console.log("selectRemoteDevice called", device);
948 if (!!device && !!device.address && !!device.deviceClass && device.deviceClass.major === tizen.bluetooth.deviceMajor.PHONE && typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.selectRemoteDevice) !== 'undefined') {
949 showLoadingSpinner("Selecting");
951 tizen.phone.selectRemoteDevice(device.address);
953 console.log("An error occured while selecting remote device ", err);
956 console.log("tizen.phone.selectRemoteDevice API not available or supplied device is not valid.");
961 * Unmarks previously selected remote Bluetooth device for incoming calls.
963 * @method unselectRemoteDevice
965 Bluetooth.prototype.unselectRemoteDevice = function() {
968 console.log("unselectRemoteDevice called");
969 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.unselectRemoteDevice) !== 'undefined') {
971 tizen.phone.unselectRemoteDevice();
973 console.log("An error occured while unselecting remote device ", err);
976 console.log("tizen.phone.unselectRemoteDevice API not available.");
981 * Sets the listener to receivce notifications when new remote Bluetooth device was marked as selected for incoming calls.
982 * @method registerSelectedRemoteDeviceChangeListener
984 Bluetooth.prototype.registerSelectedRemoteDeviceChangeListener = function() {
988 if (typeof (tizen.phone) !== 'undefined' && typeof (tizen.phone.addRemoteDeviceSelectedListener) !== 'undefined') {
990 tizen.phone.addRemoteDeviceSelectedListener(function(result) {
991 console.log("addRemoteDeviceSelectedListener: ", result);
992 if (!!result && !!result.error) {
993 console.log("An error occured while selecting remote device: ", result.error);
994 self.selectedPhone(null);
995 } else if (!!result && !!result.value && result.value.toString().trim() !== "") {
996 self.selectedPhone(result.value.toString().trim());
998 self.selectedPhone(null);
1000 self._restartRefreshDevicesInterval();
1001 hideLoadingSpinner("Selecting");
1004 console.log("An error occured while registering remote device selected listener ", err);
1007 console.log("tizen.phone.addRemoteDeviceSelectedListener API not available.");
1012 * Reloads list of nearby and knwon remote Bluetooth devices and default local Bluetooth adapter.
1014 * @method refreshDevices
1016 Bluetooth.prototype.refreshDevices = function() {
1019 console.log("refreshDevices called");
1020 var devices = self.devices().slice(0);
1021 self.clearDevices();
1022 //self.loadDefaultAdapter();
1023 if (!!self.adapter() && self.adapter().powered) {
1024 self.devices(devices);
1027 function updateDeviceInfo() {
1028 for ( var i = 0; i < self.devices().length; ++i) {
1029 var dev = self.devices()[i];
1030 if (!!self.selectedDevice() && self.selectedDevice().address === dev.address) {
1031 self.selectedDevice(dev);
1033 if (dev.toString().indexOf("BluetoothDevice") === -1) {
1034 self.getDevice(dev);
1038 self.saveBluetooth();
1041 if (self.devices().length) {
1042 self.adapter().getKnownDevices(function(devs) {
1044 for ( var i = 0; i < devs.length; ++i) {
1045 self.addUpdateDevice(devs[i], false);
1049 }, function(error) {
1050 console.log("Could not get known devices: ", error);
1058 Bluetooth.prototype._restartRefreshDevicesInterval = function() {
1061 self._clearRefreshDevicesInterval();
1062 self.refreshDevices();
1063 self._setRefreshDevicesInterval();