Merge b2g-inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-02-11 14:57:31 -05:00
commit c511df94e8
28 changed files with 868 additions and 206 deletions

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -1,4 +1,4 @@
{
"revision": "052499d9ddb89a1168cb5fcd092c15095ef3a6a9",
"revision": "01b437206d143e1632ee5a5fd49cc649aee2e970",
"repo_path": "/integration/gaia-central"
}

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -381,7 +381,8 @@ MediaCacheStream::MediaCacheStream(ChannelMediaResource* aClient)
mPlaybackBytesPerSecond(10000),
mPinCount(0),
mCurrentMode(MODE_PLAYBACK),
mMetadataInPartialBlockBuffer(false)
mMetadataInPartialBlockBuffer(false),
mPartialBlockBuffer(new int64_t[BLOCK_SIZE/sizeof(int64_t)])
{
}
@ -1735,12 +1736,12 @@ MediaCacheStream::NotifyDataReceived(int64_t aSize, const char* aData,
// to clear this flag.
mMetadataInPartialBlockBuffer = false;
}
memcpy(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset,
memcpy(reinterpret_cast<char*>(mPartialBlockBuffer.get()) + blockOffset,
data, chunkSize);
if (blockOffset + chunkSize == BLOCK_SIZE) {
// We completed a block, so lets write it out.
blockDataToStore = reinterpret_cast<char*>(mPartialBlockBuffer);
blockDataToStore = reinterpret_cast<char*>(mPartialBlockBuffer.get());
if (mMetadataInPartialBlockBuffer) {
mode = MODE_METADATA;
}
@ -1788,7 +1789,7 @@ MediaCacheStream::FlushPartialBlockInternal(bool aNotifyAll)
aNotifyAll ? "yes" : "no"));
// Write back the partial block
memset(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset, 0,
memset(reinterpret_cast<char*>(mPartialBlockBuffer.get()) + blockOffset, 0,
BLOCK_SIZE - blockOffset);
gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer,
mMetadataInPartialBlockBuffer ? MODE_METADATA : MODE_PLAYBACK);
@ -2182,7 +2183,7 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
// the cache.
bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
memcpy(aBuffer,
reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer) + offsetInStreamBlock, bytes);
reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
if (mCurrentMode == MODE_METADATA) {
streamWithPartialBlock->mMetadataInPartialBlockBuffer = true;
}
@ -2277,7 +2278,7 @@ MediaCacheStream::ReadFromCache(char* aBuffer,
// the cache.
bytes = std::min<int64_t>(size, mChannelOffset - streamOffset);
memcpy(aBuffer + count,
reinterpret_cast<char*>(mPartialBlockBuffer) + offsetInStreamBlock, bytes);
reinterpret_cast<char*>(mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
} else {
if (cacheBlock < 0) {
// We expect all blocks to be cached! Fail!

View File

@ -499,7 +499,9 @@ private:
// mChannelOffset%BLOCK_SIZE bytes have been filled in with good data,
// the rest are garbage.
// Use int64_t so that the data is well-aligned.
int64_t mPartialBlockBuffer[BLOCK_SIZE/sizeof(int64_t)];
// Heap allocate this buffer since the exact power-of-2 will cause allocation
// slop when combined with the rest of the object members.
nsAutoArrayPtr<int64_t> mPartialBlockBuffer;
};
} // namespace mozilla

View File

@ -86,7 +86,7 @@ class MediaRecorder::Session: public nsIObserver
if (mSession->IsEncoderError()) {
recorder->NotifyError(NS_ERROR_UNEXPECTED);
}
nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession);
nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession->GetEncodedData());
if (NS_FAILED(rv)) {
recorder->NotifyError(rv);
}
@ -544,8 +544,8 @@ MediaRecorder::RequestData(ErrorResult& aResult)
}
NS_DispatchToMainThread(
NS_NewRunnableMethodWithArg<Session *>(this,
&MediaRecorder::CreateAndDispatchBlobEvent, mSession),
NS_NewRunnableMethodWithArg<const already_AddRefed<nsIDOMBlob> >(this,
&MediaRecorder::CreateAndDispatchBlobEvent, mSession->GetEncodedData()),
NS_DISPATCH_NORMAL);
}
@ -576,7 +576,7 @@ MediaRecorder::Constructor(const GlobalObject& aGlobal,
}
nsresult
MediaRecorder::CreateAndDispatchBlobEvent(Session *aSession)
MediaRecorder::CreateAndDispatchBlobEvent(const already_AddRefed<nsIDOMBlob> &aBlob)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
@ -588,7 +588,7 @@ MediaRecorder::CreateAndDispatchBlobEvent(Session *aSession)
BlobEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mData = aSession->GetEncodedData();
init.mData = aBlob;
nsRefPtr<BlobEvent> event =
BlobEvent::Constructor(this,
NS_LITERAL_STRING("dataavailable"),

View File

@ -85,7 +85,7 @@ public:
protected:
MediaRecorder& operator = (const MediaRecorder& x) MOZ_DELETE;
// Create dataavailable event with Blob data and it runs in main thread
nsresult CreateAndDispatchBlobEvent(Session *session);
nsresult CreateAndDispatchBlobEvent(const already_AddRefed<nsIDOMBlob> &aBlob);
// Creating a simple event to notify UA simple event.
void DispatchSimpleEvent(const nsAString & aStr);
// Creating a error event with message.

View File

@ -258,6 +258,7 @@ support-files =
[test_mediarecorder_record_immediate_stop.html]
[test_mediarecorder_record_session.html]
[test_mediarecorder_record_startstopstart.html]
[test_mediarecorder_getencodeddata.html]
[test_mediarecorder_unsupported_src.html]
[test_playback.html]
[test_seekLies.html]

View File

@ -0,0 +1,68 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 957452 Test GetEncodedData problem on asan build</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
function () {
var ac = new window.AudioContext();
var dest = ac.createMediaStreamDestination();
var stream = dest.stream;
var onErrorFired = false;
var expectedMimeType = '';
var ondataavailableFired = false;
setTimeout(function() {
var mediaRecorder = new MediaRecorder(stream);
mediaRecorder.onstop = function(e) {
is(e.target.state, 'inactive',
'Media recorder is inactive after being stopped');
ok(onErrorFired, 'onStop after onError');
ok(ondataavailableFired, 'ondataavailableFired');
SimpleTest.finish();
}
mediaRecorder.ondataavailable = function(evt) {
if (onErrorFired) {
ondataavailableFired = true;
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.type, 'dataavailable',
'Event type should dataavailable');
is(evt.data.size, 0,
'Blob data size received is equal to zero');
is(evt.data.type, expectedMimeType,
'Blob data received should have type = ' + expectedMimeType);
is(evt.target.mimeType, expectedMimeType,
'Mime type in ondataavailable = ' + expectedMimeType);
} else {
ok(false, 'should get onError first');
}
}
mediaRecorder.onerror = function(evt) {
ok(evt instanceof RecordErrorEvent,
'Events fired from onerror should be RecordErrorEvent');
is(evt.type, 'error',
'Event type should onerror');
is(evt.name, 'GenericError',
'Event name is GenericError');
onErrorFired = true;
}
mediaRecorder.start(0);
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
is(mediaRecorder.stream, stream,
'Media recorder stream = element stream at the start of recording');
mediaRecorder.requestData();
mediaRecorder.stop();
}, 100);
}
);
</script>
</pre>
</body>
</html>

