Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
717 lines
23 KiB
JavaScript
717 lines
23 KiB
JavaScript
/* API Summary:
|
|
stopSendingFile(in DOMString aDeviceAddress);
|
|
confirmReceivingFile(in DOMString aDeviceAddress, in bool aConfirmation); */
|
|
'use strict';
|
|
/* global MimeMapper, Service, LazyLoader,
|
|
MozActivity, NotificationHelper, UtilityTray */
|
|
/* exported BluetoothTransfer */
|
|
(function(exports) {
|
|
var BluetoothTransfer = {
|
|
name: 'BluetoothTransfer',
|
|
// The first-in-first-out queue maintain each scheduled sending task.
|
|
// Each element is a object for scheduled sending tasks.
|
|
_sendingFilesQueue: [],
|
|
|
|
_bindOnCancelTransferTask: null,
|
|
|
|
/**
|
|
* Debug message.
|
|
*
|
|
* @private
|
|
* @type {Boolean} turn on/off the console log
|
|
*/
|
|
onDebug: false,
|
|
|
|
bluetoothIcon: 'style/bluetooth_transfer/images/icon_bluetooth.png',
|
|
|
|
get _deviceStorage() {
|
|
return navigator.getDeviceStorage('sdcard');
|
|
},
|
|
|
|
get transferStatusList() {
|
|
var transferStatusList =
|
|
document.getElementById('bluetooth-transfer-status-list');
|
|
delete this.transferStatusList;
|
|
this.transferStatusList = transferStatusList;
|
|
return transferStatusList;
|
|
},
|
|
|
|
/**
|
|
* Initialize BluetoothTransfer module.
|
|
*
|
|
* Service request handleSystemMessageNotification is used to filter
|
|
* and relay BluetoothTransfer related notifications handle event after
|
|
* reboot. Now only `_onTransferComplete` method generate notifications
|
|
* that need to be handled after reboot.
|
|
*
|
|
* @public
|
|
*/
|
|
start: function bt_start() {
|
|
// Bind message handler for sending files from Bluetooth app
|
|
window.addEventListener('iac-bluetoothTransfercomms',
|
|
this._onFilesSending.bind(this)
|
|
);
|
|
|
|
// 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));
|
|
|
|
window.addEventListener('bluetooth-sendfile-via-handover',
|
|
this.sendFileViaHandover.bind(this));
|
|
|
|
Service.registerState('isSendFileQueueEmpty', this);
|
|
Service.registerState('isFileTransferInProgress', this);
|
|
Service.request('handleSystemMessageNotification',
|
|
'BluetoothTransfer', this);
|
|
|
|
this._bindOnCancelTransferTask = this.onCancelTransferTask.bind(this);
|
|
},
|
|
|
|
getDeviceName: function bt_getDeviceName(address) {
|
|
return new Promise((resolve) => {
|
|
var adapter = Service.query('Bluetooth.getAdapter');
|
|
if (adapter === null) {
|
|
var msg = 'Since cannot get Bluetooth adapter, ' +
|
|
'resolve with an unknown device.';
|
|
this.debug(msg);
|
|
navigator.mozL10n.formatValue('unknown-device').then(resolve);
|
|
return;
|
|
}
|
|
// Service Class Name: OBEXObjectPush, UUID: 0x1105
|
|
// Specification: Object Push Profile (OPP)
|
|
// NOTE: Used as both Service Class Identifier and Profile.
|
|
// Allowed Usage: Service Class/Profile
|
|
// https://www.bluetooth.org/en-us/specification/assigned-numbers/
|
|
// service-discovery
|
|
var serviceUuid = '0x1105';
|
|
var req = adapter.getConnectedDevices(serviceUuid);
|
|
req.onsuccess = () => {
|
|
if (req.result) {
|
|
this.debug('got connectedList');
|
|
var connectedList = req.result;
|
|
var length = connectedList.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (connectedList[i].address == address) {
|
|
resolve(connectedList[i].name);
|
|
}
|
|
}
|
|
} else {
|
|
navigator.mozL10n.formatValue('unknown-device').then(resolve);
|
|
}
|
|
};
|
|
req.onerror = () => {
|
|
var msg = 'Can not check is device connected from adapter.';
|
|
this.debug(msg);
|
|
navigator.mozL10n.formatValue('unknown-device').then(resolve);
|
|
};
|
|
});
|
|
},
|
|
|
|
debug: function bt_debug(msg) {
|
|
if (!this.onDebug) {
|
|
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])
|
|
});
|
|
},
|
|
|
|
_onFilesSending: function bt__onFilesSending(evt) {
|
|
// Notify user that we are sending files
|
|
var icon = 'style/bluetooth_transfer/images/transfer.png';
|
|
|
|
NotificationHelper.send('transferHasStartedTitle', {
|
|
'bodyL10n': 'transferHasStartedDescription',
|
|
'icon': icon
|
|
}).then(function(notification) {
|
|
notification.addEventListener('click',
|
|
UtilityTray.show.bind(UtilityTray));
|
|
});
|
|
|
|
// Push sending files request in queue
|
|
var sendingFilesSchedule = evt.detail;
|
|
this._sendingFilesQueue.push(sendingFilesSchedule);
|
|
var msg = 'push sending files request in queue, queued length = ' +
|
|
this._sendingFilesQueue.length;
|
|
this.debug(msg);
|
|
},
|
|
|
|
onReceivingFileConfirmation: function bt_onReceivingFileConfirmation(evt) {
|
|
if (Service.query('NfcHandoverManager.isHandoverInProgress')) {
|
|
// Bypassing confirm dialog while incoming file transfer via
|
|
// NFC Handover
|
|
this.debug('Incoming file via NFC Handover. Bypassing confirm dialog');
|
|
window.dispatchEvent(new CustomEvent('nfc-transfer-started'));
|
|
this.acceptReceive(evt);
|
|
return;
|
|
}
|
|
|
|
// Prompt appears when a transfer request from a paired device is
|
|
// received.
|
|
this.debug('show receive confirm dialog');
|
|
var address = evt.address;
|
|
|
|
this.getDeviceName(address).then((deviceName) => {
|
|
var title = {
|
|
id: 'transfer-confirmation-title',
|
|
args: { deviceName: deviceName }
|
|
};
|
|
|
|
NotificationHelper.send(title, {
|
|
'bodyL10n': 'transfer-confirmation-desc',
|
|
'icon': this.bluetoothIcon,
|
|
'mozbehavior': {noclear: true}
|
|
}).then((notification) => {
|
|
notification.addEventListener('click', () => {
|
|
UtilityTray.hide();
|
|
this.showReceivePrompt(evt);
|
|
});
|
|
});
|
|
});
|
|
},
|
|
|
|
showReceivePrompt: function bt_showReceivePrompt(evt) {
|
|
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, evt),
|
|
recommend: true
|
|
};
|
|
|
|
this.getDeviceName(address).then(function(deviceName) {
|
|
Service.request('showCustomDialog', 'acceptFileTransfer',
|
|
{
|
|
id: 'want-to-receive-file',
|
|
args: {
|
|
deviceName: deviceName,
|
|
fileName: fileName,
|
|
fileSize: fileSize
|
|
}
|
|
},
|
|
cancel,
|
|
confirm
|
|
);
|
|
});
|
|
},
|
|
|
|
declineReceive: function bt_declineReceive(address) {
|
|
Service.request('hideCustomDialog');
|
|
var adapter = Service.query('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(evt) {
|
|
this.debug('accepted the file transfer');
|
|
Service.request('hideCustomDialog');
|
|
// Check storage is available or not before confirm receiving file
|
|
var address = evt.address;
|
|
var fileSize = evt.fileLength;
|
|
this.checkStorageSpace(fileSize,
|
|
(isStorageAvailable, errorMessage) => {
|
|
var option = (isStorageAvailable) ? true : false;
|
|
var adapter = Service.query('Bluetooth.getAdapter');
|
|
if (adapter) {
|
|
adapter.confirmReceivingFile(address, option);
|
|
} else {
|
|
var msg = 'Cannot get adapter from system Bluetooth monitor.';
|
|
this.debug(msg);
|
|
}
|
|
// Storage is not available, then pop out a prompt with the reason
|
|
if (!isStorageAvailable) {
|
|
this.showStorageUnavaliablePrompt(errorMessage);
|
|
}
|
|
});
|
|
},
|
|
|
|
showStorageUnavaliablePrompt:
|
|
function bt_showStorageUnavaliablePrompt(msg) {
|
|
var confirm = {
|
|
title: 'confirm',
|
|
callback: function() {
|
|
Service.request('hideCustomDialog');
|
|
}
|
|
};
|
|
|
|
Service.request('showCustomDialog',
|
|
'cannotReceiveFile', msg, confirm, null);
|
|
},
|
|
|
|
checkStorageSpace: function bt_checkStorageSpace(fileSize, callback) {
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
|
|
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-exist2');
|
|
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');
|
|
};
|
|
},
|
|
|
|
isSendFileQueueEmpty: function() {
|
|
return this._sendingFilesQueue.length === 0;
|
|
},
|
|
|
|
isFileTransferInProgress: function() {
|
|
var jobs = this.transferStatusList.querySelector('div');
|
|
return jobs != null;
|
|
},
|
|
|
|
sendFileViaHandover: function bt_sendFileViaHandover(evt) {
|
|
var mac = evt.detail.mac;
|
|
var blob = evt.detail.blob;
|
|
var adapter = Service.query('Bluetooth.getAdapter');
|
|
if (adapter !== null) {
|
|
var sendingFilesSchedule = {
|
|
viaHandover: true,
|
|
numberOfFiles: 1,
|
|
numSuccessful: 0,
|
|
numUnsuccessful: 0
|
|
};
|
|
this._onFilesSending({detail: sendingFilesSchedule});
|
|
// XXX: Bug 915602 - [Bluetooth] Call sendFile api will crash
|
|
// the system while device is just paired.
|
|
// The paired device is ready to send file.
|
|
// Since above issue is existed, we use a setTimeout with 3 secs delay
|
|
var waitConnectionReadyTimeoutTime = 3000;
|
|
setTimeout(() => {
|
|
adapter.sendFile(mac, blob);
|
|
}, waitConnectionReadyTimeoutTime);
|
|
} else {
|
|
var msg = 'Cannot get adapter from system Bluetooth monitor.';
|
|
this.debug(msg);
|
|
}
|
|
},
|
|
|
|
_onUpdateProgress: function bt__onUpdateProgress(mode, evt) {
|
|
switch (mode) {
|
|
case 'start':
|
|
var transferInfo = evt.detail.transferInfo;
|
|
this.initProgress(transferInfo);
|
|
break;
|
|
|
|
case 'progress':
|
|
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) {
|
|
// Create progress dynamically in notification center
|
|
var address = evt.address;
|
|
var transferMode =
|
|
(evt.received === true) ?
|
|
'bluetooth-receiving-progress2' : 'bluetooth-sending-progress2';
|
|
|
|
var content =
|
|
`<div data-icon="bluetooth-transfer-circle" aria-hidden="true"></div>
|
|
<div class="title-container" data-l10n-id="${transferMode}"></div>
|
|
<progress value="0" max="1"></progress>`;
|
|
|
|
var transferTask = document.createElement('div');
|
|
transferTask.id = 'bluetooth-transfer-status';
|
|
transferTask.className = 'fake-notification';
|
|
transferTask.setAttribute('data-id', address);
|
|
transferTask.setAttribute('role', 'link');
|
|
transferTask.innerHTML = content;
|
|
transferTask.addEventListener('click', this._bindOnCancelTransferTask);
|
|
this.transferStatusList.appendChild(transferTask);
|
|
},
|
|
|
|
updateProgress: function bt_updateProgress(value, evt) {
|
|
var address = evt.address;
|
|
var id = 'div[data-id="' + address + '"] progress';
|
|
var progressEl = this.transferStatusList.querySelector(id);
|
|
progressEl.value = value;
|
|
},
|
|
|
|
removeProgress: function bt_removeProgress(evt) {
|
|
var address = evt.address;
|
|
var id = 'div[data-id="' + address + '"]';
|
|
var finishedTask = this.transferStatusList.querySelector(id);
|
|
// If we decline receiving file, Bluetooth won't callback
|
|
// 'bluetooth-opp-transfer-start', 'bluetooth-opp-update-progress' event.
|
|
// So that there is no progress element which was created on notification.
|
|
// There is only 'bluetooth-opp-transfer-complete' event to notify Gaia
|
|
// the transferring request in failed case.
|
|
if (finishedTask == null) {
|
|
return;
|
|
}
|
|
|
|
finishedTask.removeEventListener('click', this._bindOnCancelTransferTask);
|
|
this.transferStatusList.removeChild(finishedTask);
|
|
},
|
|
|
|
onCancelTransferTask: function bt_onCancelTransferTask(evt) {
|
|
var address = evt.currentTarget.dataset.id;
|
|
// Show confirm dialog for user to cancel transferring task
|
|
UtilityTray.hide();
|
|
this.showCancelTransferPrompt(address);
|
|
},
|
|
|
|
showCancelTransferPrompt: function bt_showCancelTransferPrompt(address) {
|
|
var cancel = {
|
|
title: 'no',
|
|
callback: this.continueTransfer.bind(this)
|
|
};
|
|
|
|
var confirm = {
|
|
title: 'yes',
|
|
callback: this.cancelTransfer.bind(this, address)
|
|
};
|
|
|
|
Service.request('showCustomDialog',
|
|
'cancelFileTransfer',
|
|
'cancelFileTransfer',
|
|
cancel,
|
|
confirm
|
|
);
|
|
},
|
|
|
|
continueTransfer: function bt_continueTransfer() {
|
|
Service.request('hideCustomDialog');
|
|
},
|
|
|
|
cancelTransfer: function bt_cancelTransfer(address) {
|
|
Service.request('hideCustomDialog');
|
|
var adapter = Service.query('Bluetooth.getAdapter');
|
|
if (adapter !== null) {
|
|
adapter.stopSendingFile(address);
|
|
} else {
|
|
var msg = 'Cannot get adapter from system Bluetooth monitor.';
|
|
this.debug(msg);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Create notification when transfer complete.
|
|
*
|
|
* @param {Object} evt bluetooth-opp-transfer-complete event
|
|
*/
|
|
_onTransferComplete: function bt__onTransferComplete(evt) {
|
|
var transferInfo = evt.detail.transferInfo;
|
|
// Remove transferring progress
|
|
this.removeProgress(transferInfo);
|
|
|
|
// Show notification
|
|
var nData = {
|
|
titleL10n: null,
|
|
icon: this.bluetoothIcon,
|
|
transferInfo: null,
|
|
onclick: null
|
|
};
|
|
|
|
if (transferInfo.success === true) {
|
|
if (transferInfo.received) {
|
|
// Received file can be opened only
|
|
nData.titleL10n = 'transferFinished-receivedSuccessful-title';
|
|
nData.transferInfo = transferInfo;
|
|
nData.onclick = this.openReceivedFile.bind(this, transferInfo);
|
|
} else {
|
|
nData.titleL10n = 'transferFinished-sentSuccessful-title';
|
|
}
|
|
} else {
|
|
if (transferInfo.received) {
|
|
nData.titleL10n = 'transferFinished-receivedFailed-title';
|
|
} else {
|
|
nData.titleL10n = 'transferFinished-canceled';
|
|
}
|
|
}
|
|
|
|
var l10nArgs = {
|
|
icon: nData.icon,
|
|
data: {
|
|
systemMessageTarget: 'BluetoothTransfer'
|
|
}
|
|
};
|
|
|
|
if (transferInfo.fileName) {
|
|
l10nArgs.body = transferInfo.fileName;
|
|
// put original message in data for reference
|
|
l10nArgs.data.transferInfo = nData.transferInfo;
|
|
} else {
|
|
l10nArgs.bodyL10n = 'unknown-file';
|
|
}
|
|
|
|
var promise = NotificationHelper.send(nData.titleL10n, l10nArgs);
|
|
if (nData.onclick) {
|
|
promise.then(function(notification) {
|
|
notification.addEventListener('click', nData.onclick);
|
|
});
|
|
}
|
|
|
|
var viaHandover = false;
|
|
if (this._sendingFilesQueue.length > 0) {
|
|
viaHandover = this._sendingFilesQueue[0].viaHandover || false;
|
|
}
|
|
|
|
// Have a report notification for sending multiple files.
|
|
this.summarizeSentFilesReport(transferInfo);
|
|
|
|
// Inform NfcHandoverManager that the transfer completed
|
|
var details = {received: transferInfo.received,
|
|
success: transferInfo.success,
|
|
viaHandover: viaHandover};
|
|
|
|
window.dispatchEvent(new CustomEvent('nfc-transfer-completed', {
|
|
detail: details}));
|
|
},
|
|
|
|
/**
|
|
* Handle related system notification message operation after reboot.
|
|
* Need close notification message by ourself.
|
|
*
|
|
* @param {Object} message system notification message
|
|
*/
|
|
handleSystemMessageNotification: function(message) {
|
|
this.debug('Received system message: ' + JSON.stringify(message));
|
|
if (message.data && message.data.transferInfo) {
|
|
var evt = {
|
|
fileName: message.data.transferInfo.fileName,
|
|
contentType: message.data.transferInfo.contentType
|
|
};
|
|
this.openReceivedFile(evt);
|
|
} else {
|
|
console.error('The notification does not carry correct data');
|
|
}
|
|
this.closeSystemMessageNotification(message);
|
|
},
|
|
|
|
/**
|
|
* Close the system notification message.
|
|
*
|
|
* @param {Object} message system notification message
|
|
*/
|
|
closeSystemMessageNotification: function(message) {
|
|
Notification.get({ tag: message.tag }).then(notifs => {
|
|
notifs.forEach(notif => {
|
|
// check on the body
|
|
if (notif.body === message.body) {
|
|
notif.close && notif.close();
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
summarizeSentFilesReport:
|
|
function bt_summarizeSentFilesReport(transferInfo) {
|
|
// Ignore received files
|
|
if (transferInfo.received) {
|
|
return;
|
|
}
|
|
|
|
// Consumer: System app consume each sending file request from Bluetooth
|
|
// app
|
|
var msg = 'remove the finished sending task from queue, ' +
|
|
'queue length = ';
|
|
var successful = transferInfo.success;
|
|
var sendingFilesSchedule = this._sendingFilesQueue[0];
|
|
var numberOfFiles = sendingFilesSchedule.numberOfFiles;
|
|
if (numberOfFiles == 1) { // for sent one file only.
|
|
// We don't need to summarize a report for sent one file only.
|
|
// Remove the finished sending task from the queue
|
|
this._sendingFilesQueue.shift();
|
|
msg += this._sendingFilesQueue.length;
|
|
this.debug(msg);
|
|
} else { // The scheduled task is for sent multiple files.
|
|
// Create a report in notification.
|
|
// Record each transferring report.
|
|
if (successful) {
|
|
this._sendingFilesQueue[0].numSuccessful++;
|
|
} else {
|
|
this._sendingFilesQueue[0].numUnsuccessful++;
|
|
}
|
|
|
|
var numSuccessful = this._sendingFilesQueue[0].numSuccessful;
|
|
var numUnsuccessful = this._sendingFilesQueue[0].numUnsuccessful;
|
|
if ((numSuccessful + numUnsuccessful) == numberOfFiles) {
|
|
// In this item of queue, all files were sent completely.
|
|
NotificationHelper.send('transferReportTitle', {
|
|
'bodyL10n': {
|
|
id: 'transferReport-description',
|
|
args: {
|
|
numSuccessful: numSuccessful,
|
|
numUnsuccessful: numUnsuccessful
|
|
}
|
|
},
|
|
'icon': this.bluetoothIcon
|
|
});
|
|
|
|
// Remove the finished sending task from the queue
|
|
this._sendingFilesQueue.shift();
|
|
msg += this._sendingFilesQueue.length;
|
|
this.debug(msg);
|
|
}
|
|
}
|
|
},
|
|
|
|
openReceivedFile: function bt_openReceivedFile(evt) {
|
|
// Launch the gallery with an open activity to view this specific photo
|
|
// XXX: Bug 897434 - Save received/downloaded files in one specific folder
|
|
// with meaningful path and filename
|
|
var filePath = 'Download/Bluetooth/' + evt.fileName;
|
|
var contentType = evt.contentType;
|
|
var storageType = 'sdcard';
|
|
var storage = navigator.getDeviceStorage(storageType);
|
|
var getreq = storage.get(filePath);
|
|
var loader = LazyLoader.load(['shared/js/mime_mapper.js']);
|
|
Promise.all([getreq, loader]).then(() => {
|
|
var file = getreq.result;
|
|
// When we got the file by storage type of "sdcard"
|
|
// use the file.type to replace the empty fileType which is given by API
|
|
var fileName = file.name;
|
|
var extension = fileName.split('.').pop();
|
|
var originalType = file.type || contentType;
|
|
var mappedType = (MimeMapper.isSupportedType(originalType)) ?
|
|
originalType : MimeMapper.guessTypeFromExtension(extension);
|
|
|
|
var a = new MozActivity({
|
|
name: mappedType == 'text/vcard' ? 'import' : 'open',
|
|
data: {
|
|
type: mappedType,
|
|
blob: file,
|
|
// XXX: https://bugzilla.mozilla.org/show_bug.cgi?id=812098
|
|
// Pass the file name for Music APP since it can not open blob
|
|
filename: fileName
|
|
}
|
|
});
|
|
|
|
a.onerror = (e) => {
|
|
var msg = 'open activity error:' + a.error.name;
|
|
this.debug(msg);
|
|
switch (a.error.name) {
|
|
case 'NO_PROVIDER':
|
|
UtilityTray.hide();
|
|
// Cannot identify MIMETYPE
|
|
// So, show cannot open file dialog with unknow media type
|
|
this.showUnknownMediaPrompt(fileName);
|
|
return;
|
|
case 'ActivityCanceled':
|
|
return;
|
|
case 'USER_ABORT':
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
};
|
|
a.onsuccess = (e) => {
|
|
var msg = 'open activity onsuccess';
|
|
this.debug(msg);
|
|
};
|
|
}, (err) => {
|
|
if (getreq.readyState === 'done' && getreq.error) {
|
|
// DeviceStorage Error
|
|
var msg = 'failed to get file:' + filePath + ' ' + err.name;
|
|
this.debug(msg);
|
|
} else { // LazyLoader Error
|
|
throw err;
|
|
}
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
});
|
|
},
|
|
|
|
showUnknownMediaPrompt: function bt_showUnknownMediaPrompt(fileName) {
|
|
var confirm = {
|
|
title: 'confirm',
|
|
callback: function() {
|
|
Service.request('hideCustomDialog');
|
|
}
|
|
};
|
|
|
|
var body = {id: 'unknownMediaTypeToOpenFile', args: {fileName: fileName}};
|
|
Service.request('showCustomDialog',
|
|
'cannotOpenFile', body, confirm, null);
|
|
}
|
|
};
|
|
|
|
exports.BluetoothTransfer = BluetoothTransfer;
|
|
})(window);
|