Add permission-based reading of Android contacts, SMS and call history. Include shared Gaia fixes and document device validation limits. Pixel image qualification remains pending.
105 lines
3 KiB
JavaScript
Executable file
105 lines
3 KiB
JavaScript
Executable file
'use strict';
|
|
|
|
(function(exports) {
|
|
|
|
var LayoutDictionaryDownloader = function(imEngineId, dictFilename) {
|
|
this.imEngineId = imEngineId;
|
|
this.dictFilename = dictFilename;
|
|
|
|
this._xhr = null;
|
|
};
|
|
|
|
// Dictionaries ship with Vulpes so adding a layout also works offline.
|
|
LayoutDictionaryDownloader.prototype.REMOTE_URL =
|
|
'/js/imes/%imEngineId/dictionaries/%dictFilename';
|
|
|
|
// If the data schema changes in an incompatible way, we must bump the
|
|
// version-to-download here.
|
|
LayoutDictionaryDownloader.prototype.ENGINE_DATA_VERSIONS = Object.freeze({
|
|
'latin': 1
|
|
});
|
|
|
|
LayoutDictionaryDownloader.prototype.onprogress = null;
|
|
|
|
LayoutDictionaryDownloader.prototype.load = function() {
|
|
if (this._xhr) {
|
|
throw new Error('LayoutDictionaryDownloader: Already downloading...');
|
|
}
|
|
|
|
var p = new Promise(function(resolve, reject) {
|
|
var url = this.REMOTE_URL
|
|
.replace('%imEngineId', this.imEngineId)
|
|
.replace('%ver', this.ENGINE_DATA_VERSIONS[this.imEngineId])
|
|
.replace('%dictFilename', this.dictFilename);
|
|
|
|
var xhr = this._xhr = new XMLHttpRequest();
|
|
xhr.open('GET', url, true);
|
|
xhr.responseType = 'arraybuffer';
|
|
|
|
xhr.onprogress = function(evt) {
|
|
if (typeof this.onprogress === 'function') {
|
|
this.onprogress(evt.loaded, evt.total);
|
|
}
|
|
}.bind(this);
|
|
|
|
xhr.onloadend = function() {
|
|
this._xhr = null;
|
|
|
|
var data = xhr.response;
|
|
// We will only resolve the promise when the data is verified.
|
|
// For any other situration, we simply return the HTTP status code as
|
|
// a rejected placeholder value.
|
|
// (it doesn't really matter if you got 200/404/500
|
|
// or anything if it's not what you are looking for right :-/?)
|
|
if (data && this._verifyData(data)) {
|
|
if (typeof this.onprogress === 'function') {
|
|
this.onprogress(data.byteLength, data.byteLength);
|
|
}
|
|
|
|
resolve(data);
|
|
} else {
|
|
reject(xhr.statusText);
|
|
}
|
|
}.bind(this);
|
|
|
|
xhr.send();
|
|
}.bind(this));
|
|
|
|
return p;
|
|
};
|
|
|
|
LayoutDictionaryDownloader.prototype.abort = function() {
|
|
if (!this._xhr) {
|
|
throw new Error('LayoutDictionaryDownloader: ' +
|
|
'Not downloading but abort is called.');
|
|
}
|
|
|
|
this._xhr.abort();
|
|
|
|
this._xhr = null;
|
|
};
|
|
|
|
LayoutDictionaryDownloader.prototype._verifyData = function(buffer) {
|
|
switch (this.imEngineId) {
|
|
case 'latin':
|
|
// There is only first 8 bytes to check -- we can't be sure if the data
|
|
// is truncated. However that shouldn't happen since our CDN sends out
|
|
// Content-Length header.
|
|
//
|
|
// TODO: Harden the verification here in some way.
|
|
//
|
|
if (!(buffer instanceof ArrayBuffer) || buffer.byteLength < 8) {
|
|
return false;
|
|
}
|
|
var view = new Uint8Array(buffer, 0, 8);
|
|
return (String.fromCharCode.apply(String, view) === 'FxOSDICT');
|
|
|
|
default:
|
|
throw new Error('LayoutDictionaryDownloader: ' +
|
|
'No verify method available for this imEngine.');
|
|
}
|
|
};
|
|
|
|
exports.LayoutDictionaryDownloader = LayoutDictionaryDownloader;
|
|
|
|
}(window));
|