/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 'use strict'; var BluetoothTransfer = { bannerContainer: null, pairList: { index: [] }, _deviceStorage: navigator.getDeviceStorage('sdcard'), _debug: false, get transferStatusList() { delete this.transferStatusList; return this.transferStatusList = document.getElementById('bluetooth-transfer-status-list'); }, get banner() { delete this.banner; return this.banner = document.getElementById('system-banner'); }, init: function bt_init() { // Bind message handler for transferring file callback navigator.mozSetMessageHandler('bluetooth-opp-receiving-file-confirmation', this.onReceivingFileConfirmation.bind(this) ); // Listen to 'bluetooth-opp-transfer-start' from bluetooth.js window.addEventListener('bluetooth-opp-transfer-start', this.onUpdateProgress.bind(this, 'start') ); navigator.mozSetMessageHandler('bluetooth-opp-update-progress', this.onUpdateProgress.bind(this, 'progress') ); // Listen to 'bluetooth-opp-transfer-complete' from bluetooth.js window.addEventListener('bluetooth-opp-transfer-complete', this.onTransferComplete.bind(this) ); this.bannerContainer = this.banner.firstElementChild; }, getDeviceName: function bt_getDeviceName(address) { var _ = navigator.mozL10n.get; var length = this.pairList.index.length; for (var i = 0; i < length; i++) { if (this.pairList.index[i].address == address) return this.pairList.index[i].name; } return _('unknown-device'); }, getPairedDevice: function bt_getPairedDevice(callback) { var adapter = Bluetooth.getAdapter(); if (adapter == null) { var msg = 'Cannot get Bluetooth adapter.'; this.debug(msg); return; } var self = this; var req = adapter.getPairedDevices(); req.onsuccess = function bt_getPairedSuccess() { self.pairList.index = req.result; var length = self.pairList.index.length; if (length == 0) { var msg = 'There is no paired device! Please pair your bluetooth device first.'; self.debug(msg); return; } if (callback) { callback(); } }; req.onerror = function() { var msg = 'Can not get paired devices from adapter.'; self.debug(msg); }; }, debug: function bt_debug(msg) { if (!this._debug) return; console.log('[System Bluetooth Transfer]: ' + msg); }, humanizeSize: function bt_humanizeSize(bytes) { var _ = navigator.mozL10n.get; var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var size, e; if (bytes) { e = Math.floor(Math.log(bytes) / Math.log(1024)); size = (bytes / Math.pow(1024, e)).toFixed(2); } else { e = 0; size = '0.00'; } return _('fileSize', { size: size, unit: _('byteUnit-' + units[e]) }); }, onReceivingFileConfirmation: function bt_onReceivingFileConfirmation(evt) { // Prompt appears when a transfer request from a paired device is received. var _ = navigator.mozL10n.get; var fileSize = evt.fileLength; var self = this; var icon = 'style/bluetooth_transfer/images/icon_bluetooth.png'; // Check storage is available or not before the prompt. this.checkStorageSpace(fileSize, function checkStorageSpaceComplete(isStorageAvailable, errorMessage) { if (isStorageAvailable) { NotificationHelper.send(_('notification-fileTransfer-title'), _('notification-fileTransfer-description'), icon, function() { UtilityTray.hide(); self.showReceivePrompt(evt); }); } else { self.showStorageUnavaliablePrompt(errorMessage); } }); }, showReceivePrompt: function bt_showReceivePrompt(evt) { var _ = navigator.mozL10n.get; var address = evt.address; var fileName = evt.fileName; var fileSize = this.humanizeSize(evt.fileLength); var cancel = { title: _('deny'), callback: this.declineReceive.bind(this, address) }; var confirm = { title: _('transfer'), callback: this.acceptReceive.bind(this, address) }; var deviceName = ''; var self = this; this.getPairedDevice(function getPairedDeviceComplete() { deviceName = self.getDeviceName(address); CustomDialog.show(_('acceptFileTransfer'), _('wantToReceiveFile', { deviceName: deviceName, fileName: fileName, fileSize: fileSize }), cancel, confirm); }); }, declineReceive: function bt_declineReceive(address) { CustomDialog.hide(); var adapter = Bluetooth.getAdapter(); if (adapter != null) { adapter.confirmReceivingFile(address, false); } else { var msg = 'Cannot get adapter from system Bluetooth monitor.'; this.debug(msg); } }, acceptReceive: function bt_acceptReceive(address, fileSize) { CustomDialog.hide(); var adapter = Bluetooth.getAdapter(); if (adapter != null) { adapter.confirmReceivingFile(address, true); } else { var msg = 'Cannot get adapter from system Bluetooth monitor.'; this.debug(msg); } }, showStorageUnavaliablePrompt: function bt_showStorageUnavaliablePrompt(msg) { var _ = navigator.mozL10n.get; var confirm = { title: _('confirm'), callback: function() { CustomDialog.hide(); } }; var body = msg; CustomDialog.show(_('cannotReceiveFile'), body, confirm); }, checkStorageSpace: function bt_checkStorageSpace(fileSize, callback) { if (!callback) return; var _ = navigator.mozL10n.get; var storage = this._deviceStorage; var availreq = storage.available(); availreq.onsuccess = function(e) { switch (availreq.result) { case 'available': // skip down to the code below break; case 'unavailable': callback(false, _('sdcard-not-exist')); return; case 'shared': callback(false, _('sdcard-in-use')); return; default: callback(false, _('unknown-error')); return; } // If we get here, then the sdcard is available, so we need to find out // if there is enough free space on it var freereq = storage.freeSpace(); freereq.onsuccess = function() { if (freereq.result >= fileSize) callback(true, ''); else callback(false, _('sdcard-no-space2')); }; freereq.onerror = function() { callback(false, _('cannotGetStorageState')); }; }; availreq.onerror = function(e) { callback(false, _('cannotGetStorageState')); }; }, onUpdateProgress: function bt_onUpdateProgress(mode, evt) { switch (mode) { case 'start': var transferInfo = evt.detail.transferInfo; this.initProgress(transferInfo); break; case 'progress': var address = evt.address; var processedLength = evt.processedLength; var fileLength = evt.fileLength; var progress = 0; if (fileLength == 0) { //XXX: May need to handle unknow progress } else if (processedLength > fileLength) { // According Bluetooth spec., // the processed length is a referenced value only. // XXX: If processed length is bigger than file length, // show an unknown progress } else { progress = processedLength / fileLength; } this.updateProgress(progress, evt); break; } }, initProgress: function bt_initProgress(evt) { var _ = navigator.mozL10n.get; // Create progress dynamically in notification center var address = evt.address; var transferMode = (evt.received == true) ? _('bluetooth-receiving-progress') : _('bluetooth-sending-progress'); var content = '' + '