View File

@ -20,24 +20,15 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
Cu.importGlobalProperties(["indexedDB"]);
const DB_NAME = "contacts";
const DB_VERSION = 18;
const STORE_NAME = "contacts";
const SAVED_GETALL_STORE_NAME = "getallcache";
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
this.DB_NAME = "contacts";
this.DB_VERSION = 19;
this.STORE_NAME = "contacts";
this.SAVED_GETALL_STORE_NAME = "getallcache";
const CHUNK_SIZE = 20;
const REVISION_STORE = "revision";
this.REVISION_STORE = "revision";
const REVISION_KEY = "revision";
function optionalDate(aValue) {
if (aValue) {
if (!(aValue instanceof Date)) {
return new Date(aValue);
}
return aValue;
}
return undefined;
}
function exportContact(aRecord) {
if (aRecord) {
delete aRecord.search;
@ -182,7 +173,16 @@ ContactDB.prototype = {
aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
}
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let valueUpgradeSteps = [];
function scheduleValueUpgrade(upgradeFunc) {
var length = valueUpgradeSteps.push(upgradeFunc);
if (DEBUG) debug("Scheduled a value upgrade function, index " + (length - 1));
}
// We always output this debug line because it's useful and the noise ratio
// very low.
debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
let objectStore;
@ -491,45 +491,34 @@ ContactDB.prototype = {
function upgrade12to13() {
if (DEBUG) debug("Add phone substring to the search index if appropriate for country");
if (this.substringMatching) {
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
cursor.value.search.parsedTel = cursor.value.search.parsedTel || [];
cursor.value.properties.tel.forEach(
scheduleValueUpgrade(function upgradeValue12to13(value) {
if (value.properties.tel) {
value.search.parsedTel = value.search.parsedTel || [];
value.properties.tel.forEach(
function(tel) {
let normalized = PhoneNumberUtils.normalize(tel.value.toString());
if (normalized) {
if (this.substringMatching && normalized.length > this.substringMatching) {
let sub = normalized.slice(-this.substringMatching);
if (cursor.value.search.parsedTel.indexOf(sub) === -1) {
if (value.search.parsedTel.indexOf(sub) === -1) {
if (DEBUG) debug("Adding substring index: " + tel + ", " + sub);
cursor.value.search.parsedTel.push(sub);
value.search.parsedTel.push(sub);
}
}
}
}.bind(this)
);
cursor.update(cursor.value);
}
cursor.continue();
return true;
} else {
next();
return false;
}
}.bind(this);
} else {
next();
}.bind(this));
}
next();
},
function upgrade13to14() {
if (DEBUG) debug("Cleaning up empty substring entries in telMatch index");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
scheduleValueUpgrade(function upgradeValue13to14(value) {
function removeEmptyStrings(value) {
if (value) {
const oldLength = value.length;
@ -542,92 +531,70 @@ ContactDB.prototype = {
}
}
let cursor = event.target.result;
if (cursor) {
let modified = removeEmptyStrings(cursor.value.search.parsedTel);
let modified2 = removeEmptyStrings(cursor.value.search.tel);
if (modified || modified2) {
cursor.update(cursor.value);
}
cursor.continue();
} else {
let modified = removeEmptyStrings(value.search.parsedTel);
let modified2 = removeEmptyStrings(value.search.tel);
return (modified || modified2);
});
next();
}
};
},
function upgrade14to15() {
if (DEBUG) debug("Fix array properties saved as scalars");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
"name", "honorificPrefix", "givenName",
"additionalName", "familyName", "honorificSuffix",
"nickname", "category", "org", "jobTitle",
"note", "key"];
const PROPERTIES_WITH_TYPE = ["adr", "email", "url", "impp", "tel"];
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
scheduleValueUpgrade(function upgradeValue14to15(value) {
let changed = false;
if (cursor) {
let props = cursor.value.properties;
let props = value.properties;
for (let prop of ARRAY_PROPERTIES) {
if (props[prop]) {
if (!Array.isArray(props[prop])) {
cursor.value.properties[prop] = [props[prop]];
value.properties[prop] = [props[prop]];
changed = true;
}
if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
let subprop = cursor.value.properties[prop];
let subprop = value.properties[prop];
for (let i = 0; i < subprop.length; ++i) {
if (!Array.isArray(subprop[i].type)) {
cursor.value.properties[prop][i].type = [subprop[i].type];
value.properties[prop][i].type = [subprop[i].type];
changed = true;
}
}
}
}
}
if (changed) {
cursor.update(cursor.value);
}
cursor.continue();
} else {
return changed;
});
next();
}
};
},
function upgrade15to16() {
if (DEBUG) debug("Fix Date properties");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
const DATE_PROPERTIES = ["bday", "anniversary"];
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
scheduleValueUpgrade(function upgradeValue15to16(value) {
let changed = false;
if (cursor) {
let props = cursor.value.properties;
let props = value.properties;
for (let prop of DATE_PROPERTIES) {
if (props[prop] && !(props[prop] instanceof Date)) {
cursor.value.properties[prop] = new Date(props[prop]);
value.properties[prop] = new Date(props[prop]);
changed = true;
}
}
if (changed) {
cursor.update(cursor.value);
}
cursor.continue();
} else {
return changed;
});
next();
}
};
},
function upgrade16to17() {
if (DEBUG) debug("Fix array with null values");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
"name", "honorificPrefix", "givenName",
"additionalName", "familyName", "honorificSuffix",
@ -638,7 +605,9 @@ ContactDB.prototype = {
const DATE_PROPERTIES = ["bday", "anniversary"];
objectStore.openCursor().onsuccess = function(event) {
scheduleValueUpgrade(function upgradeValue16to17(value) {
let changed;
function filterInvalidValues(val) {
let shouldKeep = val != null; // null or undefined
if (!shouldKeep) {
@ -651,10 +620,7 @@ ContactDB.prototype = {
return array.filter(filterInvalidValues);
}
let cursor = event.target.result;
let changed = false;
if (cursor) {
let props = cursor.value.properties;
let props = value.properties;
for (let prop of ARRAY_PROPERTIES) {
@ -693,16 +659,21 @@ ContactDB.prototype = {
}
if (changed) {
cursor.value.properties = props;
cursor.update(cursor.value);
}
cursor.continue();
value.properties = props;
return true;
} else {
return false;
}
});
next();
}
}
},
function upgrade17to18() {
// this upgrade function has been moved to the next upgrade path because
// a previous version of it had a bug
next();
},
function upgrade18to19() {
if (DEBUG) {
debug("Adding the name index");
}
@ -711,34 +682,93 @@ ContactDB.prototype = {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// an earlier version of this code could have run, so checking whether
// the index exists
if (!objectStore.indexNames.contains("name")) {
objectStore.createIndex("name", "properties.name", { multiEntry: true });
objectStore.createIndex("nameLowerCase", "search.name", { multiEntry: true });
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
let value = cursor.value;
scheduleValueUpgrade(function upgradeValue18to19(value) {
value.search.name = [];
if (value.properties.name) {
value.properties.name.forEach(function addNameIndex(name) {
value.search.name.push(name.toLowerCase());
var lowerName = name.toLowerCase();
// an earlier version of this code could have added it already
if (value.search.name.indexOf(lowerName) === -1) {
value.search.name.push(lowerName);
}
});
}
cursor.update(value);
} else {
return true;
});
next();
}
};
},
];
let index = aOldVersion;
let outer = this;
function next() {
if (index == aNewVersion) {
outer.incrementRevision(aTransaction);
/* This function runs all upgrade functions that are in the
* valueUpgradeSteps array. These functions have the following properties:
* - they must be synchronous
* - they must take the value as parameter and modify it directly. They
* must not create a new object.
* - they must return a boolean true/false; true if the value was actually
* changed
*/
function runValueUpgradeSteps(done) {
if (DEBUG) debug("Running the value upgrade functions.");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
let changed = false;
let oldValue;
let value = cursor.value;
if (DEBUG) {
oldValue = JSON.stringify(value);
}
valueUpgradeSteps.forEach(function(upgradeFunc, i) {
if (DEBUG) debug("Running upgrade function " + i);
changed = upgradeFunc(value) || changed;
});
if (changed) {
cursor.update(value);
} else if (DEBUG) {
let newValue = JSON.stringify(value);
if (newValue !== oldValue) {
// oops something went wrong
debug("upgrade: `changed` was false and still the value changed! Aborting.");
aTransaction.abort();
return;
}
}
cursor.continue();
} else {
done();
}
};
}
function finish() {
// We always output this debug line because it's useful and the noise ratio
// very low.
debug("Upgrade finished");
outer.incrementRevision(aTransaction);
}
function next() {
if (index == aNewVersion) {
runValueUpgradeSteps(finish);
return;
}
try {
var i = index++;
if (DEBUG) debug("Upgrade step: " + i + "\n");
@ -748,7 +778,7 @@ ContactDB.prototype = {
aTransaction.abort();
return;
}
};
}
function fail(why) {
why = why || "";
@ -1164,7 +1194,7 @@ ContactDB.prototype = {
for (let key in fields) {
if (DEBUG) debug("key: " + fields[key]);
if (!store.indexNames.contains(fields[key]) && fields[key] != "id") {
if (DEBUG) debug("Key not valid!" + fields[key] + ", " + store.indexNames);
if (DEBUG) debug("Key not valid!" + fields[key] + ", " + JSON.stringify(store.indexNames));
txn.abort();
return;
}

View File

@ -22,7 +22,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
let ContactService = {
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
let ContactService = this.ContactService = {
init: function() {
if (DEBUG) debug("Init");
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",

View File

@ -10,3 +10,8 @@
[test_contacts_international.html]
[test_contacts_substringmatching.html]
[test_contacts_substringmatchingVE.html]
[test_migration.html]
support-files =
test_migration_chrome.js
skip-if = os == "android"

View File

@ -389,7 +389,7 @@ function checkCount(count, msg, then) {
var index = 0;
function next() {
ok(true, "Begin!");
info("Step " + index);
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;

View File

@ -295,7 +295,8 @@ var steps = [
},
function () {
ok(true, "all done!\n");
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", -1);
SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
SimpleTest.finish();
}
];

View File

@ -124,7 +124,8 @@ var steps = [
},
function () {
ok(true, "all done!\n");
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", -1);
SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
SimpleTest.finish();
}
];

View File

@ -0,0 +1,210 @@
<!DOCTYPE html>
<html>
<head>
<title>Migration tests</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<h1>migration tests</h1>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var backend, contactsCount, allContacts;
function loadChromeScript() {
var url = SimpleTest.getTestFileURL("test_migration_chrome.js");
backend = SpecialPowers.loadChromeScript(url);
}
function addBackendEvents() {
backend.addMessageListener("createDB.success", function(count) {
contactsCount = count;
ok(true, "Created the database");
next();
});
backend.addMessageListener("createDB.error", function(err) {
ok(false, err);
next();
});
backend.addMessageListener("deleteDB.success", function() {
ok(true, "Deleted the database");
next();
});
backend.addMessageListener("deleteDB.error", function(err) {
ok(false, err);
next();
});
}
function createDB(version) {
info("Will create the DB at version " + version);
backend.sendAsyncMessage("createDB", version);
}
function deleteDB() {
info("Will delete the DB.");
backend.sendAsyncMessage("deleteDB");
}
function setSubstringMatching(value) {
info("Setting substring matching to " + value);
if (value) {
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", value);
// this is the Mcc for Brazil, so that we trigger the previous pref
SpecialPowers.setCharPref("ril.lastKnownSimMcc", "724");
} else {
SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
}
next();
}
var steps = [
function setupChromeScript() {
loadChromeScript();
addBackendEvents();
next();
},
deleteDB, // let's be sure the DB does not exist yet
createDB.bind(null, 12),
setSubstringMatching.bind(null, 7),
function testAccessMozContacts() {
info("Checking we have the right number of contacts: " + contactsCount);
var req = mozContacts.getCount();
req.onsuccess = function onsuccess() {
ok(true, "Could access the mozContacts API");
ise(this.result, contactsCount, "Contacts count is correct");
next();
};
req.onerror = function onerror() {
ok(false, "Couldn't access the mozContacts API");
next();
};
},
function testRetrieveAllContacts() {
/* if the migration does not work right, either we'll have an error, or the
contacts won't be migrated properly and thus will fail WebIDL conversion,
which will manifest as a timeout */
info("Checking the contacts are corrected to obey WebIDL constraints. (upgrades 14 to 17)");
var req = mozContacts.find();
req.onsuccess = function onsuccess() {
if (this.result) {
ise(this.result.length, contactsCount, "Contacts array length is correct");
allContacts = this.result;
next();
} else {
ok(false, "Could access the mozContacts API but got no contacts!");
next();
}
};
req.onerror = function onerror() {
ok(false, "Couldn't access the mozContacts API");
next();
};
},
function checkNameIndex() {
info("Checking name index migration (upgrades 17 to 19).");
if (!allContacts) {
next();
}
var count = allContacts.length;
function finishRequest() {
count--;
if (!count) {
next();
}
}
allContacts.forEach(function(contact) {
var name = contact.name && contact.name[0];
if (!name) {
count--;
return;
}
var req = mozContacts.find({
filterBy: ["name"],
filterValue: name,
filterOp: "equals"
});
req.onsuccess = function onsuccess() {
if (this.result) {
info("Found contact '" + name + "', checking it's the correct one.");
checkContacts(this.result[0], contact);
} else {
ok(false, "Could not find contact with name '" + name + "'");
}
finishRequest();
};
req.onerror = function onerror() {
ok(false, "Error while finding contact with name '" + name + "'!");
finishRequest();
}
});
if (!count) {
ok(false, "No contact had a name, this is unexpected.");
next();
}
},
function checkSubstringMatching() {
var subject = "0004567890"; // the last 7 digits are the same that at least one contact
info("Looking for a contact matching " + subject);
var req = mozContacts.find({
filterValue: subject,
filterOp: "match",
filterBy: ["tel"],
filterLimit: 1
});
req.onsuccess = function onsuccess() {
if (this.result && this.result[0]) {
ok(true, "Found a contact with number " + this.result[0].tel[0].value);
}
next();
};
req.onerror = function onerror() {
ok(false, "Error while finding contact for substring matching check!");
next();
};
},
deleteDB,
setSubstringMatching.bind(null, null),
function finish() {
backend.destroy();
info("all done!\n");
SimpleTest.finish();
}
];
start_tests();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,331 @@
/* global
sendAsyncMessage,
addMessageListener,
indexedDB
*/
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
let imports = {};
Cu.import("resource://gre/modules/ContactDB.jsm", imports);
Cu.import("resource://gre/modules/ContactService.jsm", imports);
Cu.import("resource://gre/modules/Promise.jsm", imports);
Cu.importGlobalProperties(["indexedDB"]);
const {
STORE_NAME,
SAVED_GETALL_STORE_NAME,
REVISION_STORE,
DB_NAME,
ContactService,
Promise
} = imports;
let DEBUG = false;
function debug(str) {
if (DEBUG){
dump("-*- TestMigrationChromeScript: " + str + "\n");
}
}
const DATA = {
12: {
SCHEMA: function createSchema12(db, transaction) {
let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
objectStore.createIndex("givenName", "properties.givenName", { multiEntry: true });
objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
objectStore.createIndex("givenNameLowerCase", "search.givenName", { multiEntry: true });
objectStore.createIndex("telLowerCase", "search.tel", { multiEntry: true });
objectStore.createIndex("emailLowerCase", "search.email", { multiEntry: true });
objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
objectStore.createIndex("category", "properties.category", { multiEntry: true });
objectStore.createIndex("email", "search.email", { multiEntry: true });
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
db.createObjectStore(SAVED_GETALL_STORE_NAME);
db.createObjectStore(REVISION_STORE).put(0, "revision");
},
BAD: [
{
// this contact is bad because its "name" property is not an array and
// is the empty string (upgrade 16 to 17)
"properties": {
"name": "",
"email": [],
"url": [{
"type": ["source"],
"value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
}],
"category": ["gmail"],
"adr": [],
"tel": [{
"type": ["mobile"],
"value": "+7 123 456-78-90"
}],
"sex": "undefined",
"genderIdentity": "undefined"
},
"search": {
"givenName": [],
"familyName": [],
"email": [],
"category": ["gmail"],
"tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
"4567890","567890","67890","7890","890","90","0","81234567890"],
"exactTel": ["+71234567890"],
"parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
},
"updated": new Date("2013-07-27T16:47:40.974Z"),
"published": new Date("2013-07-27T16:47:40.974Z"),
"id": "bad-1"
},
{
// This contact is bad because its "name" property is not an array
// (upgrade 14 to 15)
"properties": {
"name": "name-bad-2",
"email": [],
"url": [{
"type": ["source"],
"value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
}],
"category": ["gmail"],
"adr": [],
"tel": [{
"type": ["mobile"],
"value": "+7 123 456-78-90"
}],
"sex": "undefined",
"genderIdentity": "undefined"
},
"search": {
"givenName": [],
"familyName": [],
"email": [],
"category": ["gmail"],
"tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
"4567890","567890","67890","7890","890","90","0","81234567890"],
"exactTel": ["+71234567890"],
"parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
},
"updated": new Date("2013-07-27T16:47:40.974Z"),
"published": new Date("2013-07-27T16:47:40.974Z"),
"id": "bad-2"
},
{
// This contact is bad because its bday property is a String (upgrade 15
// to 16), and its anniversary property is an empty string (upgrade 16
// to 17)
"properties": {
"name": ["name-bad-3"],
"email": [],
"url": [{
"type": ["source"],
"value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
}],
"category": ["gmail"],
"adr": [],
"tel": [{
"type": ["mobile"],
"value": "+7 123 456-78-90"
}],
"sex": "undefined",
"genderIdentity": "undefined",
"bday": "2013-07-27T16:47:40.974Z",
"anniversary": ""
},
"search": {
"givenName": [],
"familyName": [],
"email": [],
"category": ["gmail"],
"tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
"4567890","567890","67890","7890","890","90","0","81234567890"],
"exactTel": ["+71234567890"],
"parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
},
"updated": new Date("2013-07-27T16:47:40.974Z"),
"published": new Date("2013-07-27T16:47:40.974Z"),
"id": "bad-3"
},
{
// This contact is bad because its tel property has a tel.type null
// value (upgrade 16 to 17), and email.type not array value (upgrade 14
// to 15)
"properties": {
"name": ["name-bad-4"],
"email": [{
"value": "toto@toto.com",
"type": "home"
}],
"url": [{
"type": ["source"],
"value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
}],
"category": ["gmail"],
"adr": [],
"tel": [{
"type": null,
"value": "+7 123 456-78-90"
}],
"sex": "undefined",
"genderIdentity": "undefined"
},
"search": {
"givenName": [],
"familyName": [],
"email": [],
"category": ["gmail"],
"tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
"4567890","567890","67890","7890","890","90","0","81234567890"],
"exactTel": ["+71234567890"],
"parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
},
"updated": new Date("2013-07-27T16:47:40.974Z"),
"published": new Date("2013-07-27T16:47:40.974Z"),
"id": "bad-4"
}
],
GOOD: [
{
"properties": {
"name": ["name-good-1"],
"email": [],
"url": [{
"type": ["source"],
"value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
}],
"category": ["gmail"],
"adr": [],
"tel": [{
"type": ["mobile"],
"value": "+7 123 456-78-90"
}],
"sex": "undefined",
"genderIdentity": "undefined"
},
"search": {
"givenName": [],
"familyName": [],
"email": [],
"category": ["gmail"],
"tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
"4567890","567890","67890","7890","890","90","0","81234567890"],
"exactTel": ["+71234567890"],
"parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
},
"updated": new Date("2013-07-27T16:47:40.974Z"),
"published": new Date("2013-07-27T16:47:40.974Z"),
"id": "good-1"
}
]
}
};
function DataManager(version) {
if (!(version in DATA)) {
throw new Error("Version " + version + " can't be found in our test datas.");
}
this.version = version;
this.data = DATA[version];
}
DataManager.prototype = {
open: function() {
debug("opening for version " + this.version);
var deferred = Promise.defer();
let req = indexedDB.open(DB_NAME, this.version);
req.onupgradeneeded = function() {
let db = req.result;
let transaction = req.transaction;
this.createSchema(db, transaction);
this.addContacts(db, transaction);
}.bind(this);
req.onsuccess = function() {
debug("succeeded opening the db, let's close it now");
req.result.close();
deferred.resolve(this.contactsCount());
}.bind(this);
req.onerror = function() {
deferred.reject(this.error);
};
return deferred.promise;
},
createSchema: function(db, transaction) {
debug("createSchema for version " + this.version);
this.data.SCHEMA(db, transaction);
},
addContacts: function(db, transaction) {
debug("adding contacts for version " + this.version);
var os = transaction.objectStore(STORE_NAME);
this.data.GOOD.forEach(function(contact) {
os.put(contact);
});
this.data.BAD.forEach(function(contact) {
os.put(contact);
});
},
contactsCount: function() {
return this.data.BAD.length + this.data.GOOD.length;
}
};
DataManager.delete = function() {
debug("Deleting the database");
var deferred = Promise.defer();
/* forcibly close the db before deleting it */
ContactService._db.close();
var req = indexedDB.deleteDatabase(DB_NAME);
req.onsuccess = function() {
debug("Successfully deleted!");
deferred.resolve();
};
req.onerror = function() {
debug("Not deleted, error is " + this.error.name);
deferred.reject(this.error);
};
req.onblocked = function() {
debug("Waiting for the current users");
};
return deferred.promise;
};
addMessageListener("createDB", function(version) {
// Promises help handling gracefully exceptions
Promise.resolve().then(function() {
return new DataManager(version);
}).then(function(manager) {
return manager.open();
}).then(function onSuccess(count) {
sendAsyncMessage("createDB.success", count);
}, function onError(err) {
sendAsyncMessage("createDB.error", "Failed to create the DB: " +
"(" + err.name + ") " + err.message);
});
});
addMessageListener("deleteDB", function() {
Promise.resolve().then(
DataManager.delete
).then(function onSuccess() {
sendAsyncMessage("deleteDB.success");
}, function onError(err) {
sendAsyncMessage("deleteDB.error", "Failed to delete the DB:" + err.name);
});
});

View File

@ -5,6 +5,10 @@
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const PREF_FXA_ENABLED = "identity.fxaccounts.enabled";
let _fxa_enabled = false;
try {
@ -18,9 +22,6 @@ const FXA_ENABLED = _fxa_enabled;
// This is the parent process corresponding to nsDOMIdentity.
this.EXPORTED_SYMBOLS = ["DOMIdentity"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
"resource://gre/modules/identity/IdentityUtils.jsm");

View File

@ -231,6 +231,15 @@ static void split(char* str, const char* sep, nsTArray<nsCString>& result)
}
}
static void split(char* str, const char* sep, nsTArray<nsString>& result)
{
char *s = strtok(str, sep);
while (s != nullptr) {
result.AppendElement(NS_ConvertUTF8toUTF16(s));
s = strtok(nullptr, sep);
}
}
/**
* Helper function that implement join function.
*/

View File

@ -75,12 +75,12 @@ public:
NetworkParams(const NetworkCommandOptions& aOther) {
#define COPY_SEQUENCE_FIELD(prop) \
#define COPY_SEQUENCE_FIELD(prop, type) \
if (aOther.prop.WasPassed()) { \
mozilla::dom::Sequence<nsString > const & currentValue = aOther.prop.InternalValue(); \
mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue(); \
uint32_t length = currentValue.Length(); \
for (uint32_t idx = 0; idx < length; idx++) { \
mHostnames.AppendElement(currentValue[idx]); \
prop.AppendElement(currentValue[idx]); \
} \
}
@ -110,7 +110,7 @@ public:
COPY_OPT_STRING_FIELD(mDns2_str, EmptyString())
COPY_OPT_STRING_FIELD(mGateway, EmptyString())
COPY_OPT_STRING_FIELD(mGateway_str, EmptyString())
COPY_SEQUENCE_FIELD(mHostnames)
COPY_SEQUENCE_FIELD(mHostnames, nsString)
COPY_OPT_STRING_FIELD(mIfname, EmptyString())
COPY_OPT_STRING_FIELD(mIp, EmptyString())
COPY_OPT_STRING_FIELD(mNetmask, EmptyString())
@ -128,7 +128,7 @@ public:
COPY_OPT_STRING_FIELD(mKey, EmptyString())
COPY_OPT_STRING_FIELD(mPrefix, EmptyString())
COPY_OPT_STRING_FIELD(mLink, EmptyString())
COPY_SEQUENCE_FIELD(mInterfaceList)
COPY_SEQUENCE_FIELD(mInterfaceList, nsString)
COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString())
COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString())
COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString())
@ -178,7 +178,7 @@ public:
nsString mKey;
nsString mPrefix;
nsString mLink;
nsTArray<nsCString> mInterfaceList;
nsTArray<nsString> mInterfaceList;
nsString mWifiStartIp;
nsString mWifiEndIp;
nsString mUsbStartIp;

View File

@ -926,13 +926,13 @@ XPCOMUtils.defineLazyGetter(this, "gDataConnectionManager", function () {
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN) {
let connHandler = this._connectionHandlers[this._currentDataClientId];
let radioInterface = connHandler.radioInterface;
if (!connHandler.allDataDisconnected() &&
if (connHandler.allDataDisconnected() &&
typeof this._pendingDataCallRequest === "function") {
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
radioInterface.setDataRegistration(false);
}
if (DEBUG) {
debug("All data calls disconnected, setup pending data call.");
this.debug("All data calls disconnected, setup pending data call.");
}
this._pendingDataCallRequest();
this._pendingDataCallRequest = null;