Backed out changeset 27695ca9f8cd (bug 1310864) for failures in test_navigator_resolve_identity.html, test_bug707564.html, and test_dom_xrays.html

This commit is contained in:
Phil Ringnalda 2016-10-31 19:39:06 -07:00
Родитель 62aec9f499
Коммит 16522e6c40
234 изменённых файлов: 37371 добавлений и 1 удалений

Просмотреть файл

@ -200,6 +200,7 @@ pref("privacy.item.syncAccount", true);
// base url for the wifi geolocation network provider
pref("geo.provider.use_mls", false);
pref("geo.cell.scan", true);
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
// base url for the stumbler

Просмотреть файл

@ -6,6 +6,7 @@
window.performance.mark('gecko-shell-loadstart');
Cu.import('resource://gre/modules/ContactService.jsm');
Cu.import('resource://gre/modules/NotificationDB.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import('resource://gre/modules/UserAgentOverrides.jsm');

Просмотреть файл

@ -157,7 +157,11 @@
@RESPATH@/components/dom_wifi.xpt
@RESPATH@/components/dom_system_gonk.xpt
#endif
#ifdef MOZ_B2G_RIL
@RESPATH@/components/dom_mobileconnection.xpt
#endif
@RESPATH@/components/dom_canvas.xpt
@RESPATH@/components/dom_contacts.xpt
@RESPATH@/components/dom_core.xpt
@RESPATH@/components/dom_css.xpt
@RESPATH@/components/dom_events.xpt
@ -333,6 +337,8 @@
@RESPATH@/components/BrowserElementParent.js
@RESPATH@/components/BrowserElementProxy.manifest
@RESPATH@/components/BrowserElementProxy.js
@RESPATH@/components/ContactManager.js
@RESPATH@/components/ContactManager.manifest
@RESPATH@/components/PhoneNumberService.js
@RESPATH@/components/PhoneNumberService.manifest
@RESPATH@/components/NotificationStorage.js
@ -444,6 +450,8 @@
#ifndef DISABLE_MOZ_RIL_GEOLOC
@RESPATH@/components/DataCallInterfaceService.js
@RESPATH@/components/DataCallInterfaceService.manifest
@RESPATH@/components/MobileConnectionService.js
@RESPATH@/components/MobileConnectionService.manifest
@RESPATH@/components/RadioInterfaceLayer.js
@RESPATH@/components/RadioInterfaceLayer.manifest
@RESPATH@/components/SmsService.js

Просмотреть файл

@ -193,6 +193,7 @@
@RESPATH@/components/dom_network.xpt
@RESPATH@/components/dom_notification.xpt
@RESPATH@/components/dom_html.xpt
@RESPATH@/components/dom_icc.xpt
@RESPATH@/components/dom_offline.xpt
@RESPATH@/components/dom_json.xpt
@RESPATH@/components/dom_power.xpt
@ -508,6 +509,8 @@
@RESPATH@/components/PermissionSettings.js
@RESPATH@/components/PermissionSettings.manifest
@RESPATH@/components/ContactManager.js
@RESPATH@/components/ContactManager.manifest
@RESPATH@/components/PhoneNumberService.js
@RESPATH@/components/PhoneNumberService.manifest
@RESPATH@/components/NotificationStorage.js

Просмотреть файл

@ -136,6 +136,11 @@ this.PermissionsTable = { geolocation: {
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
mobileconnection: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
mobilenetwork: {
app: DENY_ACTION,
privileged: ALLOW_ACTION,

Просмотреть файл

@ -40,6 +40,7 @@
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/FlyWebPublishedServer.h"
#include "mozilla/dom/FlyWebService.h"
#include "mozilla/dom/IccManager.h"
#include "mozilla/dom/InputPortManager.h"
#include "mozilla/dom/Permissions.h"
#include "mozilla/dom/Presentation.h"
@ -56,6 +57,9 @@
#include "Connection.h"
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
#include "nsGlobalWindow.h"
#ifdef MOZ_B2G_RIL
#include "mozilla/dom/MobileConnectionArray.h"
#endif
#include "nsIIdleObserver.h"
#include "nsIPermissionManager.h"
#include "nsMimeTypes.h"
@ -207,9 +211,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
#ifdef MOZ_B2G_RIL
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
#endif
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
#endif
@ -270,6 +278,11 @@ Navigator::Invalidate()
mPowerManager = nullptr;
}
if (mIccManager) {
mIccManager->Shutdown();
mIccManager = nullptr;
}
if (mInputPortManager) {
mInputPortManager = nullptr;
}
@ -279,6 +292,12 @@ Navigator::Invalidate()
mConnection = nullptr;
}
#ifdef MOZ_B2G_RIL
if (mMobileConnections) {
mMobileConnections = nullptr;
}
#endif
mMediaDevices = nullptr;
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
@ -1607,6 +1626,40 @@ Navigator::MozTCPSocket()
return socket.forget();
}
#ifdef MOZ_B2G_RIL
MobileConnectionArray*
Navigator::GetMozMobileConnections(ErrorResult& aRv)
{
if (!mMobileConnections) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
mMobileConnections = new MobileConnectionArray(mWindow);
}
return mMobileConnections;
}
#endif // MOZ_B2G_RIL
IccManager*
Navigator::GetMozIccManager(ErrorResult& aRv)
{
if (!mIccManager) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
mIccManager = new IccManager(mWindow);
}
return mIccManager;
}
#ifdef MOZ_GAMEPAD
void
Navigator::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads,

Просмотреть файл

@ -72,7 +72,12 @@ namespace network {
class Connection;
} // namespace network
#ifdef MOZ_B2G_RIL
class MobileConnectionArray;
#endif
class PowerManager;
class IccManager;
class InputPortManager;
class DeviceStorageAreaListener;
class Presentation;
@ -209,11 +214,15 @@ public:
ErrorResult& aRv);
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
IccManager* GetMozIccManager(ErrorResult& aRv);
InputPortManager* GetInputPortManager(ErrorResult& aRv);
already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
network::Connection* GetConnection(ErrorResult& aRv);
MediaDevices* GetMediaDevices(ErrorResult& aRv);
#ifdef MOZ_B2G_RIL
MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
#endif // MOZ_B2G_RIL
#ifdef MOZ_GAMEPAD
void GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
GamepadServiceTest* RequestGamepadServiceTest();
@ -302,8 +311,12 @@ private:
RefPtr<battery::BatteryManager> mBatteryManager;
RefPtr<Promise> mBatteryPromise;
RefPtr<PowerManager> mPowerManager;
RefPtr<IccManager> mIccManager;
RefPtr<InputPortManager> mInputPortManager;
RefPtr<network::Connection> mConnection;
#ifdef MOZ_B2G_RIL
RefPtr<MobileConnectionArray> mMobileConnections;
#endif
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
RefPtr<system::AudioChannelManager> mAudioChannelManager;
#endif

Просмотреть файл

@ -588,6 +588,48 @@ DOMInterfaces = {
'notflattened': True
},
'MozCdmaIccInfo': {
'headerFile': 'mozilla/dom/IccInfo.h',
'nativeType': 'mozilla::dom::CdmaIccInfo',
},
'MozGsmIccInfo': {
'headerFile': 'mozilla/dom/IccInfo.h',
'nativeType': 'mozilla::dom::GsmIccInfo',
},
'MozIcc': {
'nativeType': 'mozilla::dom::Icc',
},
'MozIccInfo': {
'nativeType': 'mozilla::dom::IccInfo',
},
'MozIccManager': {
'nativeType': 'mozilla::dom::IccManager',
},
'MozMobileCellInfo': {
'nativeType': 'mozilla::dom::MobileCellInfo',
},
'MozMobileConnection': {
'nativeType': 'mozilla::dom::MobileConnection',
},
'MozMobileConnectionArray': {
'nativeType': 'mozilla::dom::MobileConnectionArray',
},
'MozMobileConnectionInfo': {
'nativeType': 'mozilla::dom::MobileConnectionInfo',
},
'MozMobileNetworkInfo': {
'nativeType': 'mozilla::dom::MobileNetworkInfo',
},
'MozSpeakerManager': {
'nativeType': 'mozilla::dom::SpeakerManager',
'headerFile': 'SpeakerManager.h'

Просмотреть файл

@ -0,0 +1,541 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DEBUG = false;
function debug(s) { dump("-*- ContactManager: " + s + "\n"); }
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
XPCOMUtils.defineLazyServiceGetter(Services, "DOMRequest",
"@mozilla.org/dom/dom-request-service;1",
"nsIDOMRequestService");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
const CONTACTS_SENDMORE_MINIMUM = 5;
// We need this to create a copy of the mozContact object in ContactManager.save
// Keep in sync with the interfaces.
const PROPERTIES = [
"name", "honorificPrefix", "givenName", "additionalName", "familyName",
"phoneticGivenName", "phoneticFamilyName",
"honorificSuffix", "nickname", "photo", "category", "org", "jobTitle",
"bday", "note", "anniversary", "sex", "genderIdentity", "key", "adr", "email",
"url", "impp", "tel"
];
var mozContactInitWarned = false;
function Contact() { }
Contact.prototype = {
__init: function(aProp) {
for (let prop in aProp) {
this[prop] = aProp[prop];
}
},
init: function(aProp) {
// init is deprecated, warn once in the console if it's used
if (!mozContactInitWarned) {
mozContactInitWarned = true;
Cu.reportError("mozContact.init is DEPRECATED. Use the mozContact constructor instead. " +
"See https://developer.mozilla.org/docs/WebAPI/Contacts for details.");
}
for (let prop of PROPERTIES) {
this[prop] = aProp[prop];
}
},
setMetadata: function(aId, aPublished, aUpdated) {
this.id = aId;
if (aPublished) {
this.published = aPublished;
}
if (aUpdated) {
this.updated = aUpdated;
}
},
classID: Components.ID("{72a5ee28-81d8-4af8-90b3-ae935396cc66}"),
contractID: "@mozilla.org/contact;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
};
function ContactManager() { }
ContactManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
hasListenPermission: false,
_cachedContacts: [] ,
set oncontactchange(aHandler) {
this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
},
get oncontactchange() {
return this.__DOM_IMPL__.getEventHandler("oncontactchange");
},
_convertContact: function(aContact) {
let properties = aContact.properties;
if (properties.photo && properties.photo.length) {
properties.photo = Cu.cloneInto(properties.photo, this._window);
}
let newContact = new this._window.mozContact(aContact.properties);
newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
return newContact;
},
_convertContacts: function(aContacts) {
let contacts = new this._window.Array();
for (let i in aContacts) {
contacts.push(this._convertContact(aContacts[i]));
}
return contacts;
},
_fireSuccessOrDone: function(aCursor, aResult) {
if (aResult == null) {
Services.DOMRequest.fireDone(aCursor);
} else {
Services.DOMRequest.fireSuccess(aCursor, aResult);
}
},
_pushArray: function(aArr1, aArr2) {
aArr1.push.apply(aArr1, aArr2);
},
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage: " + aMessage.name);
let msg = aMessage.json;
let contacts = msg.contacts;
let req;
switch (aMessage.name) {
case "Contacts:Find:Return:OK":
req = this.getRequest(msg.requestID);
if (req) {
let result = this._convertContacts(contacts);
Services.DOMRequest.fireSuccess(req.request, result);
} else {
if (DEBUG) debug("no request stored!" + msg.requestID);
}
break;
case "Contacts:GetAll:Next":
let data = this.getRequest(msg.cursorId);
if (!data) {
break;
}
let result = contacts ? this._convertContacts(contacts) : [null];
if (data.waitingForNext) {
if (DEBUG) debug("cursor waiting for contact, sending");
data.waitingForNext = false;
let contact = result.shift();
this._pushArray(data.cachedContacts, result);
this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
if (!contact) {
this.removeRequest(msg.cursorId);
}
} else {
if (DEBUG) debug("cursor not waiting, saving");
this._pushArray(data.cachedContacts, result);
}
break;
case "Contact:Save:Return:OK":
// If a cached contact was saved and a new contact ID was returned, update the contact's ID
if (this._cachedContacts[msg.requestID]) {
if (msg.contactID) {
this._cachedContacts[msg.requestID].id = msg.contactID;
}
delete this._cachedContacts[msg.requestID];
}
case "Contacts:Clear:Return:OK":
case "Contact:Remove:Return:OK":
req = this.getRequest(msg.requestID);
if (req)
Services.DOMRequest.fireSuccess(req.request, null);
break;
case "Contacts:Find:Return:KO":
case "Contact:Save:Return:KO":
case "Contact:Remove:Return:KO":
case "Contacts:Clear:Return:KO":
case "Contacts:GetRevision:Return:KO":
case "Contacts:Count:Return:KO":
req = this.getRequest(msg.requestID);
if (req) {
if (req.request) {
req = req.request;
}
Services.DOMRequest.fireError(req, msg.errorMsg);
}
break;
case "Contacts:GetAll:Return:KO":
req = this.getRequest(msg.requestID);
if (req) {
Services.DOMRequest.fireError(req.cursor, msg.errorMsg);
}
break;
case "Contact:Changed":
// Fire oncontactchange event
if (DEBUG) debug("Contacts:ContactChanged: " + msg.contactID + ", " + msg.reason);
let event = new this._window.MozContactChangeEvent("contactchange", {
contactID: msg.contactID,
reason: msg.reason
});
this.dispatchEvent(event);
break;
case "Contacts:Revision":
if (DEBUG) debug("new revision: " + msg.revision);
req = this.getRequest(msg.requestID);
if (req) {
Services.DOMRequest.fireSuccess(req.request, msg.revision);
}
break;
case "Contacts:Count":
if (DEBUG) debug("count: " + msg.count);
req = this.getRequest(msg.requestID);
if (req) {
Services.DOMRequest.fireSuccess(req.request, msg.count);
}
break;
default:
if (DEBUG) debug("Wrong message: " + aMessage.name);
}
this.removeRequest(msg.requestID);
},
dispatchEvent: function(event) {
if (this.hasListenPermission) {
this.__DOM_IMPL__.dispatchEvent(event);
}
},
askPermission: function (aAccess, aRequest, aAllowCallback, aCancelCallback) {
if (DEBUG) debug("askPermission for contacts");
let access;
switch(aAccess) {
case "create":
access = "create";
break;
case "update":
case "remove":
access = "write";
break;
case "find":
case "listen":
case "revision":
case "count":
access = "read";
break;
default:
access = "unknown";
}
// Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
let principal = this._window.document.nodePrincipal;
let type = "contacts-" + access;
let permValue =
Services.perms.testExactPermissionFromPrincipal(principal, type);
DEBUG && debug("Existing permission " + permValue);
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
if (aAllowCallback) {
aAllowCallback();
}
return;
} else if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
if (aCancelCallback) {
aCancelCallback("PERMISSION_DENIED");
}
return;
}
// Create an array with a single nsIContentPermissionType element.
type = {
type: "contacts",
access: access,
options: [],
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
principal: principal,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
allow: function() {
aAllowCallback && aAllowCallback();
DEBUG && debug("Permission granted. Access " + access +"\n");
},
cancel: function() {
aCancelCallback && aCancelCallback("PERMISSION_DENIED");
DEBUG && debug("Permission denied. Access " + access +"\n");
},
window: this._window
};
// Using askPermission from nsIDOMWindowUtils that takes care of the
// remoting if needed.
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.askPermission(request);
},
save: function save(aContact) {
// We have to do a deep copy of the contact manually here because
// nsFrameMessageManager doesn't know how to create a structured clone of a
// mozContact object.
let newContact = {properties: {}};
try {
for (let field of PROPERTIES) {
// This hack makes sure modifications to the sequence attributes get validated.
aContact[field] = aContact[field];
newContact.properties[field] = aContact[field];
}
} catch (e) {
// And then make sure we throw a proper error message (no internal file and line #)
throw new this._window.Error(e.message);
}
let request = this.createRequest();
let requestID = this.getRequestId({request: request});
let reason;
if (aContact.id == "undefined") {
// for example {25c00f01-90e5-c545-b4d4-21E2ddbab9e0} becomes
// 25c00f0190e5c545b4d421E2ddbab9e0
aContact.id = this._getRandomId().replace(/[{}-]/g, "");
// Cache the contact so that its ID may be updated later if necessary
this._cachedContacts[requestID] = aContact;
reason = "create";
} else {
reason = "update";
}
newContact.id = aContact.id;
newContact.published = aContact.published;
newContact.updated = aContact.updated;
if (DEBUG) debug("send: " + JSON.stringify(newContact));
let options = { contact: newContact, reason: reason };
let allowCallback = function() {
cpmm.sendAsyncMessage("Contact:Save", {
requestID: requestID,
options: options
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission(reason, request, allowCallback, cancelCallback);
return request;
},
find: function(aOptions) {
if (DEBUG) debug("find! " + JSON.stringify(aOptions));
let request = this.createRequest();
let options = { findOptions: aOptions };
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:Find", {
requestID: this.getRequestId({request: request, reason: "find"}),
options: options
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission("find", request, allowCallback, cancelCallback);
return request;
},
createCursor: function CM_createCursor(aRequest) {
let data = {
cursor: Services.DOMRequest.createCursor(this._window, function() {
this.handleContinue(id);
}.bind(this)),
cachedContacts: [],
waitingForNext: true,
};
let id = this.getRequestId(data);
if (DEBUG) debug("saved cursor id: " + id);
return [id, data.cursor];
},
getAll: function CM_getAll(aOptions) {
if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));
let [cursorId, cursor] = this.createCursor();
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:GetAll", {
cursorId: cursorId,
findOptions: aOptions
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(cursor, reason);
};
this.askPermission("find", cursor, allowCallback, cancelCallback);
return cursor;
},
nextTick: function nextTick(aCallback) {
Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
},
handleContinue: function CM_handleContinue(aCursorId) {
if (DEBUG) debug("handleContinue: " + aCursorId);
let data = this.getRequest(aCursorId);
if (data.cachedContacts.length > 0) {
if (DEBUG) debug("contact in cache");
let contact = data.cachedContacts.shift();
this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
if (!contact) {
this.removeRequest(aCursorId);
} else if (data.cachedContacts.length === CONTACTS_SENDMORE_MINIMUM) {
cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
}
} else {
if (DEBUG) debug("waiting for contact");
data.waitingForNext = true;
}
},
remove: function removeContact(aRecordOrId) {
let request = this.createRequest();
let id;
if (typeof aRecordOrId === "string") {
id = aRecordOrId;
} else if (!aRecordOrId || !aRecordOrId.id) {
Services.DOMRequest.fireErrorAsync(request, true);
return request;
} else {
id = aRecordOrId.id;
}
let options = { id: id };
let allowCallback = function() {
cpmm.sendAsyncMessage("Contact:Remove", {
requestID: this.getRequestId({request: request, reason: "remove"}),
options: options
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission("remove", request, allowCallback, cancelCallback);
return request;
},
clear: function() {
if (DEBUG) debug("clear");
let request = this.createRequest();
let options = {};
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:Clear", {
requestID: this.getRequestId({request: request, reason: "remove"}),
options: options
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission("remove", request, allowCallback, cancelCallback);
return request;
},
getRevision: function() {
let request = this.createRequest();
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:GetRevision", {
requestID: this.getRequestId({ request: request })
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission("revision", request, allowCallback, cancelCallback);
return request;
},
getCount: function() {
let request = this.createRequest();
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:GetCount", {
requestID: this.getRequestId({ request: request })
});
}.bind(this);
let cancelCallback = function(reason) {
Services.DOMRequest.fireErrorAsync(request, reason);
};
this.askPermission("count", request, allowCallback, cancelCallback);
return request;
},
init: function(aWindow) {
// DOMRequestIpcHelper.initHelper sets this._window
this.initDOMRequestHelper(aWindow, ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
"Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
"Contact:Save:Return:OK", "Contact:Save:Return:KO",
"Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
"Contact:Changed",
"Contacts:GetAll:Next", "Contacts:GetAll:Return:KO",
"Contacts:Count",
"Contacts:Revision", "Contacts:GetRevision:Return:KO",]);
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:RegisterForMessages");
this.hasListenPermission = true;
}.bind(this);
this.askPermission("listen", null, allowCallback);
},
classID: Components.ID("{8beb3a66-d70a-4111-b216-b8e995ad3aff}"),
contractID: "@mozilla.org/contactManager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
Ci.nsIObserver,
Ci.nsIDOMGlobalPropertyInitializer]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
Contact, ContactManager
]);

Просмотреть файл

@ -0,0 +1,5 @@
component {72a5ee28-81d8-4af8-90b3-ae935396cc66} ContactManager.js
contract @mozilla.org/contact;1 {72a5ee28-81d8-4af8-90b3-ae935396cc66}
component {8beb3a66-d70a-4111-b216-b8e995ad3aff} ContactManager.js
contract @mozilla.org/contactManager;1 {8beb3a66-d70a-4111-b216-b8e995ad3aff}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,266 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DEBUG = false;
function debug(s) { dump("-*- Fallback ContactService component: " + s + "\n"); }
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
this.EXPORTED_SYMBOLS = ["ContactService"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContactDB",
"resource://gre/modules/ContactDB.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PhoneNumberUtils",
"resource://gre/modules/PhoneNumberUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
var ContactService = this.ContactService = {
init: function() {
if (DEBUG) debug("Init");
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
"Contacts:Clear", "Contact:Save",
"Contact:Remove", "Contacts:RegisterForMessages",
"child-process-shutdown", "Contacts:GetRevision",
"Contacts:GetCount"];
this._children = [];
this._cursors = new Map();
this._messages.forEach(function(msgName) {
ppmm.addMessageListener(msgName, this);
}.bind(this));
this._db = new ContactDB();
this._db.init();
this.configureSubstringMatching();
Services.obs.addObserver(this, "profile-before-change", false);
Services.prefs.addObserver("ril.lastKnownSimMcc", this, false);
},
observe: function(aSubject, aTopic, aData) {
if (aTopic === 'profile-before-change') {
this._messages.forEach(function(msgName) {
ppmm.removeMessageListener(msgName, this);
}.bind(this));
Services.obs.removeObserver(this, "profile-before-change");
Services.prefs.removeObserver("dom.phonenumber.substringmatching", this);
ppmm = null;
this._messages = null;
if (this._db)
this._db.close();
this._db = null;
this._children = null;
this._cursors = null;
} else if (aTopic === 'nsPref:changed' && aData === "ril.lastKnownSimMcc") {
this.configureSubstringMatching();
}
},
configureSubstringMatching: function() {
let countryName = PhoneNumberUtils.getCountryName();
if (Services.prefs.getPrefType("dom.phonenumber.substringmatching." + countryName) == Ci.nsIPrefBranch.PREF_INT) {
let val = Services.prefs.getIntPref("dom.phonenumber.substringmatching." + countryName);
if (val) {
this._db.enableSubstringMatching(val);
return;
}
}
// if we got here, we dont have a substring setting
// for this country, so disable substring matching
this._db.disableSubstringMatching();
},
assertPermission: function(aMessage, aPerm) {
if (!aMessage.target.assertPermission(aPerm)) {
Cu.reportError("Contacts message " + aMessage.name +
" from a content process with no" + aPerm + " privileges.");
return false;
}
return true;
},
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
this._children.forEach(function(msgMgr) {
msgMgr.sendAsyncMessage(aMsgName, aContent);
});
},
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage " + aMessage.name);
let mm = aMessage.target;
let msg = aMessage.data;
let cursorList;
switch (aMessage.name) {
case "Contacts:Find":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
let result = [];
this._db.find(
function(contacts) {
for (let i in contacts) {
result.push(contacts[i]);
}
if (DEBUG) debug("result:" + JSON.stringify(result));
mm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this),
msg.options.findOptions);
break;
case "Contacts:GetAll":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
cursorList = this._cursors.get(mm);
if (!cursorList) {
cursorList = [];
this._cursors.set(mm, cursorList);
}
cursorList.push(msg.cursorId);
this._db.getAll(
function(aContacts) {
try {
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
if (aContacts === null) {
let cursorList = this._cursors.get(mm);
let index = cursorList.indexOf(msg.cursorId);
cursorList.splice(index, 1);
}
} catch (e) {
if (DEBUG) debug("Child is dead, DB should stop sending contacts");
throw e;
}
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetAll:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); },
msg.findOptions, msg.cursorId);
break;
case "Contacts:GetAll:SendNow":
// sendNow is a no op if there isn't an existing cursor in the DB, so we
// don't need to assert the permission again.
this._db.sendNow(msg.cursorId);
break;
case "Contact:Save":
if (msg.options.reason === "create") {
if (!this.assertPermission(aMessage, "contacts-create")) {
return null;
}
} else {
if (!this.assertPermission(aMessage, "contacts-write")) {
return null;
}
}
this._db.saveContact(
msg.options.contact,
function() {
mm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.options.contact.id });
this.broadcastMessage("Contact:Changed", { contactID: msg.options.contact.id, reason: msg.options.reason });
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
);
break;
case "Contact:Remove":
if (!this.assertPermission(aMessage, "contacts-write")) {
return null;
}
this._db.removeContact(
msg.options.id,
function() {
mm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.options.id });
this.broadcastMessage("Contact:Changed", { contactID: msg.options.id, reason: "remove" });
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
);
break;
case "Contacts:Clear":
if (!this.assertPermission(aMessage, "contacts-write")) {
return null;
}
this._db.clear(
function() {
mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID });
this.broadcastMessage("Contact:Changed", { reason: "remove" });
}.bind(this),
function(aErrorMsg) {
mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
}.bind(this)
);
break;
case "Contacts:GetRevision":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
this._db.getRevision(
function(revision) {
mm.sendAsyncMessage("Contacts:Revision", {
requestID: msg.requestID,
revision: revision
});
},
function(aErrorMsg) {
mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
}.bind(this)
);
break;
case "Contacts:GetCount":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
this._db.getCount(
function(count) {
mm.sendAsyncMessage("Contacts:Count", {
requestID: msg.requestID,
count: count
});
},
function(aErrorMsg) {
mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
}.bind(this)
);
break;
case "Contacts:RegisterForMessages":
if (!aMessage.target.assertPermission("contacts-read")) {
return null;
}
if (DEBUG) debug("Register!");
if (this._children.indexOf(mm) == -1) {
this._children.push(mm);
}
break;
case "child-process-shutdown":
if (DEBUG) debug("Unregister");
let index = this._children.indexOf(mm);
if (index != -1) {
if (DEBUG) debug("Unregister index: " + index);
this._children.splice(index, 1);
}
cursorList = this._cursors.get(mm);
if (cursorList) {
for (let id of cursorList) {
this._db.clearDispatcher(id);
}
this._cursors.delete(mm);
}
break;
default:
if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
}
}
}
ContactService.init();

20
dom/contacts/moz.build Normal file
Просмотреть файл

@ -0,0 +1,20 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Disable the tests on Android for now (bug 927869)
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
EXTRA_COMPONENTS += [
'ContactManager.js',
'ContactManager.manifest',
]
EXTRA_JS_MODULES += [
'fallback/ContactDB.jsm',
'fallback/ContactService.jsm'
]

Просмотреть файл

@ -0,0 +1,44 @@
[DEFAULT]
skip-if = toolkit == 'android' # Bug 1287455: takes too long to complete on Android
support-files =
shared.js
file_contacts_basics.html
file_contacts_basics2.html
file_contacts_blobs.html
file_contacts_events.html
file_contacts_getall.html
file_contacts_getall2.html
file_contacts_international.html
file_contacts_substringmatching.html
file_contacts_substringmatchingVE.html
file_contacts_substringmatchingCL.html
test_migration_chrome.js
file_migration.html
# renaming with "_a_" to execure before others, since we hardcode open of
# database and this messes up with mozContacts when done after mozContacts
# did opened the database. those should really be xpcshell and not chrome
# mochitests maybe ...
[test_contacts_a_shutdown.xul]
skip-if = buildapp == 'b2g'
[test_contacts_a_upgrade.xul]
skip-if = buildapp == 'b2g'
[test_contacts_a_cache.xul]
skip-if = buildapp == 'b2g'
[test_contacts_basics.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_contacts_basics2.html]
skip-if = (toolkit == 'gonk' && debug) || (os == 'win' && os_version == '5.1') #debug-only failure, bug 967258 on XP
[test_contacts_blobs.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_contacts_events.html]
[test_contacts_getall.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_contacts_getall2.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_contacts_international.html]
[test_contacts_substringmatching.html]
[test_contacts_substringmatchingVE.html]
[test_contacts_substringmatchingCL.html]
[test_migration.html]
support-files +=

Просмотреть файл

@ -0,0 +1,787 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=674720
-->
<head>
<title>Test for Bug 674720 WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var is = parent.is;
var initialRev;
function checkRevision(revision, msg, then) {
var revReq = mozContacts.getRevision();
revReq.onsuccess = function(e) {
is(e.target.result, initialRev+revision, msg);
then();
};
// The revision function isn't supported on Android so treat on failure as success
if (isAndroid) {
revReq.onerror = function(e) {
then();
};
} else {
revReq.onerror = onFailure;
}
}
var req;
var steps = [
function() {
req = mozContacts.getRevision();
req.onsuccess = function(e) {
initialRev = e.target.result;
next();
};
// Android does not support the revision function. Treat errors as success.
if (isAndroid) {
req.onerror = function(e) {
initialRev = 0;
next();
};
} else {
req.onerror = onFailure;
}
},
function () {
ok(true, "Deleting database");
checkRevision(0, "Initial revision is 0", function() {
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
checkCount(0, "No contacts after clear", function() {
checkRevision(1, "Revision was incremented on clear", next);
});
};
req.onerror = onFailure;
});
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find(defaultOptions);
req.onsuccess = function () {
is(req.result.length, 0, "Empty database.");
checkRevision(1, "Revision was not incremented on find", next);
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding empty contact");
createResult1 = new mozContact({});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkCount(1, "1 contact after adding empty contact", function() {
checkRevision(2, "Revision was incremented on save", next);
});
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find(defaultOptions);
req.onsuccess = function () {
is(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting empty contact");
req = navigator.mozContacts.remove(findResult1);
req.onsuccess = function () {
var req2 = mozContacts.find(defaultOptions);
req2.onsuccess = function () {
is(req2.result.length, 0, "Empty Database.");
clearTemps();
checkRevision(3, "Revision was incremented on remove", next);
}
req2.onerror = onFailure;
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact1");
createResult1 = new mozContact(properties1);
mozContacts.oncontactchange = function(event) {
is(event.contactID, createResult1.id, "Same contactID");
is(event.reason, "create", "Same reason");
next();
}
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkContacts(createResult1, properties1);
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 1");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[1].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
// Some manual testing. Testint the testfunctions
// tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}],
is(findResult1.tel[0].carrier, "testCarrier", "Same Carrier");
is(String(findResult1.tel[0].type), "work", "Same type");
is(findResult1.tel[0].value, "123456", "Same Value");
is(findResult1.tel[1].type[1], "fax", "Same type");
is(findResult1.tel[1].value, "+55 (31) 9876-3456", "Same Value");
is(findResult1.adr[0].countryName, "country 1", "Same country");
// email: [{type: ["work"], value: "x@y.com"}]
is(String(findResult1.email[0].type), "work", "Same Type");
is(findResult1.email[0].value, "x@y.com", "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for exact email");
var options = {filterBy: ["email"],
filterOp: "equals",
filterValue: properties1.email[0].value};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring and update");
mozContacts.oncontactchange = function(event) {
is(event.contactID, findResult1.id, "Same contactID");
is(event.reason, "update", "Same reason");
}
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
findResult1.jobTitle = ["new Job"];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact");
mozContacts.oncontactchange = function(event) {
is(event.contactID, createResult2.id, "Same contactID");
is(event.reason, "create", "Same reason");
}
createResult2 = new mozContact({name: ["newName"]});
req = navigator.mozContacts.save(createResult2);
req.onsuccess = function () {
ok(createResult2.id, "The contact now has an ID.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 2");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
checkContacts(createResult1, findResult1);
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Retrieving by name equality 1");
var options = {filterBy: ["name"],
filterOp: "equals",
filterValue: properties1.name[0]};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
checkContacts(createResult1, findResult1);
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Retrieving by name equality 2");
var options = {filterBy: ["name"],
filterOp: "equals",
filterValue: properties1.name[1]};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
checkContacts(createResult1, findResult1);
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Retrieving by name substring 1");
var options = {filterBy: ["name"],
filterOp: "startsWith",
filterValue: properties1.name[0].substring(0,3).toLowerCase()};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
checkContacts(createResult1, findResult1);
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Retrieving by name substring 2");
var options = {filterBy: ["name"],
filterOp: "startsWith",
filterValue: properties1.name[1].substring(0,3).toLowerCase()};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
checkContacts(createResult1, findResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Remove contact1");
mozContacts.oncontactchange = function(event) {
is(event.contactID, createResult1.id, "Same contactID");
is(event.reason, "remove", "Same reason");
}
req = navigator.mozContacts.remove(createResult1);
req.onsuccess = function () {
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 3");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[1].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found no contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Remove contact2");
mozContacts.oncontactchange = function(event) {
is(event.contactID, createResult2.id, "Same contactID");
is(event.reason, "remove", "Same reason");
}
req = navigator.mozContacts.remove(createResult2);
req.onsuccess = function () {
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 4");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[1].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found no contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
mozContacts.oncontactchange = function(event) {
is(event.contactID, "undefined", "Same contactID");
is(event.reason, "remove", "Same reason");
}
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with properties1");
createResult1 = new mozContact(properties1);
mozContacts.oncontactchange = null;
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring tel1");
var options = {filterBy: ["tel"],
filterOp: "contains",
filterValue: properties1.tel[1].value.substring(2,5)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel exact");
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: "+55 319 8 7 6 3456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel exact with substring");
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: "3456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found no contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel exact with substring");
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: "+55 (31)"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found no contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel match national number");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "3198763456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel match national format");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "0451 491934"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel match entered number");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "123456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by tel match international number");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "+55 31 98763456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by match with field other than tel");
var options = {filterBy: ["givenName"],
filterOp: "match",
filterValue: "my friends call me 555-4040"};
req = mozContacts.find(options);
req.onsuccess = onUnwantedSuccess;
req.onerror = function() {
ok(true, "Failed");
next();
}
},
function () {
ok(true, "Retrieving by substring tel2");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: "9876"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring tel3");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: "98763456"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 5");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 6");
var options = {filterBy: ["familyName", "givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring3, Testing multi entry");
var options = {filterBy: ["givenName", "familyName"],
filterOp: "startsWith",
filterValue: properties1.familyName[1].substring(0,3).toLowerCase()};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find(defaultOptions);
req.onsuccess = function() {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(createResult1, findResult1);
if (!isAndroid) {
ok(findResult1.updated, "Has updated field");
ok(findResult1.published, "Has published field");
}
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Modifying contact1");
if (!findResult1) {
SpecialPowers.executeSoon(next);
} else {
findResult1.impp = properties1.impp = [{value:"phil impp"}];
req = navigator.mozContacts.save(findResult1);
req.onsuccess = function () {
var req2 = mozContacts.find(defaultOptions);
req2.onsuccess = function() {
is(req2.result.length, 1, "Found exactly 1 contact.");
findResult2 = req2.result[0];
ok(findResult2.id == sample_id1, "Same ID");
checkContacts(findResult2, properties1);
is(findResult2.impp.length, 1, "Found exactly 1 IMS info.");
next();
};
req2.onerror = onFailure;
};
req.onerror = onFailure;
}
},
function() {
// Android does not support published/updated fields. Skip this.
if (isAndroid) {
next();
return;
}
ok(true, "Saving old contact, should abort!");
req = mozContacts.save(createResult1);
req.onsuccess = onUnwantedSuccess;
req.onerror = function() { ok(true, "Successfully declined updating old contact!"); next(); };
},
function () {
ok(true, "Retrieving a specific contact by ID");
var options = {filterBy: ["id"],
filterOp: "equals",
filterValue: sample_id1};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving a specific contact by givenName");
var options = {filterBy: ["givenName"],
filterOp: "equals",
filterValue: properties1.givenName[0]};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Modifying contact2");
if (!findResult1) {
SpecialPowers.executeSoon(next);
} else {
findResult1.impp = properties1.impp = [{value: "phil impp"}];
req = mozContacts.save(findResult1);
req.onsuccess = function () {
var req2 = mozContacts.find(defaultOptions);
req2.onsuccess = function () {
is(req2.result.length, 1, "Found exactly 1 contact.");
findResult1 = req2.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
is(findResult1.impp.length, 1, "Found exactly 1 IMS info.");
next();
}
req2.onerror = onFailure;
};
req.onerror = onFailure;
}
},
function () {
ok(true, "Searching contacts by query");
var options = {filterBy: ["givenName", "email"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,4)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching contacts by query");
var options = {filterBy: ["givenName", "email"],
filterOp: "startsWith",
filterValue: properties1.givenName[0]};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching contacts with multiple indices");
var options = {filterBy: ["email", "givenName"],
filterOp: "equals",
filterValue: properties1.givenName[1]};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, properties1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Modifying contact3");
if (!findResult1) {
SpecialPowers.executeSoon(next);
} else {
findResult1.email = [{value: properties1.nickname}];
findResult1.nickname = ["TEST"];
var newContact = new mozContact(findResult1);
req = mozContacts.save(newContact);
req.onsuccess = function () {
var options = {filterBy: ["email", "givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0]};
// One contact has it in nickname and the other in email
var req2 = mozContacts.find(options);
req2.onsuccess = function () {
is(req2.result.length, 2, "Found exactly 2 contacts.");
ok(req2.result[0].id != req2.result[1].id, "Different ID");
next();
}
req2.onerror = onFailure;
};
req.onerror = onFailure;
}
},
function () {
ok(true, "Deleting contact" + findResult1);
req = mozContacts.remove(findResult1);
req.onsuccess = function () {
var req2 = mozContacts.find(defaultOptions);
req2.onsuccess = function () {
is(req2.result.length, 1, "One contact left.");
findResult1 = req2.result[0];
next();
}
req2.onerror = onFailure;
}
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.remove(findResult1);
req.onsuccess = function () {
clearTemps();
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Test JSON.stringify output for mozContact objects");
var json = JSON.parse(JSON.stringify(new mozContact(properties1)));
checkContacts(json, properties1);
next();
},
function() {
ok(true, "Test slice");
var c = new mozContact();
c.email = [{ type: ["foo"], value: "bar@baz" }]
var arr = c.email;
is(arr[0].value, "bar@baz", "Should have the right value");
arr = arr.slice();
is(arr[0].value, "bar@baz", "Should have the right value after slicing");
next();
},
function () {
ok(true, "all done!\n");
clearTemps();
parent.SimpleTest.finish();
}
];
start_tests();
</script>
</pre>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,226 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=674720
-->
<head>
<title>Test for Bug 674720 WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var is = parent.is;
var isnot = parent.isnot;
var utils = SpecialPowers.getDOMWindowUtils(window);
function getView(size)
{
var buffer = new ArrayBuffer(size);
var view = new Uint8Array(buffer);
is(buffer.byteLength, size, "Correct byte length");
return view;
}
function getRandomView(size)
{
var view = getView(size);
for (var i = 0; i < size; i++) {
view[i] = parseInt(Math.random() * 255)
}
return view;
}
function getRandomBlob(size)
{
return new Blob([getRandomView(size)], { type: "binary/random" });
}
function compareBuffers(buffer1, buffer2)
{
if (buffer1.byteLength != buffer2.byteLength) {
return false;
}
var view1 = new Uint8Array(buffer1);
var view2 = new Uint8Array(buffer2);
for (var i = 0; i < buffer1.byteLength; i++) {
if (view1[i] != view2[i]) {
return false;
}
}
return true;
}
function verifyBuffers(buffer1, buffer2, isLast)
{
ok(compareBuffers(buffer1, buffer2), "Correct blob data");
if (isLast)
next();
}
var randomBlob = getRandomBlob(1024);
var randomBlob2 = getRandomBlob(1024);
var properties1 = {
name: ["xTestname1"],
givenName: ["xTestname1"],
photo: [randomBlob]
};
var properties2 = {
name: ["yTestname2"],
givenName: ["yTestname2"],
photo: [randomBlob, randomBlob2]
};
var sample_id1;
var createResult1;
var findResult1;
function verifyBlob(blob1, blob2, isLast)
{
is(blob1 instanceof Blob, true,
"blob1 is an instance of DOMBlob");
is(blob2 instanceof Blob, true,
"blob2 is an instance of DOMBlob");
isnot(blob1 instanceof File, true,
"blob1 is an instance of File");
isnot(blob2 instanceof File, true,
"blob2 is an instance of File");
is(blob1.size, blob2.size, "Same size");
is(blob1.type, blob2.type, "Same type");
var buffer1;
var buffer2;
var reader1 = new FileReader();
reader1.readAsArrayBuffer(blob2);
reader1.onload = function(event) {
buffer2 = event.target.result;
if (buffer1) {
verifyBuffers(buffer1, buffer2, isLast);
}
}
var reader2 = new FileReader();
reader2.readAsArrayBuffer(blob1);
reader2.onload = function(event) {
buffer1 = event.target.result;
if (buffer2) {
verifyBuffers(buffer1, buffer2, isLast);
}
}
}
function verifyBlobArray(blobs1, blobs2)
{
is(blobs1 instanceof Array, true, "blobs1 is an array object");
is(blobs2 instanceof Array, true, "blobs2 is an array object");
is(blobs1.length, blobs2.length, "Same length");
if (!blobs1.length) {
next();
return;
}
for (var i = 0; i < blobs1.length; i++) {
verifyBlob(blobs1[i], blobs2[i], i == blobs1.length - 1);
}
}
var req;
var steps = [
function () {
ok(true, "Deleting database");
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact with photo");
createResult1 = new mozContact(properties1);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties1.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
verifyBlobArray(findResult1.photo, properties1.photo);
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact with 2 photos");
createResult1 = new mozContact(properties2);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring");
var options = {filterBy: ["givenName"],
filterOp: "startsWith",
filterValue: properties2.givenName[0].substring(0,3)};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
verifyBlobArray(findResult1.photo, properties2.photo);
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
start_tests();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=764667
-->
<head>
<title>Test for Bug 678695</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=764667">Mozilla Bug 764667</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 764667 **/
var ok = parent.ok;
var is = parent.is;
var e = new MozContactChangeEvent("contactchanged", {contactID: "123", reason: "create"});
ok(e, "Should have contactsChange event!");
is(e.contactID, "123", "ID should be 123.");
is(e.reason, "create", "Reason should be create.");
e = new MozContactChangeEvent("contactchanged", {contactID: "test", reason: "test"});
is(e.contactID, "test", "Name should be 'test'.");
is(e.reason, "test", "Name should be 'test'.");
e = new MozContactChangeEvent("contactchanged", {contactID: "a", reason: ""});
is(e.contactID, "a", "Name should be a.");
is(e.reason, "", "Value should be empty");
parent.SimpleTest.finish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,156 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=836519
-->
<head>
<title>Mozilla Bug 836519</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836519">Mozilla Bug 836519</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript;version=1.8">
"use strict";
var ok = parent.ok;
var is = parent.is;
var isnot = parent.isnot;
let req;
let steps = [
function start() {
SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_START");
next();
},
clearDatabase,
addContacts,
function() {
ok(true, "Delete the current contact while iterating");
req = mozContacts.getAll({});
let count = 0;
let previousId = null;
req.onsuccess = function() {
if (req.result) {
ok(true, "on success");
if (previousId) {
isnot(previousId, req.result.id, "different contacts returned");
}
previousId = req.result.id;
count++;
let delReq = mozContacts.remove(req.result);
delReq.onsuccess = function() {
ok(true, "deleted current contact");
req.continue();
};
} else {
is(count, 40, "returned 40 contacts");
next();
}
};
},
clearDatabase,
addContacts,
function() {
ok(true, "Iterating through the contact list inside a cursor callback");
let count1 = 0, count2 = 0;
let req1 = mozContacts.getAll({});
let req2;
req1.onsuccess = function() {
if (count1 == 0) {
count1++;
req2 = mozContacts.getAll({});
req2.onsuccess = function() {
if (req2.result) {
count2++;
req2.continue();
} else {
is(count2, 40, "inner cursor returned 40 contacts");
req1.continue();
}
};
} else {
if (req1.result) {
count1++;
req1.continue();
} else {
is(count1, 40, "outer cursor returned 40 contacts");
next();
}
}
};
},
clearDatabase,
addContacts,
function() {
ok(true, "20 concurrent cursors");
const NUM_CURSORS = 20;
let completed = 0;
for (let i = 0; i < NUM_CURSORS; ++i) {
mozContacts.getAll({}).onsuccess = (function(i) {
let count = 0;
return function(event) {
let req = event.target;
if (req.result) {
count++;
req.continue();
} else {
is(count, 40, "cursor " + i + " returned 40 contacts");
if (++completed == NUM_CURSORS) {
next();
}
}
};
})(i);
}
},
clearDatabase,
addContacts,
function() {
if (!SpecialPowers.isMainProcess()) {
// We stop calling continue() intentionally here to see if the cursor gets
// cleaned up properly in the parent.
ok(true, "Leaking a cursor");
req = mozContacts.getAll({
sortBy: "familyName",
sortOrder: "ascending"
});
req.onsuccess = function(event) {
next();
};
req.onerror = onFailure;
} else {
next();
}
},
clearDatabase,
function() {
ok(true, "all done!\n");
SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_END");
parent.SimpleTest.finish();
}
];
start_tests();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=836519
-->
<head>
<title>Mozilla Bug 836519</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836519">Mozilla Bug 836519</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript;version=1.8">
"use strict";
var ok = parent.ok;
var is = parent.is;
let req;
let steps = [
clearDatabase,
function() {
// add a contact
createResult1 = new mozContact({});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function() {
next();
};
req.onerror = onFailure;
},
getOne(),
getOne("Retrieving one contact with getAll - cached"),
clearDatabase,
addContacts,
getAll(),
getAll("Retrieving 40 contacts with getAll - cached"),
function() {
ok(true, "Deleting one contact");
req = mozContacts.remove(createResult1);
req.onsuccess = function() {
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Test cache invalidation");
req = mozContacts.getAll({});
let count = 0;
req.onsuccess = function(event) {
ok(true, "on success");
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 39, "last contact - 39 contacts returned");
next();
}
};
req.onerror = onFailure;
},
clearDatabase,
addContacts,
function() {
ok(true, "Test cache consistency when deleting contact during getAll");
req = mozContacts.find({});
req.onsuccess = function(e) {
let lastContact = e.target.result[e.target.result.length-1];
req = mozContacts.getAll({});
let count = 0;
let firstResult = true;
req.onsuccess = function(event) {
ok(true, "on success");
if (firstResult) {
if (req.result) {
count++;
}
let delReq = mozContacts.remove(lastContact);
delReq.onsuccess = function() {
firstResult = false;
req.continue();
};
} else {
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 40, "last contact - 40 contacts returned");
next();
}
}
};
};
},
clearDatabase,
function() {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
start_tests();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,277 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815833
-->
<head>
<title>Test for Bug 815833 WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815833">Mozilla Bug 815833</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var ise = parent.ise;
var number1 = {
local: "7932012345",
international: "+557932012345"
};
var number2 = {
local: "7932012346",
international: "+557932012346"
};
var properties1 = {
name: ["Testname1"],
tel: [{type: ["work"], value: number1.local, carrier: "testCarrier"} , {type: ["home", "fax"], value: number2.local}],
};
var shortNumber = "888";
var properties2 = {
name: ["Testname2"],
tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}]
};
var number3 = {
local: "7932012345",
international: "+557932012345"
};
var properties3 = {
name: ["Testname2"],
tel: [{value: number3.international}]
};
var req;
var createResult1;
var findResult1;
var sample_id1;
var steps = [
function () {
ok(true, "Deleting database");
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact1");
createResult1 = new mozContact(properties1);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact2");
var createResult2 = new mozContact(properties2);
req = navigator.mozContacts.save(createResult2);
req.onsuccess = function () {
ok(createResult2.id, "The contact now has an ID.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number1.local};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for international number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number1.international};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 0 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching the prefix");
var shortNumber = number1.local.substring(0, 3);
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
is(req.result.length, 0, "The prefix short number should not match any contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching the suffix");
var shortNumber = number1.local.substring(number1.local.length - 3);
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
is(req.result.length, 0, "The suffix short number should not match any contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for a short number matching a contact");
var options = {filterBy: ["tel"],
filterOp: "equals",
filterValue: shortNumber};
req = mozContacts.find(options);
req.onsuccess = function() {
is(req.result.length, 1, "Found the contact equally matching the shortNumber.");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Modifying number");
if (!findResult1) {
SpecialPowers.executeSoon(next);
} else {
findResult1.tel[0].value = number2.local;
req = mozContacts.save(findResult1);
req.onsuccess = function () {
next();
};
}
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number1.local};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 0 contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number1.international};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 0 contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number2.local};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for local number");
var options = {filterBy: ["tel"],
filterOp: "startsWith",
filterValue: number2.international};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 1 contact.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a contact with a Brazilian country code");
createResult1 = new mozContact(properties3);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for Brazilian number using local number");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: number3.local};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
SpecialPowers.pushPrefEnv({
set: [
["ril.lastKnownSimMcc", "000"]
]
}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,351 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877302
-->
<head>
<title>Test for Bug 877302 substring matching for WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877302">Mozilla Bug 877302</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var is = parent.is;
var substringLength = 8;
var prop = {
tel: [{value: "7932012345" }, {value: "7932012346"}]
};
var prop2 = {
tel: [{value: "01187654321" }]
};
var prop3 = {
tel: [{ value: "+43332112346" }]
};
var prop4 = {
tel: [{ value: "(0414) 233-9888" }]
};
var brazilianNumber = {
international1: "0041557932012345",
international2: "+557932012345"
};
var prop5 = {
tel: [{value: brazilianNumber.international2}]
};
var req;
var steps = [
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
is(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 1");
var length = prop.tel[0].value.length;
var num = prop.tel[0].value.substring(length - substringLength, length);
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
is(findResult1.tel[0].value, "7932012345", "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 2");
var length = prop.tel[1].value.length;
var num = prop.tel[1].value.substring(length - substringLength, length);
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
is(findResult1.tel[0].value, "7932012345", "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 3");
var length = prop.tel[0].value.length;
var num = prop.tel[0].value.substring(length - substringLength + 1, length);
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 0 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 4");
var length = prop.tel[0].value.length;
var num = prop.tel[0].value.substring(length - substringLength - 1, length);
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop2);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 5");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "87654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 6");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "01187654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 7");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "909087654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 8");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "0411187654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 9");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "90411187654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 10");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: "+551187654321"};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop3);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
if (!isAndroid) { // Bug 905927
ok(true, "Retrieving by substring 1");
var length = prop3.tel[0].value.length;
var num = prop3.tel[0].value.substring(length - substringLength, length);
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly 0 contacts.");
next();
};
req.onerror = onFailure;
} else {
SpecialPowers.executeSoon(next);
}
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop4);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 1");
var num = "(0424) 233-9888"
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contacts.");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with a Brazilian country code");
createResult1 = new mozContact(prop5);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for international number with prefix");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: brazilianNumber.international1};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
SpecialPowers.pushPrefEnv({
set: [
["dom.phonenumber.substringmatching.BR", substringLength],
["ril.lastKnownSimMcc", "724"]
]
}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,207 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877302
-->
<head>
<title>Test for Bug 949537 substring matching for WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=949537">Mozilla Bug 949537</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var ise = parent.ise;
var landlineNumber = "+56 2 27654321";
var number = {
local: "87654321",
international: "+56 9 87654321"
};
var properties = {
name: ["Testname2"],
tel: [{value: number.international}]
};
var req;
var steps = [
function () {
ok(true, "Adding a contact with a Chilean number");
createResult1 = new mozContact(properties);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for Chilean number with prefix");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international
});
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for Chilean number using local number");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.local
});
req.onsuccess = function () {
is(req.result.length, 1, "Found 0 contacts.");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding contact with mobile number");
createResult1 = new mozContact({tel: [{value: number.international}]});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
is(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 8 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-8)
});
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
is(findResult1.tel[0].value, number.international, "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 9 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-9)
});
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
is(findResult1.tel[0].value, number.international, "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 6 digits");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: number.international.slice(-6)
});
req.onsuccess = function () {
is(req.result.length, 0, "Found exactly zero contacts.");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding contact with landline number");
createResult1 = new mozContact({tel: [{value: landlineNumber}]});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
is(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by last 7 digits (local number) with landline calling prefix");
req = mozContacts.find({
filterBy: ["tel"],
filterOp: "match",
filterValue: "022" + landlineNumber.slice(-7)
});
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.id, sample_id1, "Same ID");
is(findResult1.tel[0].value, landlineNumber, "Same Value");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
SpecialPowers.pushPrefEnv({
set: [
["dom.phonenumber.substringmatching.CL", 8],
["ril.lastKnownSimMcc", "730"]
]
}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,135 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877302
-->
<head>
<title>Test for Bug 877302 substring matching for WebContacts</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877302">Mozilla Bug 877302</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
<script class="testbody" type="text/javascript">
"use strict";
var ok = parent.ok;
var is = parent.is;
var prop = {
tel: [{value: "7932012345" }, {value: "7704143727591"}]
};
var prop2 = {
tel: [{value: "7932012345" }, {value: "+58 212 5551212"}]
};
var req;
var steps = [
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({});
req.onsuccess = function () {
is(req.result.length, 1, "One contact.");
findResult1 = req.result[0];
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 1");
var length = prop.tel[0].value.length;
var num = "04143727591"
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
is(findResult1.tel[1].value, "7704143727591", "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding contact");
createResult1 = new mozContact(prop2);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring 2");
var num = "5551212";
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: num};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
is(findResult1.tel[1].value, "+58 212 5551212", "Same Value");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
parent.SimpleTest.finish();
}
];
SpecialPowers.pushPrefEnv({
set: [
["dom.phonenumber.substringmatching.VE", 7],
["ril.lastKnownSimMcc", "734"]
]
}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,197 @@
<!DOCTYPE html>
<html>
<head>
<title>Migration tests</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/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 ok = parent.ok;
var ise = parent.ise;
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");
}
var steps = [
function setupChromeScript() {
loadChromeScript();
addBackendEvents();
next();
},
deleteDB, // let's be sure the DB does not exist yet
createDB.bind(null, 12),
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");
is(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) {
is(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,
function finish() {
backend.destroy();
info("all done!\n");
parent.SimpleTest.finish();
}
];
// this is the Mcc for Brazil, so that we trigger the previous pref
SpecialPowers.pushPrefEnv({"set": [["dom.phonenumber.substringmatching.BR", 7],
["ril.lastKnownSimMcc", "724"]]}, start_tests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1081873
-->
<head>
<title>Test for Bug 1081873</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>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081873">Mozilla Bug 1081873</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict";
parent.is("mozContacts" in navigator, false, "navigator.mozContacts must be inaccessible");
parent.SimpleTest.finish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,6 @@
[DEFAULT]
support-files =
shared.js
file_permission_denied.html
[test_permission_denied.html]

Просмотреть файл

@ -0,0 +1,503 @@
"use strict";
// Fix the environment to run Contacts tests
SpecialPowers.importInMainProcess("resource://gre/modules/ContactService.jsm");
// Some helpful global vars
var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
var defaultOptions = {
sortBy: "givenName",
};
// Make sure we only touch |navigator.mozContacts| after we have the necessary
// permissions, or we'll race when checking the listen permission needed for the
// oncontactchange event. This is only needed for tests because at first we have
// the permission set to UNKNOWN_ACTION. That should never happen for real apps,
// see dom/apps/PermissionsTable.jsm.
var mozContacts;
// To test sorting
var c1 = {
name: ["a a"],
familyName: ["a"],
givenName: ["a"],
};
var c2 = {
name: ["b b"],
familyName: ["b"],
givenName: ["b"],
};
var c3 = {
name: ["c c", "a a", "b b"],
familyName: ["c","a","b"],
givenName: ["c","a","b"],
};
var c4 = {
name: ["c c", "a a", "c c"],
familyName: ["c","a","c"],
givenName: ["c","a","c"],
};
var c5 = {
familyName: [],
givenName: [],
};
var c6 = {
name: ["e"],
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var c7 = {
name: ["e"],
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var c8 = {
name: ["e"],
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var adr1 = {
type: ["work"],
streetAddress: "street 1",
locality: "locality 1",
region: "region 1",
postalCode: "postal code 1",
countryName: "country 1"
};
var adr2 = {
type: ["home, fax"],
streetAddress: "street2",
locality: "locality2",
region: "region2",
postalCode: "postal code2",
countryName: "country2"
};
var properties1 = {
// please keep capital letters at the start of these names
name: ["Test1 TestFamilyName", "Test2 Wagner"],
familyName: ["TestFamilyName","Wagner"],
givenName: ["Test1","Test2"],
phoneticFamilyName: ["TestphoneticFamilyName1","TestphoneticFamilyName2"],
phoneticGivenName: ["TestphoneticGivenName1","TestphoneticGivenName2"],
nickname: ["nicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
email: [{type: ["work"], value: "x@y.com"}],
};
var properties2 = {
name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyFamilyName"],
givenName: ["dummyGivenName"],
phoneticFamilyName: ["dummyphoneticFamilyName"],
phoneticGivenName: ["dummyphoneticGivenName"],
honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
honorificSuffix: ["dummyHonorificSuffix"],
additionalName: ["dummyadditionalName"],
nickname: ["dummyNickname"],
tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
adr: [adr1, adr2],
impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
org: ["org1", "org2"],
jobTitle: ["boss", "superboss"],
note: ["test note"],
category: ["cat1", "cat2"],
url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
bday: new Date("1980, 12, 01"),
anniversary: new Date("2000, 12, 01"),
sex: "male",
genderIdentity: "test",
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
// To test sorting(CJK)
var c9 = {
phoneticFamilyName: ["a"],
phoneticGivenName: ["a"],
};
var c10 = {
phoneticFamilyName: ["b"],
phoneticGivenName: ["b"],
};
var c11 = {
phoneticFamilyName: ["c","a","b"],
phoneticGivenName: ["c","a","b"],
};
var c12 = {
phoneticFamilyName: ["c","a","c"],
phoneticGivenName: ["c","a","c"],
};
var c13 = {
phoneticFamilyName: [],
phoneticGivenName: [],
};
var c14 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c15 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c16 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var properties3 = {
// please keep capital letters at the start of these names
name: ["Taro Yamada", "Ichiro Suzuki"],
familyName: ["Yamada","Suzuki"],
givenName: ["Taro","Ichiro"],
phoneticFamilyName: ["TestPhoneticFamilyYamada","TestPhoneticFamilySuzuki"],
phoneticGivenName: ["TestPhoneticGivenTaro","TestPhoneticGivenIchiro"],
nickname: ["phoneticNicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
email: [{type: ["work"], value: "x@y.com"}],
};
var properties4 = {
name: ["dummyHonorificPrefix dummyTaro dummyYamada dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyYamada"],
givenName: ["dummyTaro"],
phoneticFamilyName: ["dummyTestPhoneticFamilyYamada"],
phoneticGivenName: ["dummyTestPhoneticGivenTaro"],
honorificPrefix: ["dummyPhoneticHonorificPrefix","dummyPhoneticHonorificPrefix2"],
honorificSuffix: ["dummyPhoneticHonorificSuffix"],
additionalName: ["dummyPhoneticAdditionalName"],
nickname: ["dummyPhoneticNickname"],
tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
adr: [adr1, adr2],
impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
org: ["org1", "org2"],
jobTitle: ["boss", "superboss"],
note: ["test note"],
category: ["cat1", "cat2"],
url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
bday: new Date("1980, 12, 01"),
anniversary: new Date("2000, 12, 01"),
sex: "male",
genderIdentity: "test",
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
var sample_id1;
var sample_id2;
var createResult1;
var createResult2;
var findResult1;
var findResult2;
// DOMRequest helper functions
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
ok(false, "in on Failure!");
next();
}
// Validation helper functions
function checkStr(str1, str2, msg) {
if (str1 ^ str2) {
ok(false, "Expected both strings to be either present or absent");
return;
}
if (!str1 || str1 == "null") {
str1 = null;
}
if (!str2 || str2 == "null") {
str2 = null;
}
is(str1, str2, msg);
}
function checkStrArray(str1, str2, msg) {
function normalize_falsy(v) {
if (!v || v == "null" || v == "undefined") {
return "";
}
return v;
}
function optArray(val) {
return Array.isArray(val) ? val : [val];
}
str1 = optArray(str1).map(normalize_falsy).filter(v => v != "");
str2 = optArray(str2).map(normalize_falsy).filter(v => v != "");
is(JSON.stringify(str1), JSON.stringify(str2), msg);
}
function checkPref(pref1, pref2) {
// If on Android treat one preference as 0 and the other as undefined as matching
if (isAndroid) {
if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
pref1 = false;
pref2 = false;
}
}
is(!!pref1, !!pref2, "Same pref");
}
function checkAddress(adr1, adr2) {
if (adr1 ^ adr2) {
ok(false, "Expected both adrs to be either present or absent");
return;
}
checkStrArray(adr1.type, adr2.type, "Same type");
checkStr(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
checkStr(adr1.locality, adr2.locality, "Same locality");
checkStr(adr1.region, adr2.region, "Same region");
checkStr(adr1.postalCode, adr2.postalCode, "Same postalCode");
checkStr(adr1.countryName, adr2.countryName, "Same countryName");
checkPref(adr1.pref, adr2.pref);
}
function checkField(field1, field2) {
if (field1 ^ field2) {
ok(false, "Expected both fields to be either present or absent");
return;
}
checkStrArray(field1.type, field2.type, "Same type");
checkStr(field1.value, field2.value, "Same value");
checkPref(field1.pref, field2.pref);
}
function checkTel(tel1, tel2) {
if (tel1 ^ tel2) {
ok(false, "Expected both tels to be either present or absent");
return;
}
checkField(tel1, tel2);
checkStr(tel1.carrier, tel2.carrier, "Same carrier");
}
function checkCategory(category1, category2) {
// Android adds contacts to the a default category. This should be removed from the
// results before comparing them
if (isAndroid) {
category1 = removeAndroidDefaultCategory(category1);
category2 = removeAndroidDefaultCategory(category2);
}
checkStrArray(category1, category2, "Same Category")
}
function removeAndroidDefaultCategory(category) {
if (!category) {
return category;
}
var result = [];
for (var i of category) {
// Some devices may return the full group name (prefixed with "System Group: ")
if (i != "My Contacts" && i != "System Group: My Contacts") {
result.push(i);
}
}
return result;
}
function checkArrayField(array1, array2, func, msg) {
if (!!array1 ^ !!array2) {
ok(false, "Expected both arrays to be either present or absent: " + JSON.stringify(array1) + " vs. " + JSON.stringify(array2) + ". (" + msg + ")");
return;
}
if (!array1 && !array2) {
ok(true, msg);
return;
}
is(array1.length, array2.length, "Same length");
for (var i = 0; i < array1.length; ++i) {
func(array1[i], array2[i], msg);
}
}
function checkContacts(contact1, contact2) {
if (!!contact1 ^ !!contact2) {
ok(false, "Expected both contacts to be either present or absent");
return;
}
checkStrArray(contact1.name, contact2.name, "Same name");
checkStrArray(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
checkStrArray(contact1.phoneticFamilyName, contact2.phoneticFamilyName, "Same phoneticFamilyName");
checkStrArray(contact1.phoneticGivenName, contact2.phoneticGivenName, "Same phoneticGivenName");
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
checkCategory(contact1.category, contact2.category);
checkStrArray(contact1.org, contact2.org, "Same org");
checkStrArray(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
checkStrArray(contact1.note, contact2.note, "Same note");
is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
checkStr(contact1.sex, contact2.sex, "Same sex");
checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
checkStrArray(contact1.key, contact2.key, "Same key");
checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
checkArrayField(contact1.email, contact2.email, checkField, "Same email");
checkArrayField(contact1.url, contact2.url, checkField, "Same url");
checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
}
function addContacts() {
ok(true, "Adding 40 contacts");
let req;
for (let i = 0; i < 39; ++i) {
properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
properties1.name = [properties1.givenName[0] + " " + properties1.familyName[0]];
createResult1 = new mozContact(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
ok(createResult1.id, "The contact now has an ID.");
};
req.onerror = onFailure;
};
properties1.familyName[0] = "Testname39";
properties1.name = [properties1.givenName[0] + " Testname39"];
createResult1 = new mozContact(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
ok(createResult1.id, "The contact now has an ID.");
checkStrArray(createResult1.name, properties1.name, "Same Name");
next();
};
req.onerror = onFailure;
}
function getOne(msg) {
return function() {
ok(true, msg || "Retrieving one contact with getAll");
let req = mozContacts.getAll({});
let count = 0;
req.onsuccess = function(event) {
ok(true, "on success");
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 1, "last contact - only one contact returned");
next();
}
};
req.onerror = onFailure;
};
}
function getAll(msg) {
return function() {
ok(true, msg || "Retrieving 40 contacts with getAll");
let req = mozContacts.getAll({
sortBy: "familyName",
sortOrder: "ascending"
});
let count = 0;
let result;
let props;
req.onsuccess = function(event) {
if (req.result) {
ok(true, "result is valid");
result = req.result;
properties1.familyName[0] = "Testname" + (count < 10 ? "0" + count : count);
is(result.familyName[0], properties1.familyName[0], "Same familyName");
count++;
req.continue();
} else {
is(count, 40, "last contact - 40 contacts returned");
next();
}
};
req.onerror = onFailure;
};
}
function clearTemps() {
sample_id1 = null;
sample_id2 = null;
createResult1 = null;
createResult2 = null;
findResult1 = null;
findResult2 = null;
}
function clearDatabase() {
ok(true, "Deleting database");
let req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
}
function checkCount(count, msg, then) {
var request = mozContacts.getCount();
request.onsuccess = function(e) {
is(e.target.result, count, msg);
then();
};
request.onerror = onFailure;
}
// Helper functions to run tests
var index = 0;
function next() {
info("Step " + index);
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
var i = index++;
steps[i]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
SimpleTest.waitForExplicitFinish();
function start_tests() {
// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
let androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
.getService(SpecialPowers.Ci.nsIPropertyBag2)
.getProperty('version');
if (!isAndroid || androidVersion >= 14) {
mozContacts = navigator.mozContacts;
next();
} else {
ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
parent.SimpleTest.finish();
}
}

Просмотреть файл

@ -0,0 +1,168 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<window title="Mozilla Bug 1114520"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript;version=1.7">
<![CDATA[
"use strict";
const { 'utils': Cu } = Components;
Cu.import("resource://gre/modules/ContactDB.jsm", window);
let contactsDB = new ContactDB();
contactsDB.init();
function makeFailure(reason, skipDelete) {
return function() {
ok(false, reason);
if (skipDelete) {
SimpleTest.finish();
return;
}
deleteDatabase(SimpleTest.finish);
};
};
function deleteDatabase(then) {
contactsDB.close();
let req = indexedDB.deleteDatabase(DB_NAME);
req.onsuccess = then;
req.onblocked = makeFailure("blocked", true);
req.onupgradeneeded = makeFailure("onupgradeneeded", true);
req.onerror = makeFailure("onerror", true);
};
function checkRevision(expectedRevision, then) {
contactsDB.getRevision(function(revision) {
ok(expectedRevision === revision, "Revision OK");
then();
}, makeFailure("Could not get revision"));
};
let CONTACT_PROPS = {
id: "ab74671e36be41b680f8f030e7e24ea2",
properties: {
name: ["Magnificentest foo bar the third"],
givenName: ["foo"],
familyName: ["bar"]
}
};
let ANOTHER_CONTACT_PROPS = {
id: "b461d53d548b4e8aaa8256911a415f79",
properties: {
name: ["Magnificentest foo bar the fourth"],
givenName: ["foo"],
familyName: ["bar"]
}
};
let Tests = [function() {
info("Deleting database");
deleteDatabase(next);
}, function() {
info("Checking initial revision");
checkRevision(0, next);
}, function() {
info("Save contact");
contactsDB.saveContact(CONTACT_PROPS, function() {
ok(true, "Saved contact successfully");
checkRevision(1, next);
}, makeFailure("Could not save contact"));
}, function() {
info("Save another contact");
contactsDB.saveContact(ANOTHER_CONTACT_PROPS, function() {
ok(true, "Saved contact successfully");
checkRevision(2, next);
}, makeFailure("Could not save contact"));
}, function() {
info("Get all contacts so cache is built");
contactsDB.getAll(function(contacts) {
ok(true, "Got all contacts " + contacts.length);
next();
}, makeFailure("Unexpected error getting contacts"), {
"sortBy":"givenName","sortOrder":"ascending"
});
}, function() {
info("Contacts cache should have both ids");
let contactsCount = 0;
contactsDB.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
store.openCursor().onsuccess = function(e) {
let cursor = e.target.result;
if (!cursor) {
makeFailure("Wrong cache")();
return;
}
ok(cursor.value.length == 2, "Both contacts ids are in the cache");
next();
};
}, null, makeFailure("Txn error"));
}, function() {
info("Remove contact " + CONTACT_PROPS.id);
contactsDB.removeContact(CONTACT_PROPS.id, function() {
ok(true, "Removed contact");
checkRevision(3, next);
}, makeFailure("Unexpected error removing contact "));
}, function() {
info("Check that contact has been removed for good");
contactsDB.newTxn("readonly", STORE_NAME, function(txn, store) {
let req = store.openCursor(IDBKeyRange.only(CONTACT_PROPS.id));
req.onsuccess = function(event) {
if (event.target.result) {
makeFailure("Should not have cursor")();
return;
}
ok(true, "Yep, the contact was removed");
next();
};
req.onerror = makeFailure("OpenCursor error");
});
}, function() {
info("Contacts cache should have only one id");
contactsDB.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
store.openCursor().onsuccess = function(e) {
let cursor = e.target.result;
if (!cursor) {
makeFailure("Missing cursor")();
return;
}
ok(cursor.value.length == 1, "Only one contacts id is in the cache");
ok(cursor.value[0] == ANOTHER_CONTACT_PROPS.id, "And it is the right id");
next();
};
}, null, makeFailure("Txn error"));
}, function() {
deleteDatabase(next);
}];
function next() {
let step = Tests.shift();
if (step) {
step();
} else {
info("All done");
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
next();
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114520"
target="_blank">Mozilla Bug 1114520</a>
</body>
</window>

Просмотреть файл

@ -0,0 +1,103 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<window title="Mozilla Bug 945948"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript;version=1.7">
<![CDATA[
"use strict";
const { 'utils': Cu } = Components;
Cu.import("resource://gre/modules/ContactService.jsm", window);
//
// Mock message manager
//
function MockMessageManager() { }
MockMessageManager.prototype.assertPermission = function() { return true; };
MockMessageManager.prototype.sendAsyncMessage = function(name, data) { };
//
// Mock ContactDB
//
function MockContactDB() { }
MockContactDB.prototype.getAll = function(cb) {
cb([]);
};
MockContactDB.prototype.clearDispatcher = function() { }
MockContactDB.prototype.close = function() { }
let realContactDB = ContactService._db;
function before() {
ok(true, "Install mock ContactDB object");
ContactService._db = new MockContactDB();
}
function after() {
ok(true, "Restore real ContactDB object");
ContactService._db = realContactDB;
}
function steps() {
let mm1 = new MockMessageManager();
let mm2 = new MockMessageManager();
is(ContactService._cursors.size, 0, "Verify clean contact init");
ContactService.receiveMessage({
target: mm1,
name: "Contacts:GetAll",
data: { cursorId: 1 },
findOptions: {}
});
is(ContactService._cursors.size, 1, "Add contact cursor 1");
ContactService.receiveMessage({
target: mm2,
name: "Contacts:GetAll",
data: { cursorId: 2 },
findOptions: {}
});
is(ContactService._cursors.size, 2, "Add contact cursor 2");
ContactService.receiveMessage({
target: mm1,
name: "child-process-shutdown"
});
is(ContactService._cursors.size, 1, "Shutdown contact cursor 1");
ContactService.receiveMessage({
target: mm2,
name: "child-process-shutdown"
});
is(ContactService._cursors.size, 0, "Shutdown contact cursor 2");
}
function runTests() {
SimpleTest.waitForExplicitFinish();
try {
before();
steps();
} finally {
after();
SimpleTest.finish();
}
}
runTests();
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=945948"
target="_blank">Mozilla Bug 945948</a>
</body>
</window>

Просмотреть файл

@ -0,0 +1,271 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<window title="Mozilla Bug 889239"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript;version=1.7">
<![CDATA[
"use strict";
function checkStr(str1, str2, msg) {
if (str1 ^ str2) {
ok(false, "Expected both strings to be either present or absent");
return;
}
is(str1, str2, msg);
}
function checkStrArray(str1, str2, msg) {
// comparing /[null(,null)+]/ and undefined should pass
function nonNull(e) {
return e != null;
}
if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
ok(true, msg);
} else if (str1) {
is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
}
}
function checkAddress(adr1, adr2) {
if (adr1 ^ adr2) {
ok(false, "Expected both adrs to be either present or absent");
return;
}
checkStrArray(adr1.type, adr2.type, "Same type");
checkStrArray(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
checkStrArray(adr1.locality, adr2.locality, "Same locality");
checkStrArray(adr1.region, adr2.region, "Same region");
checkStrArray(adr1.postalCode, adr2.postalCode, "Same postalCode");
checkStrArray(adr1.countryName, adr2.countryName, "Same countryName");
is(adr1.pref, adr2.pref, "Same pref");
}
function checkTel(tel1, tel2) {
if (tel1 ^ tel2) {
ok(false, "Expected both tels to be either present or absent");
return;
}
checkStrArray(tel1.type, tel2.type, "Same type");
checkStrArray(tel1.value, tel2.value, "Same value");
checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
is(tel1.pref, tel2.pref, "Same pref");
}
function checkField(field1, field2) {
if (field1 ^ field2) {
ok(false, "Expected both fields to be either present or absent");
return;
}
checkStrArray(field1.type, field2.type, "Same type");
checkStrArray(field1.value, field2.value, "Same value");
is(field1.pref, field2.pref, "Same pref");
}
function checkDBContacts(dbContact1, dbContact2) {
let contact1 = dbContact1.properties;
let contact2 = dbContact2.properties;
checkStrArray(contact1.name, contact2.name, "Same name");
checkStrArray(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
checkStrArray(contact1.category, contact2.category, "Same category");
checkStrArray(contact1.org, contact2.org, "Same org");
checkStrArray(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
checkStrArray(contact1.note, contact2.note, "Same note");
is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
checkStr(contact1.sex, contact2.sex, "Same sex");
checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
checkStrArray(contact1.key, contact2.key, "Same key");
is(contact1.email.length, contact2.email.length, "Same number of emails");
for (let i = 0; i < contact1.email.length; ++i) {
checkField(contact1.email[i], contact2.email[i]);
}
is(contact1.adr.length, contact2.adr.length, "Same number of adrs");
for (var i in contact1.adr) {
checkAddress(contact1.adr[i], contact2.adr[i]);
}
is(contact1.tel.length, contact2.tel.length, "Same number of tels");
for (var i in contact1.tel) {
checkTel(contact1.tel[i], contact2.tel[i]);
}
is(contact1.url.length, contact2.url.length, "Same number of urls");
for (var i in contact1.url) {
checkField(contact1.url[i], contact2.url[i]);
}
is(contact1.impp.length, contact2.impp.length, "Same number of impps");
for (var i in contact1.impp) {
checkField(contact1.impp[i], contact2.impp[i]);
}
// test search indexes
contact1 = dbContact1.search;
contact2 = dbContact2.search;
checkStrArray(contact1.category, contact2.category, "Same cateogry index");
checkStrArray(contact1.email, contact2.email, "Same email index");
checkStrArray(contact1.emailLowerCase, contact2.emailLowerCase, "Same emailLowerCase index");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName index");
checkStrArray(contact1.familyNameLowerCase, contact2.familyNameLowerCase, "Same familyNameLowerCase index");
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName index");
checkStrArray(contact1.givenNameLowerCase, contact2.givenNameLowerCase, "Same givenNameLowerCase index");
checkStrArray(contact1.name, contact2.name, "Same name index");
checkStrArray(contact1.tel, contact2.tel, "Same tel index");
checkStrArray(contact1.telLowerCase, contact2.telLowerCase, "Same telLowerCase index");
checkStrArray(contact1.telMatch, contact2.telMatch, "Same telMatch index");
}
function makeFailure(reason) {
return function() {
ok(false, reason);
SimpleTest.finish();
};
};
const { 'utils': Cu } = Components;
Cu.import("resource://gre/modules/ContactDB.jsm", window);
let cdb = new ContactDB();
cdb.init();
let CONTACT_PROPS = {
id: "ab74671e36be41b680f8f030e7e24ea2",
properties: {
name: ["Magnificentest foo bar the third"],
givenName: ["foo"],
familyName: ["bar"],
honorificPrefix: ["magnificentest"],
honorificSuffix: ["the third"],
additionalName: ["addl"],
nickname: ["foo"],
tel: [
{type: ["mobile"], value: "+12345678901", carrier: "ACME Telecommunications", pref: true},
{type: ["home", "custom"], value: "7932012346", pref: false},
],
email: [{type: ["work"], value: "a@b.c"}, {value: "b@c.d", pref: true}],
adr: [
{
type: ["home"],
streetAddress: "street 1",
locality: "locality 1",
region: "region 1",
postalCode: "postal code 1",
countryName: "country 1",
}
],
impp: [{type: ["aim"], value:"im1", pref: true}, {value: "im2"}],
org: ["org1", "org2"],
jobTitle: ["boss", "superboss"],
bday: new Date("1980, 12, 01"),
note: ["bla bla bla"],
category: ["cat1", "cat2"],
url: [{type: ["work", "work2"], value: "www.1.com", pref: true}, {value: "www2.com"}],
anniversary: new Date("2000, 12, 01"),
sex: "male",
genderIdentity: "trisexual",
key: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAC4jAAAuIwF4pT92AAACrElEQVQozwXBTW8bRRgA4Hfemf1er7/iJI4Tq7VFlEZN1VZIlapy4MQBTkXcuSH+G/APKnGAAyCVCqmtCHETp64db5zdtdf7NbMzw/OQH378HkCZpmmapqYMy8yrNnadS6026HC/Z7k+SCkEBwKEEKaUQtQAmlDqrucH23nH4BRkJVRcwmod5gcn6LehFgCaEIIalFZaEcLCq73w355RdvY7nfGQGVTlmRXfqMlrUaSUMUQkhCISJIggKj3/YBHt7PRbpy+cwbF7dN/0vEqTMoo3s0tmGAAAoJAgImMq3xZ5WTPbHj4Mho8Nf+QcPtZBLxEkqeQ2WmklkRCtNdNaI1KpVCnqOC3j5ZK++4vnm6xSWZpzwQtRV2mOiBoRpEKtNQAQggjQcCwqinRxJeKlWW93dlqEsa2QRZbF85nWBAAZY4YUgl9fRJWKVuWgmhwHhpD1+ZrfVjAN867rMCne//rq7OuXjWaLCVHnOWHgFDwMw+Tvi09PdhtJXoVC7bWDIi8Lg8qyMk3rYjLzvJh2O30hwK6TpiG7zWDcck9GR17D9wxDcH7/oNtElRa1aZuLDJN4S7/87tssLVg0/eZs/3h0D5R89vR0v+1AVT0YHX31ZDy9uv7IeJrryeyu2+nS50/PqOXM5qt8Nf/jv08UwTfN27vkchldLpPf/nx/nqSz5sbzhkTYzLRppzNYre/ycrMIZwqsHdf96fd/Xr354AYBr/jESWhgGb6zVSuGrrQS1j4Zk8nc2Hs7frFb3Phc6+fOKDGLKOJTHvlj2u85N4t6vbw7OM4YRVquboPdsPNZ9eb8pvfAOf2iN4dN3EzWadnoO5JY19Oo0TYtw1t8TBqBR9v7wbOXROLWtZ3PH937+ZfXrb6BUHEbXL+FCIfDw92e5zebg8GR54r/AaMVcBxE6hgPAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTA3LTIxVDEwOjUzOjE5LTA0OjAwYyXbYgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0wNy0yMVQxMDo1MzoxOS0wNDowMBJ4Y94AAAARdEVYdGpwZWc6Y29sb3JzcGFjZQAyLHVVnwAAACB0RVh0anBlZzpzYW1wbGluZy1mYWN0b3IAMXgxLDF4MSwxeDHplfxwAAAAAElFTkSuQmCC"
}
};
function deleteDatabase(then) {
cdb.close();
let req = indexedDB.deleteDatabase(DB_NAME);
req.onsuccess = then;
req.onblocked = makeFailure("blocked");
req.onupgradeneeded = makeFailure("onupgradeneeded");
req.onerror = makeFailure("onerror");
}
function saveContact() {
// takes fast upgrade path
cdb.saveContact(CONTACT_PROPS,
function() {
ok(true, "Saved contact successfully");
next();
}
);
}
function getContact(callback) {
return function() {
let req = indexedDB.open(STORE_NAME, DB_VERSION);
req.onsuccess = function(event) {
let db = event.target.result;
let txn = db.transaction([STORE_NAME], "readonly");
txn.onabort = makeFailure("Failed to open transaction");
let r2 = txn.objectStore(STORE_NAME).get(CONTACT_PROPS.id);
r2.onsuccess = function() {
db.close();
callback(r2.result);
};
r2.onerror = makeFailure("Failed to get contact");
};
};
}
let savedContact;
let Tests = [
saveContact,
getContact(function(contact) {
savedContact = contact;
next();
}),
function() {
deleteDatabase(function() {
info("slow upgrade");
cdb.useFastUpgrade = false;
cdb.init();
next();
});
},
saveContact,
getContact(function(contact) {
checkDBContacts(savedContact, contact);
next();
}),
];
function next() {
let step = Tests.shift();
if (step) {
step();
} else {
info("All done");
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
next();
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=889239"
target="_blank">Mozilla Bug 889239</a>
</body>
</window>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_basics.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_basics2.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_blobs.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_events.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_getall.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_getall2.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_international.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_substringmatching.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_substringmatchingCL.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_contacts_substringmatchingVE.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_migration.html";
}
SimpleTest.waitForExplicitFinish();
onload = run_tests;
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,336 @@
/* global
sendAsyncMessage,
addMessageListener,
indexedDB
*/
"use strict";
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
var 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,
} = imports;
// |const| will not work because
// it will make the Promise object immutable before assigning.
// Using Object.defineProperty() instead.
Object.defineProperty(this, "Promise", {
value: imports.Promise, writable: false, configurable: false
});
var 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);
});
});

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<iframe></iframe>
<pre id="test">
<script type="application/javascript">
function run_tests() {
var iframe = document.querySelector("iframe");
iframe.src = "file_permission_denied.html";
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPermissions([
{type: "contacts-read", allow: false, context: document},
{type: "contacts-write", allow: false, context: document},
{type: "contacts-create", allow: false, context: document},
], run_tests);
};
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -175,6 +175,10 @@ const kEventConstructors = {
return new HashChangeEvent(aName, aProps);
},
},
IccChangeEvent: { create: function (aName, aProps) {
return new IccChangeEvent(aName, aProps);
},
},
IDBVersionChangeEvent: { create: function (aName, aProps) {
return new IDBVersionChangeEvent(aName, aProps);
},

Просмотреть файл

@ -8,7 +8,6 @@
#define mozilla_dom_GamepadServiceTest_h_
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/GamepadBinding.h"
namespace mozilla {

129
dom/icc/Assertions.cpp Normal file
Просмотреть файл

@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/MozIccBinding.h"
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
namespace icc {
#define ASSERT_EQUALITY(webidlType, webidlState, xpidlState) \
static_assert(static_cast<uint32_t>(webidlType::webidlState) == nsIIcc::xpidlState, \
#webidlType "::" #webidlState " should equal to nsIIccService::" #xpidlState)
/**
* Enum IccCardState
*/
#define ASSERT_ICC_CARD_STATE_EQUALITY(webidlState, xpidlState) \
ASSERT_EQUALITY(IccCardState, webidlState, xpidlState)
ASSERT_ICC_CARD_STATE_EQUALITY(Unknown, CARD_STATE_UNKNOWN);
ASSERT_ICC_CARD_STATE_EQUALITY(Ready, CARD_STATE_READY);
ASSERT_ICC_CARD_STATE_EQUALITY(PinRequired, CARD_STATE_PIN_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(PukRequired, CARD_STATE_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(PermanentBlocked, CARD_STATE_PERMANENT_BLOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(PersonalizationInProgress, CARD_STATE_PERSONALIZATION_IN_PROGRESS);
ASSERT_ICC_CARD_STATE_EQUALITY(PersonalizationReady, CARD_STATE_PERSONALIZATION_READY);
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkLocked, CARD_STATE_NETWORK_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkSubsetLocked, CARD_STATE_NETWORK_SUBSET_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(CorporateLocked, CARD_STATE_CORPORATE_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(ServiceProviderLocked, CARD_STATE_SERVICE_PROVIDER_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(SimPersonalizationLocked, CARD_STATE_SIM_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkPukRequired, CARD_STATE_NETWORK_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkSubsetPukRequired, CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(CorporatePukRequired, CARD_STATE_CORPORATE_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(ServiceProviderPukRequired, CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(SimPersonalizationPukRequired, CARD_STATE_SIM_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(Network1Locked, CARD_STATE_NETWORK1_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(Network2Locked, CARD_STATE_NETWORK2_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(HrpdNetworkLocked, CARD_STATE_HRPD_NETWORK_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimCorporateLocked, CARD_STATE_RUIM_CORPORATE_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimServiceProviderLocked, CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimPersonalizationLocked, CARD_STATE_RUIM_LOCKED);
ASSERT_ICC_CARD_STATE_EQUALITY(Network1PukRequired, CARD_STATE_NETWORK1_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(Network2PukRequired, CARD_STATE_NETWORK2_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(HrpdNetworkPukRequired, CARD_STATE_HRPD_NETWORK_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimCorporatePukRequired, CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimServiceProviderPukRequired, CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(RuimPersonalizationPukRequired, CARD_STATE_RUIM_PUK_REQUIRED);
ASSERT_ICC_CARD_STATE_EQUALITY(Illegal, CARD_STATE_ILLEGAL);
#undef ASSERT_ICC_CARD_STATE_EQUALITY
/**
* Enum IccLockType
*/
#define ASSERT_ICC_LOCK_TYPE_EQUALITY(webidlState, xpidlState) \
ASSERT_EQUALITY(IccLockType, webidlState, xpidlState)
ASSERT_ICC_LOCK_TYPE_EQUALITY(Pin, CARD_LOCK_TYPE_PIN);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Pin2, CARD_LOCK_TYPE_PIN2);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Puk, CARD_LOCK_TYPE_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Puk2, CARD_LOCK_TYPE_PUK2);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nck, CARD_LOCK_TYPE_NCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nsck, CARD_LOCK_TYPE_NSCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nck1, CARD_LOCK_TYPE_NCK1);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nck2, CARD_LOCK_TYPE_NCK2);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Hnck, CARD_LOCK_TYPE_HNCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Cck, CARD_LOCK_TYPE_CCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Spck, CARD_LOCK_TYPE_SPCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Pck, CARD_LOCK_TYPE_PCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Rcck, CARD_LOCK_TYPE_RCCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Rspck, CARD_LOCK_TYPE_RSPCK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(NckPuk, CARD_LOCK_TYPE_NCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(NsckPuk, CARD_LOCK_TYPE_NSCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nck1Puk, CARD_LOCK_TYPE_NCK1_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Nck2Puk, CARD_LOCK_TYPE_NCK2_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(HnckPuk, CARD_LOCK_TYPE_HNCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(CckPuk, CARD_LOCK_TYPE_CCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(SpckPuk, CARD_LOCK_TYPE_SPCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(PckPuk, CARD_LOCK_TYPE_PCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(RcckPuk, CARD_LOCK_TYPE_RCCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(RspckPuk, CARD_LOCK_TYPE_RSPCK_PUK);
ASSERT_ICC_LOCK_TYPE_EQUALITY(Fdn, CARD_LOCK_TYPE_FDN);
#undef ASSERT_ICC_LOCK_TYPE_EQUALITY
/**
* Enum IccContactType
*/
#define ASSERT_ICC_CONTACT_TYPE_EQUALITY(webidlState, xpidlState) \
ASSERT_EQUALITY(IccContactType, webidlState, xpidlState)
ASSERT_ICC_CONTACT_TYPE_EQUALITY(Adn, CARD_CONTACT_TYPE_ADN);
ASSERT_ICC_CONTACT_TYPE_EQUALITY(Fdn, CARD_CONTACT_TYPE_FDN);
ASSERT_ICC_CONTACT_TYPE_EQUALITY(Sdn, CARD_CONTACT_TYPE_SDN);
#undef ASSERT_ICC_CONTACT_TYPE_EQUALITY
/**
* Enum IccMvnoType
*/
#define ASSERT_ICC_MVNO_TYPE_EQUALITY(webidlState, xpidlState) \
ASSERT_EQUALITY(IccMvnoType, webidlState, xpidlState)
ASSERT_ICC_MVNO_TYPE_EQUALITY(Imsi, CARD_MVNO_TYPE_IMSI);
ASSERT_ICC_MVNO_TYPE_EQUALITY(Spn, CARD_MVNO_TYPE_SPN);
ASSERT_ICC_MVNO_TYPE_EQUALITY(Gid, CARD_MVNO_TYPE_GID);
#undef ASSERT_ICC_MVNO_TYPE_EQUALITY
/**
* Enum IccService
*/
#define ASSERT_ICC_SERVICE_EQUALITY(webidlState, xpidlState) \
ASSERT_EQUALITY(IccService, webidlState, xpidlState)
ASSERT_ICC_SERVICE_EQUALITY(Fdn, CARD_SERVICE_FDN);
#undef ASSERT_ICC_SERVICE_EQUALITY
#undef ASSERT_EQUALITY
} // namespace icc
} // namespace dom
} // namespace mozilla

519
dom/icc/Icc.cpp Normal file
Просмотреть файл

@ -0,0 +1,519 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Icc.h"
#include "IccCallback.h"
#include "IccContact.h"
#include "mozilla/dom/ContactsBinding.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/IccInfo.h"
#include "mozilla/dom/MozStkCommandEvent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIIccInfo.h"
#include "nsIIccService.h"
#include "nsIStkCmdFactory.h"
#include "nsIStkProactiveCmd.h"
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
using mozilla::dom::icc::IccCallback;
using mozilla::dom::icc::IccContact;
namespace mozilla {
namespace dom {
namespace {
bool
IsPukCardLockType(IccLockType aLockType)
{
switch(aLockType) {
case IccLockType::Puk:
case IccLockType::Puk2:
case IccLockType::NckPuk:
case IccLockType::Nck1Puk:
case IccLockType::Nck2Puk:
case IccLockType::HnckPuk:
case IccLockType::CckPuk:
case IccLockType::SpckPuk:
case IccLockType::RcckPuk:
case IccLockType::RspckPuk:
case IccLockType::NsckPuk:
case IccLockType::PckPuk:
return true;
default:
return false;
}
}
} // namespace
NS_IMPL_CYCLE_COLLECTION_INHERITED(Icc, DOMEventTargetHelper, mIccInfo)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Icc)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(Icc, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(Icc, DOMEventTargetHelper)
Icc::Icc(nsPIDOMWindowInner* aWindow, nsIIcc* aHandler, nsIIccInfo* aIccInfo)
: mLive(true)
, mHandler(aHandler)
{
BindToOwner(aWindow);
if (aIccInfo) {
aIccInfo->GetIccid(mIccId);
UpdateIccInfo(aIccInfo);
}
}
Icc::~Icc()
{
}
void
Icc::Shutdown()
{
mIccInfo.SetNull();
mHandler = nullptr;
mLive = false;
}
nsresult
Icc::NotifyEvent(const nsAString& aName)
{
return DispatchTrustedEvent(aName);
}
nsresult
Icc::NotifyStkEvent(const nsAString& aName, nsIStkProactiveCmd* aStkProactiveCmd)
{
JS::RootingContext* cx = RootingCx();
JS::Rooted<JS::Value> value(cx);
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, NS_ERROR_UNEXPECTED);
cmdFactory->CreateCommandMessage(aStkProactiveCmd, &value);
NS_ENSURE_TRUE(value.isObject(), NS_ERROR_UNEXPECTED);
RootedDictionary<MozStkCommandEventInit> init(cx);
init.mBubbles = false;
init.mCancelable = false;
init.mCommand = value;
RefPtr<MozStkCommandEvent> event =
MozStkCommandEvent::Constructor(this, aName, init);
return DispatchTrustedEvent(event);
}
void
Icc::UpdateIccInfo(nsIIccInfo* aIccInfo)
{
if (!aIccInfo) {
mIccInfo.SetNull();
return;
}
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo(do_QueryInterface(aIccInfo));
if (gsmIccInfo) {
if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozGsmIccInfo()) {
mIccInfo.SetValue().SetAsMozGsmIccInfo() = new GsmIccInfo(GetOwner());
}
mIccInfo.Value().GetAsMozGsmIccInfo().get()->Update(gsmIccInfo);
return;
}
nsCOMPtr<nsICdmaIccInfo> cdmaIccInfo(do_QueryInterface(aIccInfo));
if (cdmaIccInfo) {
if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozCdmaIccInfo()) {
mIccInfo.SetValue().SetAsMozCdmaIccInfo() = new CdmaIccInfo(GetOwner());
}
mIccInfo.Value().GetAsMozCdmaIccInfo().get()->Update(cdmaIccInfo);
return;
}
if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozIccInfo()) {
mIccInfo.SetValue().SetAsMozIccInfo() = new IccInfo(GetOwner());
}
mIccInfo.Value().GetAsMozIccInfo().get()->Update(aIccInfo);
}
// WrapperCache
JSObject*
Icc::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozIccBinding::Wrap(aCx, this, aGivenProto);
}
// MozIcc WebIDL
void
Icc::GetIccInfo(Nullable<OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo>& aIccInfo) const
{
aIccInfo = mIccInfo;
}
Nullable<IccCardState>
Icc::GetCardState() const
{
Nullable<IccCardState> result;
uint32_t cardState = nsIIcc::CARD_STATE_UNDETECTED;
if (mHandler &&
NS_SUCCEEDED(mHandler->GetCardState(&cardState)) &&
cardState != nsIIcc::CARD_STATE_UNDETECTED) {
MOZ_ASSERT(cardState < static_cast<uint32_t>(IccCardState::EndGuard_));
result.SetValue(static_cast<IccCardState>(cardState));
}
return result;
}
void
Icc::SendStkResponse(const JSContext* aCx, JS::Handle<JS::Value> aCommand,
JS::Handle<JS::Value> aResponse, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
if (!cmdFactory) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkProactiveCmd> command;
cmdFactory->CreateCommand(aCommand, getter_AddRefs(command));
if (!command) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkTerminalResponse> response;
cmdFactory->CreateResponse(aResponse, getter_AddRefs(response));
if (!response) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsresult rv = mHandler->SendStkResponse(command, response);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
void
Icc::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested,
ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsresult rv = mHandler->SendStkMenuSelection(aItemIdentifier, aHelpRequested);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
void
Icc::SendStkTimerExpiration(const JSContext* aCx, JS::Handle<JS::Value> aTimer,
ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
if (!cmdFactory) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkTimer> timer;
cmdFactory->CreateTimer(aTimer, getter_AddRefs(timer));
if (!timer) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
uint16_t timerId;
nsresult rv = timer->GetTimerId(&timerId);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
uint32_t timerValue;
rv = timer->GetTimerValue(&timerValue);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
rv = mHandler->SendStkTimerExpiration(timerId, timerValue);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
void
Icc::SendStkEventDownload(const JSContext* aCx, JS::Handle<JS::Value> aEvent,
ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
if (!cmdFactory) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIStkDownloadEvent> event;
cmdFactory->CreateEvent(aEvent, getter_AddRefs(event));
if (!event) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsresult rv = mHandler->SendStkEventDownload(event);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
already_AddRefed<DOMRequest>
Icc::GetCardLock(IccLockType aLockType, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
// TODO: Bug 1125018 - Simplify The Result of GetCardLock and
// getCardLockRetryCount in MozIcc.webidl without a wrapper object.
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request, true);
nsresult rv = mHandler->GetCardLockEnabled(static_cast<uint32_t>(aLockType),
requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::UnlockCardLock(const IccUnlockCardLockOptions& aOptions, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
const nsString& password = IsPukCardLockType(aOptions.mLockType)
? aOptions.mPuk : aOptions.mPin;
nsresult rv =
mHandler->UnlockCardLock(static_cast<uint32_t>(aOptions.mLockType),
password, aOptions.mNewPin, requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::SetCardLock(const IccSetCardLockOptions& aOptions, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsresult rv;
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
if (aOptions.mEnabled.WasPassed()) {
// Enable card lock.
const nsString& password = (aOptions.mLockType == IccLockType::Fdn) ?
aOptions.mPin2 : aOptions.mPin;
rv =
mHandler->SetCardLockEnabled(static_cast<uint32_t>(aOptions.mLockType),
password, aOptions.mEnabled.Value(),
requestCallback);
} else {
// Change card lock password.
rv =
mHandler->ChangeCardLockPassword(static_cast<uint32_t>(aOptions.mLockType),
aOptions.mPin, aOptions.mNewPin,
requestCallback);
}
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::GetCardLockRetryCount(IccLockType aLockType, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
nsresult rv = mHandler->GetCardLockRetryCount(static_cast<uint32_t>(aLockType),
requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::ReadContacts(IccContactType aContactType, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
nsresult rv = mHandler->ReadContacts(static_cast<uint32_t>(aContactType),
requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::UpdateContact(IccContactType aContactType, mozContact& aContact,
const nsAString& aPin2, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
nsCOMPtr<nsIIccContact> iccContact;
nsresult rv = IccContact::Create(aContact, getter_AddRefs(iccContact));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
rv = mHandler->UpdateContact(static_cast<uint32_t>(aContactType),
iccContact,
aPin2,
requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<DOMRequest>
Icc::MatchMvno(IccMvnoType aMvnoType, const nsAString& aMvnoData,
ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMRequest> request = new DOMRequest(GetOwner());
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), request);
nsresult rv = mHandler->MatchMvno(static_cast<uint32_t>(aMvnoType),
aMvnoData, requestCallback);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget();
}
already_AddRefed<Promise>
Icc::GetServiceState(IccService aService, ErrorResult& aRv)
{
if (!mHandler) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (!global) {
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
RefPtr<IccCallback> requestCallback =
new IccCallback(GetOwner(), promise);
nsresult rv =
mHandler->GetServiceStateEnabled(static_cast<uint32_t>(aService),
requestCallback);
if (NS_FAILED(rv)) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
// fall-through to return promise.
}
return promise.forget();
}
} // namespace dom
} // namespace mozilla

134
dom/icc/Icc.h Normal file
Просмотреть файл

@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_Icc_h
#define mozilla_dom_Icc_h
#include "mozilla/dom/MozIccBinding.h"
#include "mozilla/DOMEventTargetHelper.h"
class nsIIcc;
class nsIIccInfo;
class nsIIccProvider;
class nsIStkProactiveCmd;
namespace mozilla {
namespace dom {
class DOMRequest;
class OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo;
class mozContact;
class Promise;
class Icc final : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Icc, DOMEventTargetHelper)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
Icc(nsPIDOMWindowInner* aWindow, nsIIcc* aHandler, nsIIccInfo* aIccInfo);
void
Shutdown();
nsresult
NotifyEvent(const nsAString& aName);
nsresult
NotifyStkEvent(const nsAString& aName, nsIStkProactiveCmd* aStkProactiveCmd);
nsString
GetIccId()
{
return mIccId;
}
void
UpdateIccInfo(nsIIccInfo* aIccInfo);
nsPIDOMWindowInner*
GetParentObject() const
{
return GetOwner();
}
// WrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// MozIcc WebIDL
void
GetIccInfo(Nullable<OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo>& aIccInfo) const;
Nullable<IccCardState>
GetCardState() const;
void
SendStkResponse(const JSContext* aCx, JS::Handle<JS::Value> aCommand,
JS::Handle<JS::Value> aResponse, ErrorResult& aRv);
void
SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested,
ErrorResult& aRv);
void
SendStkTimerExpiration(const JSContext* aCx, JS::Handle<JS::Value> aTimer,
ErrorResult& aRv);
void
SendStkEventDownload(const JSContext* aCx, JS::Handle<JS::Value> aEvent,
ErrorResult& aRv);
already_AddRefed<DOMRequest>
GetCardLock(IccLockType aLockType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
UnlockCardLock(const IccUnlockCardLockOptions& aOptions, ErrorResult& aRv);
already_AddRefed<DOMRequest>
SetCardLock(const IccSetCardLockOptions& aOptions, ErrorResult& aRv);
already_AddRefed<DOMRequest>
GetCardLockRetryCount(IccLockType aLockType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
ReadContacts(IccContactType aContactType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
UpdateContact(IccContactType aContactType, mozContact& aContact,
const nsAString& aPin2, ErrorResult& aRv);
already_AddRefed<DOMRequest>
MatchMvno(IccMvnoType aMvnoType, const nsAString& aMatchData,
ErrorResult& aRv);
already_AddRefed<Promise>
GetServiceState(IccService aService, ErrorResult& aRv);
IMPL_EVENT_HANDLER(iccinfochange)
IMPL_EVENT_HANDLER(cardstatechange)
IMPL_EVENT_HANDLER(stkcommand)
IMPL_EVENT_HANDLER(stksessionend)
private:
// Put definition of the destructor in Icc.cpp to ensure forward declaration
// of nsIIccProvider, nsIIcc for the auto-generated .cpp file (i.e.,
// MozIccManagerBinding.cpp) that includes this header.
~Icc();
bool mLive;
nsString mIccId;
// mHandler will be released at Shutdown(), so there is no need to join cycle
// collection.
nsCOMPtr<nsIIcc> mHandler;
Nullable<OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo> mIccInfo;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_Icc_h

297
dom/icc/IccCallback.cpp Normal file
Просмотреть файл

@ -0,0 +1,297 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccCallback.h"
#include "mozilla/dom/ContactsBinding.h"
#include "mozilla/dom/IccCardLockError.h"
#include "mozilla/dom/MozIccBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsIIccContact.h"
#include "nsJSUtils.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace dom {
namespace icc {
namespace {
static nsresult
IccContactToMozContact(JSContext* aCx, GlobalObject& aGlobal,
nsIIccContact* aIccContact,
mozContact** aMozContact)
{
*aMozContact = nullptr;
ContactProperties properties;
// Names
char16_t** rawStringArray = nullptr;
uint32_t count = 0;
nsresult rv = aIccContact->GetNames(&count, &rawStringArray);
NS_ENSURE_SUCCESS(rv, rv);
if (count > 0) {
Sequence<nsString>& nameSeq = properties.mName.Construct().SetValue();
for (uint32_t i = 0; i < count; i++) {
nameSeq.AppendElement(
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: EmptyString(),
fallible);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
// Numbers
rawStringArray = nullptr;
count = 0;
rv = aIccContact->GetNumbers(&count, &rawStringArray);
NS_ENSURE_SUCCESS(rv, rv);
if (count > 0) {
Sequence<ContactTelField>& numberSeq = properties.mTel.Construct().SetValue();
for (uint32_t i = 0; i < count; i++) {
ContactTelField number;
number.mValue.Construct() =
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: EmptyString();
numberSeq.AppendElement(number, fallible);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
// Emails
rawStringArray = nullptr;
count = 0;
rv = aIccContact->GetEmails(&count, &rawStringArray);
NS_ENSURE_SUCCESS(rv, rv);
if (count > 0) {
Sequence<ContactField>& emailSeq = properties.mEmail.Construct().SetValue();
for (uint32_t i = 0; i < count; i++) {
ContactField email;
email.mValue.Construct() =
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: EmptyString();
emailSeq.AppendElement(email, fallible);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
ErrorResult er;
RefPtr<mozContact> contact
= mozContact::Constructor(aGlobal, aCx, properties, er);
rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString contactId;
rv = aIccContact->GetId(contactId);
NS_ENSURE_SUCCESS(rv, rv);
contact->SetId(contactId, er);
rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
contact.forget(aMozContact);
return NS_OK;
}
static nsresult
IccContactListToMozContactList(JSContext* aCx, GlobalObject& aGlobal,
nsIIccContact** aContacts, uint32_t aCount,
nsTArray<RefPtr<mozContact>>& aContactList)
{
aContactList.SetCapacity(aCount);
for (uint32_t i = 0; i < aCount ; i++) {
RefPtr<mozContact> contact;
nsresult rv =
IccContactToMozContact(aCx, aGlobal, aContacts[i], getter_AddRefs(contact));
NS_ENSURE_SUCCESS(rv, rv);
aContactList.AppendElement(contact);
}
return NS_OK;
}
} // anonymous namespace
NS_IMPL_ISUPPORTS(IccCallback, nsIIccCallback)
IccCallback::IccCallback(nsPIDOMWindowInner* aWindow, DOMRequest* aRequest,
bool aIsCardLockEnabled)
: mWindow(aWindow)
, mRequest(aRequest)
, mIsCardLockEnabled(aIsCardLockEnabled)
{
}
IccCallback::IccCallback(nsPIDOMWindowInner* aWindow, Promise* aPromise)
: mWindow(aWindow)
, mPromise(aPromise)
{
}
nsresult
IccCallback::NotifySuccess(JS::Handle<JS::Value> aResult)
{
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireSuccessAsync(mRequest, aResult);
}
nsresult
IccCallback::NotifyGetCardLockEnabled(bool aResult)
{
IccCardLockStatus result;
result.mEnabled.Construct(aResult);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> jsResult(cx);
if (!ToJSValue(cx, result, &jsResult)) {
jsapi.ClearException();
return NS_ERROR_TYPE_ERR;
}
return NotifySuccess(jsResult);
}
NS_IMETHODIMP
IccCallback::NotifySuccess()
{
return NotifySuccess(JS::UndefinedHandleValue);
}
NS_IMETHODIMP
IccCallback::NotifySuccessWithBoolean(bool aResult)
{
if (mPromise) {
mPromise->MaybeResolve(aResult ? JS::TrueHandleValue : JS::FalseHandleValue);
return NS_OK;
}
return mIsCardLockEnabled
? NotifyGetCardLockEnabled(aResult)
: NotifySuccess(aResult ? JS::TrueHandleValue : JS::FalseHandleValue);
}
NS_IMETHODIMP
IccCallback::NotifyGetCardLockRetryCount(int32_t aCount)
{
// TODO: Bug 1125018 - Simplify The Result of GetCardLock and
// getCardLockRetryCount in MozIcc.webidl without a wrapper object.
IccCardLockRetryCount result;
result.mRetryCount.Construct(aCount);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> jsResult(cx);
if (!ToJSValue(cx, result, &jsResult)) {
jsapi.ClearException();
return NS_ERROR_TYPE_ERR;
}
return NotifySuccess(jsResult);
}
NS_IMETHODIMP
IccCallback::NotifyError(const nsAString & aErrorMsg)
{
if (mPromise) {
mPromise->MaybeRejectBrokenly(aErrorMsg);
return NS_OK;
}
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireErrorAsync(mRequest, aErrorMsg);
}
NS_IMETHODIMP
IccCallback::NotifyCardLockError(const nsAString & aErrorMsg,
int32_t aRetryCount)
{
RefPtr<IccCardLockError> error =
new IccCardLockError(mWindow, aErrorMsg, aRetryCount);
mRequest->FireDetailedError(error);
return NS_OK;
}
NS_IMETHODIMP
IccCallback::NotifyRetrievedIccContacts(nsIIccContact** aContacts,
uint32_t aCount)
{
MOZ_ASSERT(aContacts);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
GlobalObject global(cx, go->GetGlobalJSObject());
nsTArray<RefPtr<mozContact>> contactList;
nsresult rv =
IccContactListToMozContactList(cx, global, aContacts, aCount, contactList);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> jsResult(cx);
if (!ToJSValue(cx, contactList, &jsResult)) {
return NS_ERROR_FAILURE;
}
return NotifySuccess(jsResult);
}
NS_IMETHODIMP
IccCallback::NotifyUpdatedIccContact(nsIIccContact* aContact)
{
MOZ_ASSERT(aContact);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
GlobalObject global(cx, go->GetGlobalJSObject());
RefPtr<mozContact> mozContact;
nsresult rv =
IccContactToMozContact(cx, global, aContact, getter_AddRefs(mozContact));
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> jsResult(cx);
if (!ToJSValue(cx, mozContact, &jsResult)) {
return NS_ERROR_FAILURE;
}
return NotifySuccess(jsResult);
}
} // namespace icc
} // namespace dom
} // namespace mozilla

66
dom/icc/IccCallback.h Normal file
Просмотреть файл

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccCallback_h
#define mozilla_dom_icc_IccCallback_h
#include "nsCOMPtr.h"
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
class DOMRequest;
class Promise;
namespace icc {
/**
* A callback object for handling asynchronous request/response. This object is
* created when an asynchronous request is made and should be destroyed after
* Notify*Success/Error is called.
* The modules hold the reference of IccCallback in OOP mode and non-OOP mode
* are different.
* - OOP mode: IccRequestChild
* - non-OOP mode: IccService
* The reference should be released after Notify*Success/Error is called.
*/
class IccCallback final : public nsIIccCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCCALLBACK
// TODO: Bug 1125018 - Simplify The Result of GetCardLock and
// getCardLockRetryCount in MozIcc.webidl without a wrapper object.
IccCallback(nsPIDOMWindowInner* aWindow, DOMRequest* aRequest,
bool aIsCardLockEnabled = false);
IccCallback(nsPIDOMWindowInner* aWindow, Promise* aPromise);
private:
~IccCallback() {}
nsresult
NotifySuccess(JS::Handle<JS::Value> aResult);
// TODO: Bug 1125018 - Simplify The Result of GetCardLock and
// getCardLockRetryCount in MozIcc.webidl without a wrapper object.
nsresult
NotifyGetCardLockEnabled(bool aResult);
nsCOMPtr<nsPIDOMWindowInner> mWindow;
RefPtr<DOMRequest> mRequest;
RefPtr<Promise> mPromise;
// TODO: Bug 1125018 - Simplify The Result of GetCardLock and
// getCardLockRetryCount in MozIcc.webidl without a wrapper object.
bool mIsCardLockEnabled;
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccCallback_h

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/IccCardLockError.h"
#include "mozilla/dom/IccCardLockErrorBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS_INHERITED0(IccCardLockError, DOMError)
/* static */ already_AddRefed<IccCardLockError>
IccCardLockError::Constructor(const GlobalObject& aGlobal,
const nsAString& aName,
int16_t aRetryCount,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<IccCardLockError> result =
new IccCardLockError(window, aName, aRetryCount);
return result.forget();
}
IccCardLockError::IccCardLockError(nsPIDOMWindowInner* aWindow,
const nsAString& aName,
int16_t aRetryCount)
: DOMError(aWindow, aName)
, mRetryCount(aRetryCount)
{
}
JSObject*
IccCardLockError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return IccCardLockErrorBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_IccCardLockError_h
#define mozilla_dom_IccCardLockError_h
#include "mozilla/dom/DOMError.h"
namespace mozilla {
namespace dom {
class IccCardLockError final : public DOMError
{
public:
NS_DECL_ISUPPORTS_INHERITED
IccCardLockError(nsPIDOMWindowInner* aWindow, const nsAString& aName,
int16_t aRetryCount);
static already_AddRefed<IccCardLockError>
Constructor(const GlobalObject& aGlobal, const nsAString& aName,
int16_t aRetryCount, ErrorResult& aRv);
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// WebIDL interface
int16_t
RetryCount() const
{
return mRetryCount;
}
private:
~IccCardLockError() {}
private:
int16_t mRetryCount;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_IccCardLockError_h

154
dom/icc/IccContact.cpp Normal file
Просмотреть файл

@ -0,0 +1,154 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccContact.h"
#include "mozilla/dom/ContactsBinding.h"
#include "nsReadableUtils.h"
using namespace mozilla::dom::icc;
using mozilla::dom::mozContact;
NS_IMPL_ISUPPORTS(IccContact, nsIIccContact)
/* static */ nsresult
IccContact::Create(mozContact& aMozContact, nsIIccContact** aIccContact)
{
*aIccContact = nullptr;
ErrorResult er;
// Id
nsAutoString id;
aMozContact.GetId(id, er);
nsresult rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
// Names
Nullable<nsTArray<nsString>> names;
aMozContact.GetName(names, er);
rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
if (names.IsNull()) {
// Set as Empty nsTarray<nsString> for IccContact constructor.
names.SetValue();
}
// Numbers
Nullable<nsTArray<ContactTelField>> nullableNumberList;
aMozContact.GetTel(nullableNumberList, er);
rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> numbers;
if (!nullableNumberList.IsNull()) {
const nsTArray<ContactTelField>& numberList = nullableNumberList.Value();
for (uint32_t i = 0; i < numberList.Length(); i++) {
if (numberList[i].mValue.WasPassed()) {
numbers.AppendElement(numberList[i].mValue.Value());
}
}
}
// Emails
Nullable<nsTArray<ContactField>> nullableEmailList;
aMozContact.GetEmail(nullableEmailList, er);
rv = er.StealNSResult();
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> emails;
if (!nullableEmailList.IsNull()) {
const nsTArray<ContactField>& emailList = nullableEmailList.Value();
for (uint32_t i = 0; i < emailList.Length(); i++) {
if (emailList[i].mValue.WasPassed()) {
emails.AppendElement(emailList[i].mValue.Value());
}
}
}
nsCOMPtr<nsIIccContact> iccContact = new IccContact(id,
names.Value(),
numbers,
emails);
iccContact.forget(aIccContact);
return NS_OK;
}
/*static*/ nsresult
IccContact::Create(const nsAString& aId,
const nsTArray<nsString>& aNames,
const nsTArray<nsString>& aNumbers,
const nsTArray<nsString>& aEmails,
nsIIccContact** aIccContact)
{
*aIccContact = nullptr;
nsCOMPtr<nsIIccContact> iccContact = new IccContact(aId,
aNames,
aNumbers,
aEmails);
iccContact.forget(aIccContact);
return NS_OK;
}
IccContact::IccContact(const nsAString& aId,
const nsTArray<nsString>& aNames,
const nsTArray<nsString>& aNumbers,
const nsTArray<nsString>& aEmails)
: mId(aId),
mNames(aNames),
mNumbers(aNumbers),
mEmails(aEmails)
{
}
// nsIIccInfo implementation.
NS_IMETHODIMP IccContact::GetId(nsAString & aId)
{
aId = mId;
return NS_OK;
}
#define ICCCONTACT_IMPL_GET_CONTACT_FIELD(_field) \
NS_IMETHODIMP IccContact::Get##_field(uint32_t* aCount, char16_t*** a##_field) \
{ \
NS_ENSURE_ARG_POINTER(aCount); \
NS_ENSURE_ARG_POINTER(a##_field); \
\
*aCount = 0; \
*a##_field = nullptr; \
\
uint32_t count = m##_field.Length(); \
if (count == 0) { \
return NS_OK; \
} \
char16_t** temp = \
static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*) * (count))); \
if (temp == nullptr) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
for (uint32_t i = 0; i < count; i++) { \
if(m##_field[i].IsVoid()) { \
(temp)[i] = nullptr; \
continue; \
} \
\
(temp)[i] = ToNewUnicode(m##_field[i]); \
if (!(temp)[i]) { \
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, temp); \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} \
\
*aCount = count; \
*a##_field = temp; \
\
return NS_OK; \
}
ICCCONTACT_IMPL_GET_CONTACT_FIELD(Names)
ICCCONTACT_IMPL_GET_CONTACT_FIELD(Numbers)
ICCCONTACT_IMPL_GET_CONTACT_FIELD(Emails)
#undef ICCCONTACT_GET_CONTACT_FIELD

50
dom/icc/IccContact.h Normal file
Просмотреть файл

@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccContact_h
#define mozilla_dom_icc_IccContact_h
#include "nsIIccContact.h"
namespace mozilla {
namespace dom {
class mozContact;
namespace icc {
class IccContact : public nsIIccContact
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCCONTACT
static nsresult
Create(mozContact& aMozContact,
nsIIccContact** aIccContact);
static nsresult
Create(const nsAString& aId,
const nsTArray<nsString>& aNames,
const nsTArray<nsString>& aNumbers,
const nsTArray<nsString>& aEmails,
nsIIccContact** aIccContact);
private:
IccContact(const nsAString& aId,
const nsTArray<nsString>& aNames,
const nsTArray<nsString>& aNumbers,
const nsTArray<nsString>& aEmails);
virtual ~IccContact() {}
nsString mId;
nsTArray<nsString> mNames;
nsTArray<nsString> mNumbers;
nsTArray<nsString> mEmails;
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccContact_h

297
dom/icc/IccInfo.cpp Normal file
Просмотреть файл

@ -0,0 +1,297 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/IccInfo.h"
#include "mozilla/dom/icc/PIccTypes.h"
#include "nsPIDOMWindow.h"
#define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum) \
{ \
uint32_t i = 0; \
for (const EnumEntry* entry = _enumType##Values::strings; \
entry->value; \
++entry, ++i) { \
if (_string.EqualsASCII(entry->value)) { \
_enum.SetValue(static_cast<_enumType>(i)); \
} \
} \
}
using namespace mozilla::dom;
using mozilla::dom::icc::IccInfoData;
// IccInfo
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(IccInfo, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(IccInfo)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IccInfo)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IccInfo)
NS_INTERFACE_MAP_ENTRY(nsIIccInfo)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END
IccInfo::IccInfo(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow)
{
mIccType.SetIsVoid(true);
mIccid.SetIsVoid(true);
mMcc.SetIsVoid(true);
mMnc.SetIsVoid(true);
mSpn.SetIsVoid(true);
}
IccInfo::IccInfo(const IccInfoData& aData)
{
mIccType = aData.iccType();
mIccid = aData.iccid();
mMcc = aData.mcc();
mMnc = aData.mnc();
mSpn = aData.spn();
mIsDisplayNetworkNameRequired = aData.isDisplayNetworkNameRequired();
mIsDisplaySpnRequired = aData.isDisplaySpnRequired();
}
// nsIIccInfo
NS_IMETHODIMP
IccInfo::GetIccType(nsAString & aIccType)
{
aIccType = mIccType;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetIccid(nsAString & aIccid)
{
aIccid = mIccid;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetMcc(nsAString & aMcc)
{
aMcc = mMcc;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetMnc(nsAString & aMnc)
{
aMnc = mMnc;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetSpn(nsAString & aSpn)
{
aSpn = mSpn;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetIsDisplayNetworkNameRequired(bool *aIsDisplayNetworkNameRequired)
{
*aIsDisplayNetworkNameRequired = mIsDisplayNetworkNameRequired;
return NS_OK;
}
NS_IMETHODIMP
IccInfo::GetIsDisplaySpnRequired(bool *aIsDisplaySpnRequired)
{
*aIsDisplaySpnRequired = mIsDisplaySpnRequired;
return NS_OK;
}
void
IccInfo::Update(nsIIccInfo* aInfo)
{
NS_ASSERTION(aInfo, "aInfo is null");
aInfo->GetIccType(mIccType);
aInfo->GetIccid(mIccid);
aInfo->GetMcc(mMcc);
aInfo->GetMnc(mMnc);
aInfo->GetSpn(mSpn);
aInfo->GetIsDisplayNetworkNameRequired(
&mIsDisplayNetworkNameRequired);
aInfo->GetIsDisplaySpnRequired(
&mIsDisplaySpnRequired);
}
// WebIDL implementation
JSObject*
IccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozIccInfoBinding::Wrap(aCx, this, aGivenProto);
}
Nullable<IccType>
IccInfo::GetIccType() const
{
Nullable<IccType> iccType;
CONVERT_STRING_TO_NULLABLE_ENUM(mIccType, IccType, iccType);
return iccType;
}
void
IccInfo::GetIccid(nsAString& aIccId) const
{
aIccId = mIccid;
}
void
IccInfo::GetMcc(nsAString& aMcc) const
{
aMcc = mMcc;
}
void
IccInfo::GetMnc(nsAString& aMnc) const
{
aMnc = mMnc;
}
void
IccInfo::GetSpn(nsAString& aSpn) const
{
aSpn = mSpn;
}
bool
IccInfo::IsDisplayNetworkNameRequired() const
{
return mIsDisplayNetworkNameRequired;
}
bool
IccInfo::IsDisplaySpnRequired() const
{
return mIsDisplaySpnRequired;
}
// GsmIccInfo
NS_IMPL_ISUPPORTS_INHERITED(GsmIccInfo, IccInfo, nsIGsmIccInfo)
GsmIccInfo::GsmIccInfo(nsPIDOMWindowInner* aWindow)
: IccInfo(aWindow)
{
mPhoneNumber.SetIsVoid(true);
}
GsmIccInfo::GsmIccInfo(const IccInfoData& aData)
: IccInfo(aData)
{
mPhoneNumber = aData.phoneNumber();
}
// nsIGsmIccInfo
NS_IMETHODIMP
GsmIccInfo::GetMsisdn(nsAString & aMsisdn)
{
aMsisdn = mPhoneNumber;
return NS_OK;
}
// WebIDL implementation
void
GsmIccInfo::Update(nsIGsmIccInfo* aInfo)
{
MOZ_ASSERT(aInfo);
nsCOMPtr<nsIIccInfo> iccInfo = do_QueryInterface(aInfo);
MOZ_ASSERT(iccInfo);
IccInfo::Update(iccInfo);
aInfo->GetMsisdn(mPhoneNumber);
}
JSObject*
GsmIccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozGsmIccInfoBinding::Wrap(aCx, this, aGivenProto);
}
void
GsmIccInfo::GetMsisdn(nsAString& aMsisdn) const
{
aMsisdn = mPhoneNumber;
}
// CdmaIccInfo
NS_IMPL_ISUPPORTS_INHERITED(CdmaIccInfo, IccInfo, nsICdmaIccInfo)
CdmaIccInfo::CdmaIccInfo(nsPIDOMWindowInner* aWindow)
: IccInfo(aWindow)
{
mPhoneNumber.SetIsVoid(true);
}
CdmaIccInfo::CdmaIccInfo(const IccInfoData& aData)
: IccInfo(aData)
{
mPhoneNumber = aData.phoneNumber();
mPrlVersion = aData.prlVersion();
}
// nsICdmaIccInfo
NS_IMETHODIMP
CdmaIccInfo::GetMdn(nsAString & aMdn)
{
aMdn = mPhoneNumber;
return NS_OK;
}
NS_IMETHODIMP
CdmaIccInfo::GetPrlVersion(int32_t *aPrlVersion)
{
*aPrlVersion = mPrlVersion;
return NS_OK;
}
void
CdmaIccInfo::Update(nsICdmaIccInfo* aInfo)
{
MOZ_ASSERT(aInfo);
nsCOMPtr<nsIIccInfo> iccInfo = do_QueryInterface(aInfo);
MOZ_ASSERT(iccInfo);
IccInfo::Update(iccInfo);
aInfo->GetMdn(mPhoneNumber);
aInfo->GetPrlVersion(&mPrlVersion);
}
// WebIDL implementation
JSObject*
CdmaIccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozCdmaIccInfoBinding::Wrap(aCx, this, aGivenProto);
}
void
CdmaIccInfo::GetMdn(nsAString& aMdn) const
{
aMdn = mPhoneNumber;
}
int32_t
CdmaIccInfo::PrlVersion() const
{
return mPrlVersion;
}

152
dom/icc/IccInfo.h Normal file
Просмотреть файл

@ -0,0 +1,152 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_IccInfo_h
#define mozilla_dom_IccInfo_h
#include "MozIccInfoBinding.h"
#include "nsIIccInfo.h"
#include "nsWrapperCache.h"
class nsPIDOMWindowInner;
namespace mozilla {
namespace dom {
namespace icc {
class IccInfoData;
} // namespace icc
class IccInfo : public nsIIccInfo
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IccInfo)
NS_DECL_NSIICCINFO
explicit IccInfo(nsPIDOMWindowInner* aWindow);
explicit IccInfo(const icc::IccInfoData& aData);
void
Update(nsIIccInfo* aInfo);
nsPIDOMWindowInner*
GetParentObject() const
{
return mWindow;
}
// WrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// WebIDL interface
Nullable<IccType>
GetIccType() const;
void
GetIccid(nsAString& aIccId) const;
void
GetMcc(nsAString& aMcc) const;
void
GetMnc(nsAString& aMnc) const;
void
GetSpn(nsAString& aSpn) const;
bool
IsDisplayNetworkNameRequired() const;
bool
IsDisplaySpnRequired() const;
protected:
virtual ~IccInfo() {}
nsCOMPtr<nsPIDOMWindowInner> mWindow;
// To prevent compiling error in OS_WIN in auto-generated UnifiedBindingsXX.cpp,
// we have all data fields expended here instead of having a data member of
// |IccInfoData| defined in PIccTypes.h which indirectly includes "windows.h"
// See 925382 for the restriction of including "windows.h" in UnifiedBindings.cpp.
nsString mIccType;
nsString mIccid;
nsString mMcc;
nsString mMnc;
nsString mSpn;
// The following booleans shall be initialized either in the constructor or in Update
MOZ_INIT_OUTSIDE_CTOR bool mIsDisplayNetworkNameRequired;
MOZ_INIT_OUTSIDE_CTOR bool mIsDisplaySpnRequired;
};
class GsmIccInfo final : public IccInfo
, public nsIGsmIccInfo
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIICCINFO(IccInfo::)
NS_DECL_NSIGSMICCINFO
explicit GsmIccInfo(nsPIDOMWindowInner* aWindow);
explicit GsmIccInfo(const icc::IccInfoData& aData);
void
Update(nsIGsmIccInfo* aInfo);
// WrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// MozCdmaIccInfo WebIDL
void
GetMsisdn(nsAString& aMsisdn) const;
private:
~GsmIccInfo() {}
nsString mPhoneNumber;
};
class CdmaIccInfo final : public IccInfo
, public nsICdmaIccInfo
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIICCINFO(IccInfo::)
NS_DECL_NSICDMAICCINFO
explicit CdmaIccInfo(nsPIDOMWindowInner* aWindow);
explicit CdmaIccInfo(const icc::IccInfoData& aData);
void
Update(nsICdmaIccInfo* aInfo);
// WrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// MozCdmaIccInfo WebIDL
void
GetMdn(nsAString& aMdn) const;
int32_t
PrlVersion() const;
private:
~CdmaIccInfo() {}
nsString mPhoneNumber;
// The following integer shall be initialized either in the constructor or in Update
MOZ_INIT_OUTSIDE_CTOR int32_t mPrlVersion;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_IccInfo_h

142
dom/icc/IccListener.cpp Normal file
Просмотреть файл

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccListener.h"
#include "Icc.h"
#include "IccManager.h"
#include "nsIDOMClassInfo.h"
#include "nsIIccInfo.h"
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(IccListener, nsIIccListener)
IccListener::IccListener(IccManager* aIccManager, uint32_t aClientId)
: mClientId(aClientId)
, mIccManager(aIccManager)
{
MOZ_ASSERT(mIccManager);
nsCOMPtr<nsIIccService> iccService = do_GetService(ICC_SERVICE_CONTRACTID);
if (!iccService) {
NS_WARNING("Could not acquire nsIIccService!");
return;
}
iccService->GetIccByServiceId(mClientId, getter_AddRefs(mHandler));
if (!mHandler) {
NS_WARNING("Could not acquire nsIIcc!");
return;
}
nsCOMPtr<nsIIccInfo> iccInfo;
mHandler->GetIccInfo(getter_AddRefs(iccInfo));
if (iccInfo) {
nsString iccId;
iccInfo->GetIccid(iccId);
if (!iccId.IsEmpty()) {
mIcc = new Icc(mIccManager->GetOwner(), mHandler, iccInfo);
}
}
DebugOnly<nsresult> rv = mHandler->RegisterListener(this);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed registering icc listener with Icc Handler");
}
IccListener::~IccListener()
{
Shutdown();
}
void
IccListener::Shutdown()
{
if (mHandler) {
mHandler->UnregisterListener(this);
mHandler = nullptr;
}
if (mIcc) {
mIcc->Shutdown();
mIcc = nullptr;
}
mIccManager = nullptr;
}
// nsIIccListener
NS_IMETHODIMP
IccListener::NotifyStkCommand(nsIStkProactiveCmd *aStkProactiveCmd)
{
if (!mIcc) {
return NS_OK;
}
return mIcc->NotifyStkEvent(NS_LITERAL_STRING("stkcommand"), aStkProactiveCmd);
}
NS_IMETHODIMP
IccListener::NotifyStkSessionEnd()
{
if (!mIcc) {
return NS_OK;
}
return mIcc->NotifyEvent(NS_LITERAL_STRING("stksessionend"));
}
NS_IMETHODIMP
IccListener::NotifyCardStateChanged()
{
if (!mIcc) {
return NS_OK;
}
return mIcc->NotifyEvent(NS_LITERAL_STRING("cardstatechange"));
}
NS_IMETHODIMP
IccListener::NotifyIccInfoChanged()
{
if (!mHandler) {
return NS_OK;
}
nsCOMPtr<nsIIccInfo> iccInfo;
mHandler->GetIccInfo(getter_AddRefs(iccInfo));
// Create/delete icc object based on current iccInfo.
// 1. If the mIcc is nullptr and iccInfo has valid data, create icc object and
// notify mIccManager a new icc is added.
// 2. If the mIcc is not nullptr and iccInfo becomes to null, delete existed
// icc object and notify mIccManager the icc is removed.
if (!mIcc) {
if (iccInfo) {
nsString iccId;
iccInfo->GetIccid(iccId);
if (!iccId.IsEmpty()) {
mIcc = new Icc(mIccManager->GetOwner(), mHandler, iccInfo);
mIccManager->NotifyIccAdd(iccId);
mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange"));
}
}
} else {
mIcc->UpdateIccInfo(iccInfo);
mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange"));
if (!iccInfo) {
nsString iccId = mIcc->GetIccId();
mIcc->Shutdown();
mIcc = nullptr;
mIccManager->NotifyIccRemove(iccId);
}
}
return NS_OK;
}

54
dom/icc/IccListener.h Normal file
Просмотреть файл

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_IccListener_h
#define mozilla_dom_IccListener_h
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
class IccManager;
class Icc;
class IccListener final : public nsIIccListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCLISTENER
IccListener(IccManager* aIccManager, uint32_t aClientId);
void
Shutdown();
Icc*
GetIcc()
{
return mIcc;
}
private:
~IccListener();
private:
uint32_t mClientId;
// We did not setup 'mIcc' and 'mIccManager' being a participant of cycle
// collection is because in Navigator->Invalidate() it will call
// mIccManager->Shutdown(), then IccManager will call Shutdown() of each
// IccListener, this will release the reference and break the cycle.
RefPtr<Icc> mIcc;
RefPtr<IccManager> mIccManager;
// mHandler will be released at Shutdown(), there is no need to join cycle
// collection.
nsCOMPtr<nsIIcc> mHandler;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_IccListener_h

155
dom/icc/IccManager.cpp Normal file
Просмотреть файл

@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccManager.h"
#include "mozilla/dom/MozIccManagerBinding.h"
#include "Icc.h"
#include "IccListener.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/IccChangeEvent.h"
#include "mozilla/Preferences.h"
#include "nsIIccInfo.h"
// Service instantiation
#include "ipc/IccIPCService.h"
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
#include "nsIGonkIccService.h"
#endif
#include "nsXULAppAPI.h" // For XRE_GetProcessType()
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IccManager,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IccManager,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
// QueryInterface implementation for IccManager
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IccManager)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(IccManager, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(IccManager, DOMEventTargetHelper)
IccManager::IccManager(nsPIDOMWindowInner* aWindow)
: DOMEventTargetHelper(aWindow)
{
uint32_t numberOfServices =
mozilla::Preferences::GetUint("ril.numRadioInterfaces", 1);
for (uint32_t i = 0; i < numberOfServices; i++) {
RefPtr<IccListener> iccListener = new IccListener(this, i);
mIccListeners.AppendElement(iccListener);
}
}
IccManager::~IccManager()
{
Shutdown();
}
JSObject*
IccManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozIccManagerBinding::Wrap(aCx, this, aGivenProto);
}
void
IccManager::Shutdown()
{
for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
mIccListeners[i]->Shutdown();
mIccListeners[i] = nullptr;
}
mIccListeners.Clear();
}
nsresult
IccManager::NotifyIccAdd(const nsAString& aIccId)
{
MozIccManagerBinding::ClearCachedIccIdsValue(this);
IccChangeEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mIccId = aIccId;
RefPtr<IccChangeEvent> event =
IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccdetected"), init);
event->SetTrusted(true);
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
return asyncDispatcher->PostDOMEvent();
}
nsresult
IccManager::NotifyIccRemove(const nsAString& aIccId)
{
MozIccManagerBinding::ClearCachedIccIdsValue(this);
IccChangeEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mIccId = aIccId;
RefPtr<IccChangeEvent> event =
IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccundetected"), init);
event->SetTrusted(true);
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
return asyncDispatcher->PostDOMEvent();
}
// MozIccManager
void
IccManager::GetIccIds(nsTArray<nsString>& aIccIds)
{
nsTArray<RefPtr<IccListener>>::size_type i;
for (i = 0; i < mIccListeners.Length(); ++i) {
Icc* icc = mIccListeners[i]->GetIcc();
if (icc) {
aIccIds.AppendElement(icc->GetIccId());
}
}
}
Icc*
IccManager::GetIccById(const nsAString& aIccId) const
{
nsTArray<RefPtr<IccListener>>::size_type i;
for (i = 0; i < mIccListeners.Length(); ++i) {
Icc* icc = mIccListeners[i]->GetIcc();
if (icc && aIccId == icc->GetIccId()) {
return icc;
}
}
return nullptr;
}
already_AddRefed<nsIIccService>
NS_CreateIccService()
{
nsCOMPtr<nsIIccService> service;
if (XRE_IsContentProcess()) {
service = new mozilla::dom::icc::IccIPCService();
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
} else {
service = do_GetService(GONK_ICC_SERVICE_CONTRACTID);
#endif
}
return service.forget();
}

65
dom/icc/IccManager.h Normal file
Просмотреть файл

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_IccManager_h
#define mozilla_dom_IccManager_h
#include "mozilla/DOMEventTargetHelper.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTArrayHelpers.h"
namespace mozilla {
namespace dom {
class Icc;
class IccListener;
class IccManager final : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IccManager, DOMEventTargetHelper)
explicit IccManager(nsPIDOMWindowInner* aWindow);
void
Shutdown();
nsresult
NotifyIccAdd(const nsAString& aIccId);
nsresult
NotifyIccRemove(const nsAString& aIccId);
IMPL_EVENT_HANDLER(iccdetected)
IMPL_EVENT_HANDLER(iccundetected)
void
GetIccIds(nsTArray<nsString>& aIccIds);
Icc*
GetIccById(const nsAString& aIccId) const;
nsPIDOMWindowInner*
GetParentObject() const { return GetOwner(); }
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
private:
~IccManager();
private:
nsTArray<RefPtr<IccListener>> mIccListeners;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_IccManager_h

741
dom/icc/gonk/IccService.js Normal file
Просмотреть файл

@ -0,0 +1,741 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
const GONK_ICCSERVICE_CONTRACTID = "@mozilla.org/icc/gonkiccservice;1";
const GONK_ICCSERVICE_CID = Components.ID("{df854256-9554-11e4-a16c-c39e8d106c26}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIGonkMobileConnectionService");
XPCOMUtils.defineLazyServiceGetter(this, "gIccMessenger",
"@mozilla.org/ril/system-messenger-helper;1",
"nsIIccMessenger");
XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory",
"@mozilla.org/icc/stkcmdfactory;1",
"nsIStkCmdFactory");
var DEBUG = RIL.DEBUG_RIL;
function debug(s) {
dump("IccService: " + s);
}
function IccInfo() {}
IccInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
// nsIIccInfo
iccType: null,
iccid: null,
mcc: null,
mnc: null,
spn: null,
isDisplayNetworkNameRequired: false,
isDisplaySpnRequired: false
};
function GsmIccInfo() {}
GsmIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
Ci.nsIIccInfo]),
// nsIGsmIccInfo
msisdn: null
};
function CdmaIccInfo() {}
CdmaIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaIccInfo,
Ci.nsIIccInfo]),
// nsICdmaIccInfo
mdn: null,
prlVersion: 0
};
function IccContact(aContact) {
this.id = aContact.contactId || null;
this._names = [];
this._numbers = [];
this._emails = [];
this._names.push(aContact.alphaId);
this._numbers.push(aContact.number);
let anrLen = aContact.anr ? aContact.anr.length : 0;
for (let i = 0; i < anrLen; i++) {
this._numbers.push(aContact.anr[i]);
}
if (aContact.email) {
this._emails.push(aContact.email);
}
}
IccContact.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccContact]),
_names: null,
_numbers: null,
_emails: null,
// nsIIccContact
id: null,
getNames: function(aCount) {
if (!this._names) {
if (aCount) {
aCount.value = 0;
}
return null;
}
if (aCount) {
aCount.value = this._names.length;
}
return this._names.slice();
},
getNumbers: function(aCount) {
if (!this._numbers) {
if (aCount) {
aCount.value = 0;
}
return null;
}
if (aCount) {
aCount.value = this._numbers.length;
}
return this._numbers.slice();
},
getEmails: function(aCount) {
if (!this._emails) {
if (aCount) {
aCount.value = 0;
}
return null;
}
if (aCount) {
aCount.value = this._emails.length;
}
return this._emails.slice();
},
};
function IccService() {
this._iccs = [];
let numClients = gRadioInterfaceLayer.numRadioInterfaces;
for (let i = 0; i < numClients; i++) {
this._iccs.push(new Icc(i));
}
this._updateDebugFlag();
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
IccService.prototype = {
classID: GONK_ICCSERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: GONK_ICCSERVICE_CID,
contractID: GONK_ICCSERVICE_CONTRACTID,
classDescription: "IccService",
interfaces: [Ci.nsIIccService,
Ci.nsIGonkIccService],
flags: Ci.nsIClassInfo.SINGLETON}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccService,
Ci.nsIGonkIccService,
Ci.nsIObserver]),
// An array of Icc instances.
_iccs: null,
_updateDebugFlag: function() {
try {
DEBUG = DEBUG ||
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {}
},
/**
* nsIIccService interface.
*/
getIccByServiceId: function(aServiceId) {
let icc = this._iccs[aServiceId];
if (!icc) {
throw Cr.NS_ERROR_UNEXPECTED;
}
return icc;
},
/**
* nsIGonkIccService interface.
*/
notifyStkCommand: function(aServiceId, aStkcommand) {
if (DEBUG) {
debug("notifyStkCommand for service Id: " + aServiceId);
}
let icc = this.getIccByServiceId(aServiceId);
if (!icc.iccInfo || !icc.iccInfo.iccid) {
debug("Warning: got STK command when iccid is invalid.");
return;
}
gIccMessenger.notifyStkProactiveCommand(icc.iccInfo.iccid, aStkcommand);
icc._deliverListenerEvent("notifyStkCommand", [aStkcommand]);
},
notifyStkSessionEnd: function(aServiceId) {
if (DEBUG) {
debug("notifyStkSessionEnd for service Id: " + aServiceId);
}
this.getIccByServiceId(aServiceId)
._deliverListenerEvent("notifyStkSessionEnd");
},
notifyCardStateChanged: function(aServiceId, aCardState) {
if (DEBUG) {
debug("notifyCardStateChanged for service Id: " + aServiceId +
", CardState: " + aCardState);
}
this.getIccByServiceId(aServiceId)._updateCardState(aCardState);
},
notifyIccInfoChanged: function(aServiceId, aIccInfo) {
if (DEBUG) {
debug("notifyIccInfoChanged for service Id: " + aServiceId +
", IccInfo: " + JSON.stringify(aIccInfo));
}
this.getIccByServiceId(aServiceId)._updateIccInfo(aIccInfo);
},
notifyImsiChanged: function(aServiceId, aImsi) {
if (DEBUG) {
debug("notifyImsiChanged for service Id: " + aServiceId +
", Imsi: " + aImsi);
}
let icc = this.getIccByServiceId(aServiceId);
icc.imsi = aImsi || null;
},
/**
* nsIObserver interface.
*/
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
if (aData === kPrefRilDebuggingEnabled) {
this._updateDebugFlag();
}
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
break;
}
}
};
function Icc(aClientId) {
this._clientId = aClientId;
this._radioInterface = gRadioInterfaceLayer.getRadioInterface(aClientId);
this._listeners = [];
}
Icc.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
_clientId: 0,
_radioInterface: null,
_listeners: null,
_updateCardState: function(aCardState) {
if (this.cardState != aCardState) {
this.cardState = aCardState;
}
this._deliverListenerEvent("notifyCardStateChanged");
},
// An utility function to copy objects.
_updateInfo: function(aSrcInfo, aDestInfo) {
for (let key in aSrcInfo) {
aDestInfo[key] = aSrcInfo[key];
}
},
/**
* A utility function to compare objects. The srcInfo may contain
* "rilMessageType", should ignore it.
*/
_isInfoChanged: function(srcInfo, destInfo) {
if (!destInfo) {
return true;
}
for (let key in srcInfo) {
if (key === "rilMessageType") {
continue;
}
if (srcInfo[key] !== destInfo[key]) {
return true;
}
}
return false;
},
/**
* We need to consider below cases when update iccInfo:
* 1. Should clear iccInfo to null if there is no card detected.
* 2. Need to create corresponding object based on iccType.
*/
_updateIccInfo: function(aIccInfo) {
let oldSpn = this.iccInfo ? this.iccInfo.spn : null;
// Card is not detected, clear iccInfo to null.
if (!aIccInfo || !aIccInfo.iccid) {
if (this.iccInfo) {
if (DEBUG) {
debug("Card is not detected, clear iccInfo to null.");
}
this.imsi = null;
this.iccInfo = null;
this._deliverListenerEvent("notifyIccInfoChanged");
}
return;
}
if (!this._isInfoChanged(aIccInfo, this.iccInfo)) {
return;
}
// If iccInfo is null, new corresponding object based on iccType.
if (!this.iccInfo ||
this.iccInfo.iccType != aIccInfo.iccType) {
if (aIccInfo.iccType === "ruim" || aIccInfo.iccType === "csim") {
this.iccInfo = new CdmaIccInfo();
} else if (aIccInfo.iccType === "sim" || aIccInfo.iccType === "usim") {
this.iccInfo = new GsmIccInfo();
} else {
this.iccInfo = new IccInfo();
}
}
this._updateInfo(aIccInfo, this.iccInfo);
this._deliverListenerEvent("notifyIccInfoChanged");
// Update lastKnownSimMcc.
if (aIccInfo.mcc) {
try {
Services.prefs.setCharPref("ril.lastKnownSimMcc",
aIccInfo.mcc.toString());
} catch (e) {}
}
// Update lastKnownHomeNetwork.
if (aIccInfo.mcc && aIccInfo.mnc) {
let lastKnownHomeNetwork = aIccInfo.mcc + "-" + aIccInfo.mnc;
// Append spn information if available.
if (aIccInfo.spn) {
lastKnownHomeNetwork += "-" + aIccInfo.spn;
}
gMobileConnectionService.notifyLastHomeNetworkChanged(this._clientId,
lastKnownHomeNetwork);
}
// If spn becomes available, we should check roaming again.
if (!oldSpn && aIccInfo.spn) {
gMobileConnectionService.notifySpnAvailable(this._clientId);
}
},
_deliverListenerEvent: function(aName, aArgs) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
if (this._listeners.indexOf(listener) === -1) {
continue;
}
let handler = listener[aName];
if (typeof handler != "function") {
throw new Error("No handler for " + aName);
}
try {
handler.apply(listener, aArgs);
} catch (e) {
if (DEBUG) {
debug("listener for " + aName + " threw an exception: " + e);
}
}
}
},
_modifyCardLock: function(aOperation, aOptions, aCallback) {
this._radioInterface.sendWorkerMessage(aOperation,
aOptions,
(aResponse) => {
if (aResponse.errorMsg) {
let retryCount =
(aResponse.retryCount !== undefined) ? aResponse.retryCount : -1;
aCallback.notifyCardLockError(aResponse.errorMsg, retryCount);
return;
}
aCallback.notifySuccess();
});
},
/**
* Helper to match the MVNO pattern with IMSI.
*
* Note: Characters 'x' and 'X' in MVNO are skipped and not compared.
* E.g., if the aMvnoData passed is '310260x10xxxxxx', then the
* function returns true only if imsi has the same first 6 digits, 8th
* and 9th digit.
*
* @param aMvnoData
* MVNO pattern.
* @param aImsi
* IMSI of this ICC.
*
* @return true if matched.
*/
_isImsiMatches: function(aMvnoData, aImsi) {
// This should not be an error, but a mismatch.
if (aMvnoData.length > aImsi.length) {
return false;
}
for (let i = 0; i < aMvnoData.length; i++) {
let c = aMvnoData[i];
if ((c !== 'x') && (c !== 'X') && (c !== aImsi[i])) {
return false;
}
}
return true;
},
/**
* nsIIcc interface.
*/
iccInfo: null,
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
imsi: null,
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.push(aListener);
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index >= 0) {
this._listeners.splice(index, 1);
}
},
getCardLockEnabled: function(aLockType, aCallback) {
this._radioInterface.sendWorkerMessage("iccGetCardLockEnabled",
{ lockType: aLockType },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifySuccessWithBoolean(aResponse.enabled);
});
},
unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
this._modifyCardLock("iccUnlockCardLock",
{ lockType: aLockType,
password: aPassword,
newPin: aNewPin },
aCallback);
},
setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
this._modifyCardLock("iccSetCardLockEnabled",
{ lockType: aLockType,
password: aPassword,
enabled: aEnabled },
aCallback);
},
changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
this._modifyCardLock("iccChangeCardLockPassword",
{ lockType: aLockType,
password: aPassword,
newPassword: aNewPassword, },
aCallback);
},
getCardLockRetryCount: function(aLockType, aCallback) {
this._radioInterface.sendWorkerMessage("iccGetCardLockRetryCount",
{ lockType: aLockType },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifyGetCardLockRetryCount(aResponse.retryCount);
});
},
matchMvno: function(aMvnoType, aMvnoData, aCallback) {
if (!aMvnoData) {
aCallback.notifyError(RIL.GECKO_ERROR_INVALID_PARAMETER);
return;
}
switch (aMvnoType) {
case Ci.nsIIcc.CARD_MVNO_TYPE_IMSI:
let imsi = this.imsi;
if (!imsi) {
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
break;
}
aCallback.notifySuccessWithBoolean(
this._isImsiMatches(aMvnoData, imsi));
break;
case Ci.nsIIcc.CARD_MVNO_TYPE_SPN:
let spn = this.iccInfo && this.iccInfo.spn;
if (!spn) {
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
break;
}
aCallback.notifySuccessWithBoolean(spn == aMvnoData);
break;
case Ci.nsIIcc.CARD_MVNO_TYPE_GID:
this._radioInterface.sendWorkerMessage("getGID1",
null,
(aResponse) => {
let gid = aResponse.gid1;
let mvnoDataLength = aMvnoData.length;
if (!gid) {
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
} else if (mvnoDataLength > gid.length) {
aCallback.notifySuccessWithBoolean(false);
} else {
let result =
gid.substring(0, mvnoDataLength).toLowerCase() ==
aMvnoData.toLowerCase();
aCallback.notifySuccessWithBoolean(result);
}
});
break;
default:
aCallback.notifyError(RIL.GECKO_ERROR_MODE_NOT_SUPPORTED);
break;
}
},
getServiceStateEnabled: function(aService, aCallback) {
this._radioInterface.sendWorkerMessage("getIccServiceState",
{ service: aService },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifySuccessWithBoolean(aResponse.result);
});
},
iccOpenChannel: function(aAid, aCallback) {
this._radioInterface.sendWorkerMessage("iccOpenChannel",
{ aid: aAid },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifyOpenChannelSuccess(aResponse.channel);
});
},
iccExchangeAPDU: function(aChannel, aCla, aIns, aP1, aP2, aP3, aData, aCallback) {
if (!aData) {
if (DEBUG) debug('data is not set , aP3 : ' + aP3);
}
let apdu = {
cla: aCla,
command: aIns,
p1: aP1,
p2: aP2,
p3: aP3,
data: aData
};
this._radioInterface.sendWorkerMessage("iccExchangeAPDU",
{ channel: aChannel, apdu: apdu },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifyExchangeAPDUResponse(aResponse.sw1,
aResponse.sw2,
aResponse.simResponse);
});
},
iccCloseChannel: function(aChannel, aCallback) {
this._radioInterface.sendWorkerMessage("iccCloseChannel",
{ channel: aChannel },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifyCloseChannelSuccess();
});
},
sendStkResponse: function(aCommand, aResponse) {
let response = gStkCmdFactory.createResponseMessage(aResponse);
response.command = gStkCmdFactory.createCommandMessage(aCommand);
this._radioInterface.sendWorkerMessage("sendStkTerminalResponse", response);
},
sendStkMenuSelection: function(aItemIdentifier, aHelpRequested) {
this._radioInterface
.sendWorkerMessage("sendStkMenuSelection", {
itemIdentifier: aItemIdentifier,
helpRequested: aHelpRequested
});
},
sendStkTimerExpiration: function(aTimerId, aTimerValue) {
this._radioInterface
.sendWorkerMessage("sendStkTimerExpiration",{
timer: {
timerId: aTimerId,
timerValue: aTimerValue
}
});
},
sendStkEventDownload: function(aEvent) {
this._radioInterface
.sendWorkerMessage("sendStkEventDownload",
{ event: gStkCmdFactory.createEventMessage(aEvent) });
},
readContacts: function(aContactType, aCallback) {
this._radioInterface
.sendWorkerMessage("readICCContacts",
{ contactType: aContactType },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
let iccContacts = [];
aResponse.contacts.forEach(c => iccContacts.push(new IccContact(c)));
aCallback.notifyRetrievedIccContacts(iccContacts, iccContacts.length);
});
},
updateContact: function(aContactType, aContact, aPin2, aCallback) {
let iccContact = { contactId: aContact.id };
let count = { value: 0 };
let names = aContact.getNames(count);
if (count.value > 0) {
iccContact.alphaId = names[0];
}
let numbers = aContact.getNumbers(count);
if (count.value > 0) {
iccContact.number = numbers[0];
let anrArray = numbers.slice(1);
let length = anrArray.length;
if (length > 0) {
iccContact.anr = [];
for (let i = 0; i < length; i++) {
iccContact.anr.push(anrArray[i]);
}
}
}
let emails = aContact.getEmails(count);
if (count.value > 0) {
iccContact.email = emails[0];
}
this._radioInterface
.sendWorkerMessage("updateICCContact",
{ contactType: aContactType,
contact: iccContact,
pin2: aPin2 },
(aResponse) => {
if (aResponse.errorMsg) {
aCallback.notifyError(aResponse.errorMsg);
return;
}
aCallback.notifyUpdatedIccContact(new IccContact(aResponse.contact));
});
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IccService]);

Просмотреть файл

@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
component {df854256-9554-11e4-a16c-c39e8d106c26} IccService.js
contract @mozilla.org/icc/gonkiccservice;1 {df854256-9554-11e4-a16c-c39e8d106c26}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
component {7a663440-e336-11e4-8fd5-c3140a7ff307} StkCmdFactory.js
contract @mozilla.org/icc/stkcmdfactory;1 {7a663440-e336-11e4-8fd5-c3140a7ff307}

Просмотреть файл

@ -0,0 +1,21 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIIccContact.idl',
'nsIIccInfo.idl',
'nsIIccService.idl',
'nsIStkCmdFactory.idl',
'nsIStkProactiveCmd.idl',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
XPIDL_SOURCES += [
'nsIGonkIccService.idl',
'nsIIccMessenger.idl',
]
XPIDL_MODULE = 'dom_icc'

Просмотреть файл

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIIccService.idl"
%{C++
#define GONK_ICC_SERVICE_CONTRACTID \
"@mozilla.org/icc/gonkiccservice;1"
%}
[scriptable, uuid(cdcdd800-ef24-11e4-99e7-1f0f5f2576c5)]
interface nsIGonkIccService : nsIIccService
{
void notifyStkCommand(in unsigned long aServiceId, in nsIStkProactiveCmd aStkcommand);
void notifyStkSessionEnd(in unsigned long aServiceId);
void notifyCardStateChanged(in unsigned long aServiceId, in unsigned long aCardState);
void notifyIccInfoChanged(in unsigned long aServiceId, in jsval aIccInfo);
void notifyImsiChanged(in unsigned long aServiceId, in DOMString aImsi);
};

Просмотреть файл

@ -0,0 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, uuid(0f3dbcd1-9f7b-40a8-aa3c-b5701978ec53)]
interface nsIIccContact : nsISupports
{
/**
* The unique identifier of this ICC Contact.
*
* Note: This id is composed of the iccid and its record index of EF_ADN.
*/
readonly attribute DOMString id;
/**
* Name list.
*
* The container of Alpha-Id in EF_ADN and Second Name in EF_SNE of this contact,
* where EF_SNE provides the possibility to store a name in different language.
*
* @see 10.2.1 Support of two name fields per entry, 3GPP TS 21.111.
*
* @param aCount
* The number of names.
*
* @returns the array of names.
*/
void getNames([optional] out unsigned long aCount,
[array, size_is(aCount), retval] out wstring aNames);
/**
* Phone number list.
*
* The container of the dialing numbers of this contact in EF_ADN and EF_ANR.
*
* @see 10.2.2 Support of multiple phone numbers per entry, 3GPP TS 21.111.
*
* @param aCount
* The number of phone numbers.
*
* @returns the array of phone numbers.
*/
void getNumbers([optional] out unsigned long aCount,
[array, size_is(aCount), retval] out wstring aNumbers);
/**
* Email list.
*
* The container of the emails of this contact in EF_EMAIL.
*
* @param aCount
* The number of emails.
*
* @returns the array of emails.
*/
void getEmails([optional] out unsigned long aCount,
[array, size_is(aCount), retval] out wstring aEmails);
};

Просмотреть файл

@ -0,0 +1,70 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, uuid(3ba11a90-34e0-11e4-8c21-0800200c9a66)]
interface nsIIccInfo : nsISupports
{
/**
* Integrated Circuit Card Type.
*
* Possible values: null(unknown), "sim", "usim", "csim", ruim".
*/
readonly attribute DOMString iccType;
/**
* Integrated Circuit Card Identifier.
*/
readonly attribute DOMString iccid;
/**
* Mobile Country Code (MCC) of the subscriber's home network.
*/
readonly attribute DOMString mcc;
/**
* Mobile Network Code (MNC) of the subscriber's home network.
*/
readonly attribute DOMString mnc;
/**
* Service Provider Name (SPN) of the subscriber's home network.
*/
readonly attribute DOMString spn;
/**
* Network name must be a part of displayed carrier name.
*/
readonly attribute boolean isDisplayNetworkNameRequired;
/**
* Service provider name must be a part of displayed carrier name.
*/
readonly attribute boolean isDisplaySpnRequired;
};
[scriptable, uuid(6c9c78b0-34e0-11e4-8c21-0800200c9a66)]
interface nsIGsmIccInfo : nsIIccInfo
{
/**
* Mobile Station ISDN Number (MSISDN) of the subscriber, aka
* his phone number.
*/
readonly attribute DOMString msisdn;
};
[scriptable, uuid(7452f570-34e0-11e4-8c21-0800200c9a66)]
interface nsICdmaIccInfo : nsIIccInfo
{
/**
* Mobile Directory Number (MDN) of the subscriber, aka his phone number.
*/
readonly attribute DOMString mdn;
/**
* Preferred Roaming List (PRL) version of the subscriber.
*/
readonly attribute long prlVersion;
};

Просмотреть файл

@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIStkProactiveCmd;
[scriptable, uuid(000696fe-5d85-11e4-8da2-2fdf3880276b)]
interface nsIIccMessenger : nsISupports
{
/**
* To broadcast 'icc-stkcommand' system message
*
* @param aIccId
* Integrated Circuit Card Identifier.
* @param aCommand
* An instance of nsIStkProactiveCmd or its sub-class.
*/
void notifyStkProactiveCommand(in DOMString aIccId,
in nsIStkProactiveCmd aCommand);
};

Просмотреть файл

@ -0,0 +1,538 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIIcc;
interface nsIIccContact;
interface nsIIccInfo;
interface nsIStkDownloadEvent;
interface nsIStkProactiveCmd;
interface nsIStkTerminalResponse;
[scriptable, uuid(71b33012-eca2-11e4-a40d-9ff040a6fe2a)]
interface nsIIccListener : nsISupports
{
void notifyStkCommand(in nsIStkProactiveCmd aStkProactiveCmd);
void notifyStkSessionEnd();
void notifyCardStateChanged();
void notifyIccInfoChanged();
};
/**
* A callback interface for handling asynchronous response.
*/
[scriptable, uuid(b7b0623f-fb2c-4cec-b0dc-00ac2fe7b296)]
interface nsIIccCallback : nsISupports
{
/**
* The success callback with no result required:
* |unlockCardLock|, |setCardLockEnabled| and |changeCardLockPassword|.
*/
void notifySuccess();
/**
* The success callback with boolean response:
* |getCardLockEnabled|, |matchMvno|, and |getServiceStateEnabled|.
*/
void notifySuccessWithBoolean(in boolean aResult);
/**
* The success callback of |getCardLockRetryCount|.
*
* @param aCount
* The number of remaining retries. -1 if unknown.
*/
void notifyGetCardLockRetryCount(in long aCount);
/**
* The success callback of |readContacts|.
*
* @param aContacts
* The list of contacts retrieved from ICC.
* @param aCount
* The number of contacts retrieved from ICC.
*/
void notifyRetrievedIccContacts([array, size_is(aCount)] in nsIIccContact aContacts,
in uint32_t aCount);
/**
* The success callback of |updateContact|.
*
* @param aContact
* The contact with the updated result.
*/
void notifyUpdatedIccContact(in nsIIccContact aContact);
/**
* The error callback of |getCardLockEnabled|, |getCardLockRetryCount|,
* |matchMvno|, |getServiceStateEnabled|, |readContacts| and |updateContact|.
*
* @param aErrorMsg
* The error message.
*/
void notifyError(in DOMString aErrorMsg);
/**
* The error callback of |unlockCardLock|, |setCardLockEnabled| and
* |changeCardLockPassword|.
*
* @param aErrorMsg
* The error message.
* @param aRetryCount
* The number of remaining retries. -1 if unknown.
*/
void notifyCardLockError(in DOMString aErrorMsg, in long aRetryCount);
};
[scriptable, uuid(6136acab-b50e-494a-a86d-df392a032897)]
interface nsIIccChannelCallback : nsISupports
{
/**
* Callback function to notify on successfully opening a logical channel.
*
* @param channel
* The Channel Number/Handle that is successfully opened.
*/
void notifyOpenChannelSuccess(in long channel);
/**
* Callback function to notify on successfully closing the logical channel.
*
*/
void notifyCloseChannelSuccess();
/**
* Callback function to notify the status of 'iccExchangeAPDU' command.
*
* @param sw1
* Response's First Status Byte
* @param sw2
* Response's Second Status Byte
* @param data
* Response's data
*/
void notifyExchangeAPDUResponse(in octet sw1,
in octet sw2,
in DOMString data);
/**
* Callback function to notify error
*
*/
void notifyError(in DOMString error);
};
%{C++
#define ICC_SERVICE_CID \
{ 0xbab0277a, 0x900e, 0x11e4, { 0x80, 0xc7, 0xdb, 0xd7, 0xad, 0x05, 0x24, 0x01 } }
#define ICC_SERVICE_CONTRACTID \
"@mozilla.org/icc/iccservice;1"
template<typename T> struct already_AddRefed;
%}
/**
* XPCOM Service for the selection of the ICC to be accessed.
*/
[scriptable, uuid(6590a04c-9ca4-11e4-ae95-570876ecc428)]
interface nsIIccService : nsISupports
{
/**
* Get Icc instance with specified Service Id.
*
* @param aServiceId
* Started from 0 to nsIMobileConnectionService.numItems - 1;
*
* @return a nsIcc instance.
*/
nsIIcc getIccByServiceId(in unsigned long aServiceId);
};
%{C++
already_AddRefed<nsIIccService>
NS_CreateIccService();
%}
/**
* XPCOM component that provides the access to the selected ICC.
*/
[scriptable, uuid(1791f102-b081-4435-8555-37eb035fa4e2)]
interface nsIIcc : nsISupports
{
/**
* Card State Constants
*
* Note: MUST be matched with enum IccCardState in MozIcc.webidl!
*/
const unsigned long CARD_STATE_UNKNOWN = 0;
const unsigned long CARD_STATE_READY = 1;
const unsigned long CARD_STATE_PIN_REQUIRED = 2;
const unsigned long CARD_STATE_PUK_REQUIRED = 3;
const unsigned long CARD_STATE_PERMANENT_BLOCKED = 4;
const unsigned long CARD_STATE_PERSONALIZATION_IN_PROGRESS = 5;
const unsigned long CARD_STATE_PERSONALIZATION_READY = 6;
const unsigned long CARD_STATE_NETWORK_LOCKED = 7;
const unsigned long CARD_STATE_NETWORK_SUBSET_LOCKED = 8;
const unsigned long CARD_STATE_CORPORATE_LOCKED = 9;
const unsigned long CARD_STATE_SERVICE_PROVIDER_LOCKED = 10;
const unsigned long CARD_STATE_SIM_LOCKED = 11;
const unsigned long CARD_STATE_NETWORK_PUK_REQUIRED = 12;
const unsigned long CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED = 13;
const unsigned long CARD_STATE_CORPORATE_PUK_REQUIRED = 14;
const unsigned long CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED = 15;
const unsigned long CARD_STATE_SIM_PUK_REQUIRED = 16;
const unsigned long CARD_STATE_NETWORK1_LOCKED = 17;
const unsigned long CARD_STATE_NETWORK2_LOCKED = 18;
const unsigned long CARD_STATE_HRPD_NETWORK_LOCKED = 19;
const unsigned long CARD_STATE_RUIM_CORPORATE_LOCKED = 20;
const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED = 21;
const unsigned long CARD_STATE_RUIM_LOCKED = 22;
const unsigned long CARD_STATE_NETWORK1_PUK_REQUIRED = 23;
const unsigned long CARD_STATE_NETWORK2_PUK_REQUIRED = 24;
const unsigned long CARD_STATE_HRPD_NETWORK_PUK_REQUIRED = 25;
const unsigned long CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
const unsigned long CARD_STATE_RUIM_PUK_REQUIRED = 28;
const unsigned long CARD_STATE_ILLEGAL = 29;
const unsigned long CARD_STATE_UNDETECTED = 4294967295; // UINT32_MAX
/**
* Card Lock Constants
*
* Note: MUST be matched with enum IccLockType in MozIcc.webidl!
*/
const unsigned long CARD_LOCK_TYPE_PIN = 0;
const unsigned long CARD_LOCK_TYPE_PIN2 = 1;
const unsigned long CARD_LOCK_TYPE_PUK = 2;
const unsigned long CARD_LOCK_TYPE_PUK2 = 3;
const unsigned long CARD_LOCK_TYPE_NCK = 4;
const unsigned long CARD_LOCK_TYPE_NSCK = 5;
const unsigned long CARD_LOCK_TYPE_NCK1 = 6;
const unsigned long CARD_LOCK_TYPE_NCK2 = 7;
const unsigned long CARD_LOCK_TYPE_HNCK = 8;
const unsigned long CARD_LOCK_TYPE_CCK = 9;
const unsigned long CARD_LOCK_TYPE_SPCK = 10;
const unsigned long CARD_LOCK_TYPE_PCK = 11;
const unsigned long CARD_LOCK_TYPE_RCCK = 12;
const unsigned long CARD_LOCK_TYPE_RSPCK = 13;
const unsigned long CARD_LOCK_TYPE_NCK_PUK = 14;
const unsigned long CARD_LOCK_TYPE_NSCK_PUK = 15;
const unsigned long CARD_LOCK_TYPE_NCK1_PUK = 16;
const unsigned long CARD_LOCK_TYPE_NCK2_PUK = 17;
const unsigned long CARD_LOCK_TYPE_HNCK_PUK = 18;
const unsigned long CARD_LOCK_TYPE_CCK_PUK = 19;
const unsigned long CARD_LOCK_TYPE_SPCK_PUK = 20;
const unsigned long CARD_LOCK_TYPE_PCK_PUK = 21;
const unsigned long CARD_LOCK_TYPE_RCCK_PUK = 22;
const unsigned long CARD_LOCK_TYPE_RSPCK_PUK = 23;
const unsigned long CARD_LOCK_TYPE_FDN = 24;
/**
* Contact Type Constants
*
* Note: MUST be matched with enum IccContactType in MozIcc.webidl!
*/
const unsigned long CARD_CONTACT_TYPE_ADN = 0;
const unsigned long CARD_CONTACT_TYPE_FDN = 1;
const unsigned long CARD_CONTACT_TYPE_SDN = 2;
/**
* MVNO Type Constants
*
* Note: MUST be matched with enum IccMvnoType in MozIcc.webidl!
*/
const unsigned long CARD_MVNO_TYPE_IMSI = 0;
const unsigned long CARD_MVNO_TYPE_SPN = 1;
const unsigned long CARD_MVNO_TYPE_GID = 2;
/**
* Card Service Constants
*
* Note: MUST be matched with enum IccService in MozIcc.webidl!
*/
const unsigned long CARD_SERVICE_FDN = 0;
/**
* Icc Contact Type Constants
*
* Note: MUST be matched with enum IccContactType in MozIcc.webidl!
*/
const unsigned long CONTACT_TYPE_ADN = 0;
const unsigned long CONTACT_TYPE_FDN = 1;
const unsigned long CONTACT_TYPE_SDN = 2;
/**
* Called to register icc-related changes.
*
* 'mobileconnection' permission is required to register.
*/
void registerListener(in nsIIccListener aListener);
void unregisterListener(in nsIIccListener aListener);
/**
* Information stored in this ICC.
*/
readonly attribute nsIIccInfo iccInfo;
/**
* Indicates the state of this ICC.
*
* One of the CARD_STATE_* values.
*/
readonly attribute unsigned long cardState;
/**
* IMSI of this ICC.
*/
readonly attribute DOMString imsi;
/**
* Get the status of an ICC lock (e.g. the PIN lock).
*
* @param aLockType
* One of the CARD_LOCK_TYPE_* values.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccessWithBoolean() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void getCardLockEnabled(in unsigned long aLockType,
in nsIIccCallback aCallback);
/**
* Unlock a card lock.
*
* @param aLockType
* One of the CARD_LOCK_TYPE_* values.
* @param aPassword
* The password of this lock.
* @param aNewPin (Optional)
* The new PIN to be set after PUK/PUK2 is unlock.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccess() if success.
* nsIIccCallback::notifyCardLockError(), otherwise.
*/
void unlockCardLock(in unsigned long aLockType,
in DOMString aPassword,
in DOMString aNewPin,
in nsIIccCallback aCallback);
/**
* Enable/Disable a card lock.
*
* @param aLockType
* One of the CARD_LOCK_TYPE_* values.
* @param aPassword
* The password of this lock.
* @param aEnabled.
* True to enable the lock. False to disable, otherwise.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccess() if success.
* nsIIccCallback::notifyCardLockError(), otherwise.
*/
void setCardLockEnabled(in unsigned long aLockType,
in DOMString aPassword,
in boolean aEnabled,
in nsIIccCallback aCallback);
/**
* Change the password of a card lock.
*
* @param aLockType
* One of the CARD_LOCK_TYPE_* values.
* @param aPassword
* The password of this lock.
* @param aNewPassword.
* The new password of this lock.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccess() if success.
* nsIIccCallback::notifyCardLockError(), otherwise.
*/
void changeCardLockPassword(in unsigned long aLockType,
in DOMString aPassword,
in DOMString aNewPassword,
in nsIIccCallback aCallback);
/**
* Get the number of remaining tries of a lock.
*
* @param aLockType
* One of the CARD_LOCK_TYPE_* values.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifyGetCardLockRetryCount() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void getCardLockRetryCount(in unsigned long aLockType,
in nsIIccCallback aCallback);
/**
* Verify whether the passed data (matchData) matches with some ICC's field
* according to the mvno type (mvnoType).
*
* @param aMvnoType
* One of CARD_MVNO_TYPE_* values.
* @param aMvnoData
* Data to be compared with ICC's field.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccessWithBoolean() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void matchMvno(in unsigned long aMvnoType,
in DOMString aMvnoData,
in nsIIccCallback aCallback);
/**
* Retrieve the the availability of an icc service.
*
* @param aService
* One of CARD_SERVICE_* values.
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifySuccessWithBoolean() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void getServiceStateEnabled(in unsigned long aService,
in nsIIccCallback aCallback);
/**
* Open Secure Card Icc communication channel
*
* @param aAid
* Card Application Id in this UICC.
* @param aCallback
* An instance of nsIIccChannelCallback.
* nsIIccChannelCallback::notifyOpenChannelSuccess() if success.
* nsIIccChannelCallback::notifyError(), otherwise.
*/
void iccOpenChannel(in DOMString aAid,
in nsIIccChannelCallback aCallback);
/**
* Exchange Command APDU (C-APDU) with UICC on the given logical channel.
* Note that 'P3' parameter could be Le/Lc depending on command APDU case.
* For Case 1 scenario (when only command header is present), the value
* of 'P3' should be set to '-1' explicitly.
* Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases.
*
* @param aChannel
* given logical channel.
* @param aCla
* APDU class.
* @param aIns
* Instruction code.
* @param aP1, aP2, aP3
* P1, P2, P3 parameters in APDU.
* @param aData
* The hex data to be sent by this PDU.
* @param aCallback
* An instance of nsIIccChannelCallback.
* nsIIccChannelCallback::notifyExchangeAPDUResponse() if success.
* nsIIccChannelCallback::notifyError(), otherwise.
*/
void iccExchangeAPDU(in long aChannel,
in octet aCla,
in octet aIns,
in octet aP1,
in octet aP2,
in short aP3,
in DOMString aData,
in nsIIccChannelCallback aCallback);
/**
* Close Secure Card Icc communication channel
*
* @param aChannel
* Channel to be closed.
* @param aCallback
* An instance of nsIIccChannelCallback.
* nsIIccChannelCallback::notifyCloseChannelSuccess() if success.
* nsIIccChannelCallback::notifyError(), otherwise.
*/
void iccCloseChannel(in long aChannel,
in nsIIccChannelCallback aCallback);
/**
* Send STK terminal response to the received proactive command.
*
* @param aCommand
* The received proactive command.
* @param aResponse
* The response to be reply to the card application that issues
* this proactive command.
*/
void sendStkResponse(in nsIStkProactiveCmd aCommand,
in nsIStkTerminalResponse aResponse);
/**
* Send envelope to notify the selected item of the main STK menu.
*
* @param aItemIdentifier
* The identifier of the menu item.
* @param aHelpRequested
* True if help information of the selected item is requested by
* the user.
*/
void sendStkMenuSelection(in unsigned short aItemIdentifier,
in boolean aHelpRequested);
/**
* Send envelope to notify the expiration of a requested timer.
*
* @param aTimerId
* The TimerId provided from previous proactive command.
* @param aTimerValue
* The real used seconds when expired.
*/
void sendStkTimerExpiration(in unsigned short aTimerId,
in unsigned long aTimerValue);
/**
* Send "Event Download" envelope to the ICC.
*
* @param aEvent
* The event that ICC listening to in STK_CMD_SET_UP_EVENT_LIST.
*/
void sendStkEventDownload(in nsIStkDownloadEvent aEvent);
/**
* Read Specified type of Contact from ICC.
*
* @param aContactType
* One of CONTACT_TYPE_*.
*
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifyRetrievedIccContacts() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void readContacts(in unsigned long aContactType,
in nsIIccCallback aCallback);
/**
* Update Specified type of Contact in ICC.
*
* @param aContactType
* One of CONTACT_TYPE_*.
* @param aContact
* an nsIIccContact instance with information to be updated.
* @param aPin2 (Optional)
* The PIN2 required to update FDN contact.
*
* @param aCallback
* An instance of nsIIccCallback:
* nsIIccCallback::notifyUpdatedIccContact() if success.
* nsIIccCallback::notifyError(), otherwise.
*/
void updateContact(in unsigned long aContactType,
in nsIIccContact aContact,
in DOMString aPin2,
in nsIIccCallback aCallback);
};

Просмотреть файл

@ -0,0 +1,140 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
%{C++
#define ICC_STK_CMD_FACTORY_CONTRACTID \
"@mozilla.org/icc/stkcmdfactory;1"
%}
interface nsIStkProactiveCmd;
interface nsIStkTerminalResponse;
interface nsIStkDownloadEvent;
interface nsIStkTimer;
/**
* This StkCmdFactory provides series factory methods to create objects defined
* in nsIStkProactiveCmd.idl and MozStkCommandEvent.webidl.
*/
[scriptable, uuid(743536c4-006f-11e5-a3f7-bf7a7fd59b9b)]
interface nsIStkCmdFactory : nsISupports
{
/**
* @param aCommandDetails
* A JS object which complies with 'dictionary MozStkCommand'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkProactiveCmd instance.
*/
nsIStkProactiveCmd createCommand(in jsval aCommandDetails);
/**
* @param aStkProactiveCmd
* a nsIStkProactiveCmd instance.
*
* @return a JS object which complies with 'dictionary MozStkCommand'
* in MozStkCommandEvent.webidl
*/
jsval createCommandMessage(in nsIStkProactiveCmd aStkProactiveCmd);
/**
* @param aStkProactiveCmd
* a nsIStkProactiveCmd instance.
*
* @return a JSON string which complies with 'dictionary MozStkCommand'
* in MozStkCommandEvent.webidl
*/
AString deflateCommand(in nsIStkProactiveCmd aStkProactiveCmd);
/**
* @param a JSON string which complies with 'dictionary MozStkCommand'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkProactiveCmd instance.
*/
nsIStkProactiveCmd inflateCommand(in AString aJSON);
/**
* @param aResponseMessage
* A JS object which complies with 'dictionary MozStkResponse'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkTerminalResponse instance.
*/
nsIStkTerminalResponse createResponse(in jsval aResponseMessage);
/**
* @param aStkTerminalResponse
* a nsIStkTerminalResponse instance.
*
* @return a JS object which complies with 'dictionary MozStkResponse'
* in MozStkCommandEvent.webidl
*/
jsval createResponseMessage(in nsIStkTerminalResponse aStkTerminalResponse);
/**
* @param aStkTerminalResponse
* a nsIStkTerminalResponse instance.
*
* @return a JSON string which complies with 'dictionary MozStkResponse'
* in MozStkCommandEvent.webidl
*/
AString deflateResponse(in nsIStkTerminalResponse aStkTerminalResponse);
/**
* @param a JSON string which complies with 'dictionary MozStkResponse'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkTerminalResponse instance.
*/
nsIStkTerminalResponse inflateResponse(in AString aJSON);
/**
* @param aEventMessage
* A JS object which complies with 'dictionary MozStkXxxEvent'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkDownloadEvent instance.
*/
nsIStkDownloadEvent createEvent(in jsval aEventMessage);
/**
* @param aStkDownloadEvent
* a nsIStkDownloadEvent instance.
*
* @return a JS object which complies with 'dictionary MozStkXxxEvent'
* in MozStkCommandEvent.webidl
*/
jsval createEventMessage(in nsIStkDownloadEvent aStkDownloadEvent);
/**
* @param aStkDownloadEvent
* a nsIStkDownloadEvent instance.
*
* @return a JSON string which complies with 'dictionary MozStkXxxEvent'
* in MozStkCommandEvent.webidl
*/
AString deflateDownloadEvent(in nsIStkDownloadEvent aStkDownloadEvent);
/**
* @param a JSON string which complies with 'dictionary MozStkXxxEvent'
* in MozStkCommandEvent.webidl
*
* @return a nsIStkDownloadEvent instance.
*/
nsIStkDownloadEvent inflateDownloadEvent(in AString aJSON);
/**
* @param aStkTimerMessage
* a JS object which complies with 'dictionary MozStkTimer'
* in MozStkCommandEvent.webidl
*
* @return an instance of nsIStkTimer with the same timerId and timerValue
* from aStkTimerMessage.
*
* Note: This API is specific to nsIIcc::sendStkTimerExpiration().
*/
nsIStkTimer createTimer(in jsval aStkTimerMessage);
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

481
dom/icc/ipc/IccChild.cpp Normal file
Просмотреть файл

@ -0,0 +1,481 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccInfo.h"
#include "mozilla/dom/icc/IccChild.h"
#include "mozilla/dom/icc/IccIPCUtils.h"
#include "nsIStkCmdFactory.h"
#include "nsIStkProactiveCmd.h"
using mozilla::dom::IccInfo;
namespace mozilla {
namespace dom {
namespace icc {
/**
* PIccChild Implementation.
*/
IccChild::IccChild()
: mCardState(nsIIcc::CARD_STATE_UNKNOWN)
, mIsAlive(true)
{
MOZ_COUNT_CTOR(IccChild);
}
IccChild::~IccChild()
{
MOZ_COUNT_DTOR(IccChild);
}
void
IccChild::Init()
{
OptionalIccInfoData infoData;
bool rv = SendInit(&infoData, &mCardState);
NS_ENSURE_TRUE_VOID(rv);
UpdateIccInfo(infoData);
}
void
IccChild::Shutdown(){
if (mIsAlive) {
mIsAlive = false;
Send__delete__(this);
}
mListeners.Clear();
mIccInfo = nullptr;
mCardState = nsIIcc::CARD_STATE_UNKNOWN;
}
void
IccChild::ActorDestroy(ActorDestroyReason why)
{
mIsAlive = false;
}
bool
IccChild::RecvNotifyCardStateChanged(const uint32_t& aCardState)
{
mCardState = aCardState;
for (int32_t i = 0; i < mListeners.Count(); i++) {
mListeners[i]->NotifyCardStateChanged();
}
return true;
}
bool
IccChild::RecvNotifyIccInfoChanged(const OptionalIccInfoData& aInfoData)
{
UpdateIccInfo(aInfoData);
for (int32_t i = 0; i < mListeners.Count(); i++) {
mListeners[i]->NotifyIccInfoChanged();
}
return true;
}
bool
IccChild::RecvNotifyStkCommand(const nsString& aStkProactiveCmd)
{
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, false);
nsCOMPtr<nsIStkProactiveCmd> cmd;
cmdFactory->InflateCommand(aStkProactiveCmd, getter_AddRefs(cmd));
NS_ENSURE_TRUE(cmd, false);
for (int32_t i = 0; i < mListeners.Count(); i++) {
mListeners[i]->NotifyStkCommand(cmd);
}
return true;
}
bool
IccChild::RecvNotifyStkSessionEnd()
{
for (int32_t i = 0; i < mListeners.Count(); i++) {
mListeners[i]->NotifyStkSessionEnd();
}
return true;
}
PIccRequestChild*
IccChild::AllocPIccRequestChild(const IccRequest& aRequest)
{
MOZ_CRASH("Caller is supposed to manually construct a request!");
}
bool
IccChild::DeallocPIccRequestChild(PIccRequestChild* aActor)
{
delete aActor;
return true;
}
bool
IccChild::SendRequest(const IccRequest& aRequest, nsIIccCallback* aRequestReply)
{
NS_ENSURE_TRUE(mIsAlive, false);
// Deallocated in IccChild::DeallocPIccRequestChild().
IccRequestChild* actor = new IccRequestChild(aRequestReply);
SendPIccRequestConstructor(actor, aRequest);
return true;
}
void
IccChild::UpdateIccInfo(const OptionalIccInfoData& aInfoData) {
if (aInfoData.type() == OptionalIccInfoData::Tvoid_t) {
mIccInfo = nullptr;
return;
}
NS_ENSURE_TRUE_VOID(aInfoData.type() == OptionalIccInfoData::TIccInfoData);
RefPtr<IccInfo> iccInfo;
const IccInfoData& infoData = aInfoData.get_IccInfoData();
if (infoData.iccType().EqualsLiteral("sim")
|| infoData.iccType().EqualsLiteral("usim")) {
iccInfo = new GsmIccInfo(infoData);
} else if (infoData.iccType().EqualsLiteral("ruim")
|| infoData.iccType().EqualsLiteral("csim")){
iccInfo = new CdmaIccInfo(infoData);
} else {
iccInfo = new IccInfo(infoData);
}
// We update the orignal one instead of replacing with a new one
// if the IccType is the same.
if (mIccInfo) {
nsAutoString oldIccType;
nsAutoString newIccType;
mIccInfo->GetIccType(oldIccType);
iccInfo->GetIccType(newIccType);
if (oldIccType.Equals(newIccType)) {
mIccInfo->Update(iccInfo);
return;
}
}
mIccInfo = iccInfo;
}
/**
* nsIIcc Implementation.
*/
NS_IMPL_ISUPPORTS(IccChild, nsIIcc)
NS_IMETHODIMP
IccChild::RegisterListener(nsIIccListener *aListener)
{
NS_ENSURE_TRUE(!mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
mListeners.AppendObject(aListener);
return NS_OK;
}
NS_IMETHODIMP
IccChild::UnregisterListener(nsIIccListener *aListener)
{
NS_ENSURE_TRUE(mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
mListeners.RemoveObject(aListener);
return NS_OK;
}
NS_IMETHODIMP
IccChild::GetIccInfo(nsIIccInfo** aIccInfo)
{
nsCOMPtr<nsIIccInfo> info(mIccInfo);
info.forget(aIccInfo);
return NS_OK;
}
NS_IMETHODIMP
IccChild::GetCardState(uint32_t* aCardState)
{
*aCardState = mCardState;
return NS_OK;
}
NS_IMETHODIMP
IccChild::GetImsi(nsAString & aImsi)
{
NS_WARNING("IMSI shall not directly be fetched in child process.");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
IccChild::GetCardLockEnabled(uint32_t aLockType,
nsIIccCallback* aRequestReply)
{
return SendRequest(GetCardLockEnabledRequest(aLockType), aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::UnlockCardLock(uint32_t aLockType,
const nsAString& aPassword,
const nsAString& aNewPin,
nsIIccCallback* aRequestReply)
{
return SendRequest(UnlockCardLockRequest(aLockType,
nsAutoString(aPassword),
nsAutoString(aNewPin)),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::SetCardLockEnabled(uint32_t aLockType,
const nsAString& aPassword,
bool aEnabled,
nsIIccCallback* aRequestReply)
{
return SendRequest(SetCardLockEnabledRequest(aLockType,
nsAutoString(aPassword),
aEnabled),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::ChangeCardLockPassword(uint32_t aLockType,
const nsAString& aPassword,
const nsAString& aNewPassword,
nsIIccCallback* aRequestReply)
{
return SendRequest(ChangeCardLockPasswordRequest(aLockType,
nsAutoString(aPassword),
nsAutoString(aNewPassword)),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::GetCardLockRetryCount(uint32_t aLockType,
nsIIccCallback* aRequestReply)
{
return SendRequest(GetCardLockRetryCountRequest(aLockType), aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::MatchMvno(uint32_t aMvnoType,
const nsAString& aMvnoData,
nsIIccCallback* aRequestReply)
{
return SendRequest(MatchMvnoRequest(aMvnoType, nsAutoString(aMvnoData)),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::GetServiceStateEnabled(uint32_t aService,
nsIIccCallback* aRequestReply)
{
return SendRequest(GetServiceStateEnabledRequest(aService),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::IccOpenChannel(const nsAString& aAid, nsIIccChannelCallback* aCallback)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
IccChild::IccExchangeAPDU(int32_t aChannel, uint8_t aCla, uint8_t aIns, uint8_t aP1,
uint8_t aP2, int16_t aP3, const nsAString & aData,
nsIIccChannelCallback* aCallback)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
IccChild::IccCloseChannel(int32_t aChannel, nsIIccChannelCallback* aCallback)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
IccChild::SendStkResponse(nsIStkProactiveCmd* aCommand, nsIStkTerminalResponse* aResponse)
{
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, NS_ERROR_FAILURE);
nsAutoString cmd, response;
nsresult rv = cmdFactory->DeflateCommand(aCommand, cmd);
NS_ENSURE_SUCCESS(rv, rv);
rv = cmdFactory->DeflateResponse(aResponse, response);
NS_ENSURE_SUCCESS(rv, rv);
return PIccChild::SendStkResponse(cmd, response) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested)
{
return PIccChild::SendStkMenuSelection(aItemIdentifier, aHelpRequested)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::SendStkTimerExpiration(uint16_t aTimerId, uint32_t aTimerValue)
{
return PIccChild::SendStkTimerExpiration(aTimerId, aTimerValue)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::SendStkEventDownload(nsIStkDownloadEvent* aEvent)
{
MOZ_ASSERT(aEvent);
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, NS_ERROR_FAILURE);
nsAutoString event;
nsresult rv = cmdFactory->DeflateDownloadEvent(aEvent, event);
NS_ENSURE_SUCCESS(rv, rv);
return PIccChild::SendStkEventDownload(event) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::ReadContacts(uint32_t aContactType, nsIIccCallback* aRequestReply)
{
return SendRequest(ReadContactsRequest(aContactType),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccChild::UpdateContact(uint32_t aContactType, nsIIccContact* aContact,
const nsAString& aPin2,
nsIIccCallback* aRequestReply)
{
MOZ_ASSERT(aContact);
IccContactData contactData;
IccIPCUtils::GetIccContactDataFromIccContact(aContact, contactData);
return SendRequest(UpdateContactRequest(aContactType,
nsAutoString(aPin2),
contactData),
aRequestReply)
? NS_OK : NS_ERROR_FAILURE;
}
/**
* PIccRequestChild Implementation.
*/
IccRequestChild::IccRequestChild(nsIIccCallback* aRequestReply)
: mRequestReply(aRequestReply)
{
MOZ_COUNT_CTOR(IccRequestChild);
MOZ_ASSERT(aRequestReply);
}
bool
IccRequestChild::Recv__delete__(const IccReply& aResponse)
{
MOZ_ASSERT(mRequestReply);
switch(aResponse.type()) {
case IccReply::TIccReplySuccess:
return NS_SUCCEEDED(mRequestReply->NotifySuccess());
case IccReply::TIccReplySuccessWithBoolean: {
const IccReplySuccessWithBoolean& resultWithBoolean
= aResponse.get_IccReplySuccessWithBoolean();
return NS_SUCCEEDED(
mRequestReply->NotifySuccessWithBoolean(resultWithBoolean.result()));
}
case IccReply::TIccReplyCardLockRetryCount: {
const IccReplyCardLockRetryCount& retryCount
= aResponse.get_IccReplyCardLockRetryCount();
return NS_SUCCEEDED(
mRequestReply->NotifyGetCardLockRetryCount(retryCount.count()));
}
case IccReply::TIccReplyError: {
const IccReplyError& error = aResponse.get_IccReplyError();
return NS_SUCCEEDED(mRequestReply->NotifyError(error.message()));
}
case IccReply::TIccReplyCardLockError: {
const IccReplyCardLockError& error
= aResponse.get_IccReplyCardLockError();
return NS_SUCCEEDED(
mRequestReply->NotifyCardLockError(error.message(),
error.retryCount()));
}
case IccReply::TIccReplyReadContacts: {
const nsTArray<IccContactData>& data
= aResponse.get_IccReplyReadContacts().contacts();
uint32_t count = data.Length();
nsCOMArray<nsIIccContact> contactList;
nsresult rv;
for (uint32_t i = 0; i < count; i++) {
nsCOMPtr<nsIIccContact> contact;
rv = IccContact::Create(data[i].id(),
data[i].names(),
data[i].numbers(),
data[i].emails(),
getter_AddRefs(contact));
NS_ENSURE_SUCCESS(rv, false);
contactList.AppendElement(contact);
}
rv = mRequestReply->NotifyRetrievedIccContacts(contactList.Elements(),
count);
return NS_SUCCEEDED(rv);
}
case IccReply::TIccReplyUpdateContact: {
IccContactData data
= aResponse.get_IccReplyUpdateContact().contact();
nsCOMPtr<nsIIccContact> contact;
IccContact::Create(data.id(),
data.names(),
data.numbers(),
data.emails(),
getter_AddRefs(contact));
return NS_SUCCEEDED(
mRequestReply->NotifyUpdatedIccContact(contact));
}
default:
MOZ_CRASH("Received invalid response type!");
}
return true;
}
} // namespace icc
} // namespace dom
} // namespace mozilla

94
dom/icc/ipc/IccChild.h Normal file
Просмотреть файл

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccChild_h
#define mozilla_dom_icc_IccChild_h
#include "mozilla/dom/icc/PIccChild.h"
#include "mozilla/dom/icc/PIccRequestChild.h"
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
class IccInfo;
namespace icc {
class IccChild final : public PIccChild
, public nsIIcc
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICC
explicit IccChild();
void
Init();
void
Shutdown();
protected:
virtual void
ActorDestroy(ActorDestroyReason why) override;
virtual PIccRequestChild*
AllocPIccRequestChild(const IccRequest& aRequest) override;
virtual bool
DeallocPIccRequestChild(PIccRequestChild* aActor) override;
virtual bool
RecvNotifyCardStateChanged(const uint32_t& aCardState) override;
virtual bool
RecvNotifyIccInfoChanged(const OptionalIccInfoData& aInfoData) override;
virtual bool
RecvNotifyStkCommand(const nsString& aStkProactiveCmd) override;
virtual bool
RecvNotifyStkSessionEnd() override;
private:
~IccChild();
void
UpdateIccInfo(const OptionalIccInfoData& aInfoData);
bool
SendRequest(const IccRequest& aRequest, nsIIccCallback* aRequestReply);
nsCOMArray<nsIIccListener> mListeners;
RefPtr<IccInfo> mIccInfo;
uint32_t mCardState;
bool mIsAlive;
};
class IccRequestChild final : public PIccRequestChild
{
public:
explicit IccRequestChild(nsIIccCallback* aRequestReply);
protected:
virtual bool
Recv__delete__(const IccReply& aReply) override;
private:
virtual ~IccRequestChild() {
MOZ_COUNT_DTOR(IccRequestChild);
}
nsCOMPtr<nsIIccCallback> mRequestReply;
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccChild_h

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IccIPCService.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
namespace mozilla {
namespace dom {
namespace icc {
NS_IMPL_ISUPPORTS(IccIPCService, nsIIccService)
IccIPCService::IccIPCService()
{
int32_t numRil = Preferences::GetInt("ril.numRadioInterfaces", 1);
mIccs.SetLength(numRil);
}
IccIPCService::~IccIPCService()
{
uint32_t count = mIccs.Length();
for (uint32_t i = 0; i < count; i++) {
if (mIccs[i]) {
mIccs[i]->Shutdown();
}
}
}
NS_IMETHODIMP
IccIPCService::GetIccByServiceId(uint32_t aServiceId, nsIIcc** aIcc)
{
NS_ENSURE_TRUE(aServiceId < mIccs.Length(), NS_ERROR_INVALID_ARG);
if (!mIccs[aServiceId]) {
RefPtr<IccChild> child = new IccChild();
// |SendPIccConstructor| adds another reference to the child
// actor and removes in |DeallocPIccChild|.
ContentChild::GetSingleton()->SendPIccConstructor(child, aServiceId);
child->Init();
mIccs[aServiceId] = child;
}
nsCOMPtr<nsIIcc> icc(mIccs[aServiceId]);
icc.forget(aIcc);
return NS_OK;
}
} // namespace icc
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccIPCService_h
#define mozilla_dom_icc_IccIPCService_h
#include "nsCOMPtr.h"
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
namespace icc {
class IccChild;
class IccIPCService final : public nsIIccService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCSERVICE
IccIPCService();
private:
~IccIPCService();
nsTArray<RefPtr<IccChild>> mIccs;
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccIPCService_h

Просмотреть файл

@ -0,0 +1,92 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/icc/IccIPCUtils.h"
#include "mozilla/dom/icc/PIccTypes.h"
#include "nsIIccContact.h"
#include "nsIIccInfo.h"
namespace mozilla {
namespace dom {
namespace icc {
/*static*/ void
IccIPCUtils::GetIccInfoDataFromIccInfo(nsIIccInfo* aInInfo,
IccInfoData& aOutData)
{
aInInfo->GetIccType(aOutData.iccType());
aInInfo->GetIccid(aOutData.iccid());
aInInfo->GetMcc(aOutData.mcc());
aInInfo->GetMnc(aOutData.mnc());
aInInfo->GetSpn(aOutData.spn());
aInInfo->GetIsDisplayNetworkNameRequired(
&aOutData.isDisplayNetworkNameRequired());
aInInfo->GetIsDisplaySpnRequired(
&aOutData.isDisplaySpnRequired());
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo(do_QueryInterface(aInInfo));
if (gsmIccInfo) {
gsmIccInfo->GetMsisdn(aOutData.phoneNumber());
}
nsCOMPtr<nsICdmaIccInfo> cdmaIccInfo(do_QueryInterface(aInInfo));
if (cdmaIccInfo) {
cdmaIccInfo->GetMdn(aOutData.phoneNumber());
cdmaIccInfo->GetPrlVersion(&aOutData.prlVersion());
}
}
/*static*/ void
IccIPCUtils::GetIccContactDataFromIccContact(nsIIccContact* aContact,
IccContactData& aOutData){
// Id
nsresult rv = aContact->GetId(aOutData.id());
NS_ENSURE_SUCCESS_VOID(rv);
// Names
char16_t** rawStringArray = nullptr;
uint32_t count = 0;
rv = aContact->GetNames(&count, &rawStringArray);
NS_ENSURE_SUCCESS_VOID(rv);
if (count > 0) {
for (uint32_t i = 0; i < count; i++) {
aOutData.names().AppendElement(
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: NullString());
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
// Numbers
rawStringArray = nullptr;
count = 0;
rv = aContact->GetNumbers(&count, &rawStringArray);
NS_ENSURE_SUCCESS_VOID(rv);
if (count > 0) {
for (uint32_t i = 0; i < count; i++) {
aOutData.numbers().AppendElement(
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: NullString());
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
// Emails
rawStringArray = nullptr;
count = 0;
rv = aContact->GetEmails(&count, &rawStringArray);
NS_ENSURE_SUCCESS_VOID(rv);
if (count > 0) {
for (uint32_t i = 0; i < count; i++) {
aOutData.emails().AppendElement(
rawStringArray[i] ? nsDependentString(rawStringArray[i])
: NullString());
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
}
}
} // namespace icc
} // namespace dom
} // namespace mozilla

35
dom/icc/ipc/IccIPCUtils.h Normal file
Просмотреть файл

@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccIPCUtils_h
#define mozilla_dom_icc_IccIPCUtils_h
class nsIIccContact;
class nsIIccInfo;
namespace mozilla {
namespace dom {
namespace icc {
class IccInfoData;
class IccContactData;
class IccIPCUtils
{
public:
static void GetIccInfoDataFromIccInfo(nsIIccInfo* aInInfo,
IccInfoData& aOutData);
static void GetIccContactDataFromIccContact(nsIIccContact* aContact,
IccContactData& aOutData);
private:
IccIPCUtils() {}
virtual ~IccIPCUtils() {}
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccIPCUtils_h

424
dom/icc/ipc/IccParent.cpp Normal file
Просмотреть файл

@ -0,0 +1,424 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/icc/IccIPCUtils.h"
#include "mozilla/dom/icc/IccParent.h"
#include "nsIIccService.h"
#include "nsIStkCmdFactory.h"
#include "nsIStkProactiveCmd.h"
namespace mozilla {
namespace dom {
namespace icc {
/**
* PIccParent Implementation.
*/
IccParent::IccParent(uint32_t aServiceId)
{
MOZ_COUNT_CTOR(IccParent);
nsCOMPtr<nsIIccService> service =
do_GetService(ICC_SERVICE_CONTRACTID);
NS_ASSERTION(service, "Failed to get IccService!");
service->GetIccByServiceId(aServiceId, getter_AddRefs(mIcc));
NS_ASSERTION(mIcc, "Failed to get Icc with specified serviceId.");
mIcc->RegisterListener(this);
}
void
IccParent::ActorDestroy(ActorDestroyReason aWhy)
{
if (mIcc) {
mIcc->UnregisterListener(this);
mIcc = nullptr;
}
}
bool
IccParent::RecvInit(OptionalIccInfoData* aInfoData,
uint32_t* aCardState)
{
NS_ENSURE_TRUE(mIcc, false);
nsresult rv = mIcc->GetCardState(aCardState);
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIIccInfo> iccInfo;
rv = mIcc->GetIccInfo(getter_AddRefs(iccInfo));
NS_ENSURE_SUCCESS(rv, false);
if (iccInfo) {
IccInfoData data;
IccIPCUtils::GetIccInfoDataFromIccInfo(iccInfo, data);
*aInfoData = OptionalIccInfoData(data);
return true;
}
*aInfoData = OptionalIccInfoData(void_t());
return true;
}
bool
IccParent::RecvStkResponse(const nsString& aCmd, const nsString& aResponse)
{
NS_ENSURE_TRUE(mIcc, false);
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, false);
nsCOMPtr<nsIStkProactiveCmd> cmd;
cmdFactory->InflateCommand(aCmd, getter_AddRefs(cmd));
NS_ENSURE_TRUE(cmd, false);
nsCOMPtr<nsIStkTerminalResponse> response;
cmdFactory->InflateResponse(aResponse, getter_AddRefs(response));
NS_ENSURE_TRUE(response, false);
nsresult rv = mIcc->SendStkResponse(cmd, response);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
bool
IccParent::RecvStkMenuSelection(const uint16_t& aItemIdentifier,
const bool& aHelpRequested)
{
NS_ENSURE_TRUE(mIcc, false);
nsresult rv = mIcc->SendStkMenuSelection(aItemIdentifier, aHelpRequested);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
bool
IccParent::RecvStkTimerExpiration(const uint16_t& aTimerId,
const uint32_t& aTimerValue)
{
NS_ENSURE_TRUE(mIcc, false);
nsresult rv = mIcc->SendStkTimerExpiration(aTimerId, aTimerValue);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
bool
IccParent::RecvStkEventDownload(const nsString& aEvent)
{
NS_ENSURE_TRUE(mIcc, false);
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, false);
nsCOMPtr<nsIStkDownloadEvent> event;
cmdFactory->InflateDownloadEvent(aEvent, getter_AddRefs(event));
NS_ENSURE_TRUE(event, false);
nsresult rv = mIcc->SendStkEventDownload(event);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
PIccRequestParent*
IccParent::AllocPIccRequestParent(const IccRequest& aRequest)
{
NS_ASSERTION(mIcc, "AllocPIccRequestParent after actor was destroyed!");
IccRequestParent* actor = new IccRequestParent(mIcc);
// Add an extra ref for IPDL. Will be released in
// IccParent::DeallocPIccRequestParent().
actor->AddRef();
return actor;
}
bool
IccParent::DeallocPIccRequestParent(PIccRequestParent* aActor)
{
// IccRequestParent is refcounted, must not be freed manually.
static_cast<IccRequestParent*>(aActor)->Release();
return true;
}
bool
IccParent::RecvPIccRequestConstructor(PIccRequestParent* aActor,
const IccRequest& aRequest)
{
NS_ASSERTION(mIcc, "RecvPIccRequestConstructor after actor was destroyed!");
IccRequestParent* actor = static_cast<IccRequestParent*>(aActor);
switch (aRequest.type()) {
case IccRequest::TGetCardLockEnabledRequest:
return actor->DoRequest(aRequest.get_GetCardLockEnabledRequest());
case IccRequest::TUnlockCardLockRequest:
return actor->DoRequest(aRequest.get_UnlockCardLockRequest());
case IccRequest::TSetCardLockEnabledRequest:
return actor->DoRequest(aRequest.get_SetCardLockEnabledRequest());
case IccRequest::TChangeCardLockPasswordRequest:
return actor->DoRequest(aRequest.get_ChangeCardLockPasswordRequest());
case IccRequest::TGetCardLockRetryCountRequest:
return actor->DoRequest(aRequest.get_GetCardLockRetryCountRequest());
case IccRequest::TMatchMvnoRequest:
return actor->DoRequest(aRequest.get_MatchMvnoRequest());
case IccRequest::TGetServiceStateEnabledRequest:
return actor->DoRequest(aRequest.get_GetServiceStateEnabledRequest());
case IccRequest::TReadContactsRequest:
return actor->DoRequest(aRequest.get_ReadContactsRequest());
case IccRequest::TUpdateContactRequest:
return actor->DoRequest(aRequest.get_UpdateContactRequest());
default:
MOZ_CRASH("Received invalid request type!");
}
return true;
}
/**
* nsIIccListener Implementation.
*/
NS_IMPL_ISUPPORTS(IccParent, nsIIccListener)
NS_IMETHODIMP
IccParent::NotifyStkCommand(nsIStkProactiveCmd *aStkProactiveCmd)
{
nsCOMPtr<nsIStkCmdFactory> cmdFactory =
do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
NS_ENSURE_TRUE(cmdFactory, NS_ERROR_UNEXPECTED);
nsAutoString cmd;
nsresult rv = cmdFactory->DeflateCommand(aStkProactiveCmd, cmd);
NS_ENSURE_SUCCESS(rv, rv);
return SendNotifyStkCommand(cmd) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccParent::NotifyStkSessionEnd()
{
return SendNotifyStkSessionEnd() ? NS_OK : NS_ERROR_FAILURE;;
}
NS_IMETHODIMP
IccParent::NotifyCardStateChanged()
{
NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
uint32_t cardState;
nsresult rv = mIcc->GetCardState(&cardState);
NS_ENSURE_SUCCESS(rv, rv);
return SendNotifyCardStateChanged(cardState) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
IccParent::NotifyIccInfoChanged()
{
NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
nsCOMPtr<nsIIccInfo> iccInfo;
nsresult rv = mIcc->GetIccInfo(getter_AddRefs(iccInfo));
NS_ENSURE_SUCCESS(rv, rv);
if (!iccInfo) {
return SendNotifyIccInfoChanged(OptionalIccInfoData(void_t()))
? NS_OK : NS_ERROR_FAILURE;
}
IccInfoData data;
IccIPCUtils::GetIccInfoDataFromIccInfo(iccInfo, data);
return SendNotifyIccInfoChanged(OptionalIccInfoData(data))
? NS_OK : NS_ERROR_FAILURE;
}
/**
* PIccRequestParent Implementation.
*/
IccRequestParent::IccRequestParent(nsIIcc* aIcc)
: mIcc(aIcc)
{
MOZ_COUNT_CTOR(IccRequestParent);
}
void
IccRequestParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIcc = nullptr;
}
bool
IccRequestParent::DoRequest(const GetCardLockEnabledRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->GetCardLockEnabled(aRequest.lockType(),
this));
}
bool
IccRequestParent::DoRequest(const UnlockCardLockRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->UnlockCardLock(aRequest.lockType(),
aRequest.password(),
aRequest.newPin(),
this));
}
bool
IccRequestParent::DoRequest(const SetCardLockEnabledRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->SetCardLockEnabled(aRequest.lockType(),
aRequest.password(),
aRequest.enabled(),
this));
}
bool
IccRequestParent::DoRequest(const ChangeCardLockPasswordRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->ChangeCardLockPassword(aRequest.lockType(),
aRequest.password(),
aRequest.newPassword(),
this));
}
bool
IccRequestParent::DoRequest(const GetCardLockRetryCountRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->GetCardLockRetryCount(aRequest.lockType(),
this));
}
bool
IccRequestParent::DoRequest(const MatchMvnoRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->MatchMvno(aRequest.mvnoType(),
aRequest.mvnoData(),
this));
}
bool
IccRequestParent::DoRequest(const GetServiceStateEnabledRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->GetServiceStateEnabled(aRequest.service(),
this));
}
bool
IccRequestParent::DoRequest(const ReadContactsRequest& aRequest)
{
return NS_SUCCEEDED(mIcc->ReadContacts(aRequest.contactType(),
this));
}
bool
IccRequestParent::DoRequest(const UpdateContactRequest& aRequest)
{
nsCOMPtr<nsIIccContact> contact;
nsresult rv = IccContact::Create(aRequest.contact().id(),
aRequest.contact().names(),
aRequest.contact().numbers(),
aRequest.contact().emails(),
getter_AddRefs(contact));
NS_ENSURE_SUCCESS(rv, false);
return NS_SUCCEEDED(mIcc->UpdateContact(aRequest.contactType(),
contact,
aRequest.pin2(),
this));
}
nsresult
IccRequestParent::SendReply(const IccReply& aReply)
{
NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE;
}
/**
* nsIIccCallback Implementation.
*/
NS_IMPL_ISUPPORTS(IccRequestParent, nsIIccCallback)
NS_IMETHODIMP
IccRequestParent::NotifySuccess()
{
return SendReply(IccReplySuccess());
}
NS_IMETHODIMP
IccRequestParent::NotifySuccessWithBoolean(bool aResult)
{
return SendReply(IccReplySuccessWithBoolean(aResult));
}
NS_IMETHODIMP
IccRequestParent::NotifyGetCardLockRetryCount(int32_t aCount)
{
return SendReply(IccReplyCardLockRetryCount(aCount));
}
NS_IMETHODIMP
IccRequestParent::NotifyError(const nsAString & aErrorMsg)
{
return SendReply(IccReplyError(nsAutoString(aErrorMsg)));
}
NS_IMETHODIMP
IccRequestParent::NotifyCardLockError(const nsAString & aErrorMsg,
int32_t aRetryCount)
{
return SendReply(IccReplyCardLockError(aRetryCount, nsAutoString(aErrorMsg)));
}
NS_IMETHODIMP
IccRequestParent::NotifyRetrievedIccContacts(nsIIccContact** aContacts,
unsigned int aCount)
{
nsTArray<IccContactData> contacts;
for (uint32_t i = 0; i < aCount; i++) {
MOZ_ASSERT(aContacts[i]);
IccContactData contactData;
IccIPCUtils::GetIccContactDataFromIccContact(aContacts[i], contactData);
contacts.AppendElement(contactData);
}
return SendReply(IccReplyReadContacts(contacts));
}
NS_IMETHODIMP
IccRequestParent::NotifyUpdatedIccContact(nsIIccContact* aContact)
{
MOZ_ASSERT(aContact);
IccContactData contactData;
IccIPCUtils::GetIccContactDataFromIccContact(aContact, contactData);
return SendReply(IccReplyUpdateContact(contactData));
}
} // namespace icc
} // namespace dom
} // namespace mozilla

129
dom/icc/ipc/IccParent.h Normal file
Просмотреть файл

@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_icc_IccParent_h
#define mozilla_dom_icc_IccParent_h
#include "mozilla/dom/icc/PIccParent.h"
#include "mozilla/dom/icc/PIccRequestParent.h"
#include "nsIIccService.h"
namespace mozilla {
namespace dom {
namespace icc {
class IccParent final : public PIccParent
, public nsIIccListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCLISTENER
explicit IccParent(uint32_t aServiceId);
protected:
virtual
~IccParent()
{
MOZ_COUNT_DTOR(IccParent);
}
virtual void
ActorDestroy(ActorDestroyReason aWhy) override;
virtual bool
RecvInit(
OptionalIccInfoData* aInfoData,
uint32_t* aCardState) override;
virtual bool
RecvStkResponse(const nsString& aCmd, const nsString& aResponse) override;
virtual bool
RecvStkMenuSelection(const uint16_t& aItemIdentifier,
const bool& aHelpRequested) override;
virtual bool
RecvStkTimerExpiration(const uint16_t& aTimerId,
const uint32_t& aTimerValue) override;
virtual bool
RecvStkEventDownload(const nsString& aEvent) override;
virtual PIccRequestParent*
AllocPIccRequestParent(const IccRequest& aRequest) override;
virtual bool
DeallocPIccRequestParent(PIccRequestParent* aActor) override;
virtual bool
RecvPIccRequestConstructor(PIccRequestParent* aActor,
const IccRequest& aRequest) override;
private:
IccParent();
nsCOMPtr<nsIIcc> mIcc;
};
class IccRequestParent final : public PIccRequestParent
, public nsIIccCallback
{
friend class IccParent;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCCALLBACK
explicit IccRequestParent(nsIIcc* icc);
protected:
virtual void
ActorDestroy(ActorDestroyReason why) override;
private:
~IccRequestParent()
{
MOZ_COUNT_DTOR(IccRequestParent);
}
bool
DoRequest(const GetCardLockEnabledRequest& aRequest);
bool
DoRequest(const UnlockCardLockRequest& aRequest);
bool
DoRequest(const SetCardLockEnabledRequest& aRequest);
bool
DoRequest(const ChangeCardLockPasswordRequest& aRequest);
bool
DoRequest(const GetCardLockRetryCountRequest& aRequest);
bool
DoRequest(const MatchMvnoRequest& aRequest);
bool
DoRequest(const GetServiceStateEnabledRequest& aRequest);
bool
DoRequest(const ReadContactsRequest& aRequest);
bool
DoRequest(const UpdateContactRequest& aRequest);
nsresult
SendReply(const IccReply& aReply);
nsCOMPtr<nsIIcc> mIcc;
};
} // namespace icc
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_icc_IccParent_h

166
dom/icc/ipc/PIcc.ipdl Normal file
Просмотреть файл

@ -0,0 +1,166 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PContent;
include protocol PIccRequest;
include PIccTypes;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
namespace icc {
union OptionalIccInfoData
{
void_t;
IccInfoData;
};
struct GetCardLockEnabledRequest
{
uint32_t lockType;
};
struct UnlockCardLockRequest
{
uint32_t lockType;
nsString password;
nsString newPin;
};
struct SetCardLockEnabledRequest
{
uint32_t lockType;
nsString password;
bool enabled;
};
struct ChangeCardLockPasswordRequest
{
uint32_t lockType;
nsString password;
nsString newPassword;
};
struct GetCardLockRetryCountRequest
{
uint32_t lockType;
};
struct MatchMvnoRequest
{
uint32_t mvnoType;
nsString mvnoData;
};
struct GetServiceStateEnabledRequest
{
uint32_t service;
};
struct ReadContactsRequest
{
uint32_t contactType;
};
struct UpdateContactRequest
{
uint32_t contactType;
nsString pin2;
IccContactData contact;
};
union IccRequest
{
GetCardLockEnabledRequest;
UnlockCardLockRequest;
SetCardLockEnabledRequest;
ChangeCardLockPasswordRequest;
GetCardLockRetryCountRequest;
MatchMvnoRequest;
GetServiceStateEnabledRequest;
ReadContactsRequest;
UpdateContactRequest;
};
sync protocol PIcc
{
manager PContent;
manages PIccRequest;
child:
/**
* Notify CardStateChanged with updated CardState.
*/
async NotifyCardStateChanged(uint32_t aCardState);
/**
* Notify IccInfoChanged with updated IccInfo.
*/
async NotifyIccInfoChanged(OptionalIccInfoData aInfoData);
/**
* Notify STK proactive command issue by selected UICC.
*
* @param aStkProactiveCmd
* a MozStkCommand instance serialized in JSON.
*/
async NotifyStkCommand(nsString aStkProactiveCmd);
/**
* Notify that STK session is ended by selected UICC.
*/
async NotifyStkSessionEnd();
parent:
/**
* Sent when the child no longer needs to use PIcc.
*/
async __delete__();
/**
* Sent when the child makes an asynchronous request to the parent.
*/
async PIccRequest(IccRequest aRequest);
/**
* Send STK response to the selected UICC.
*
* @param aCommand
* a MozStkCommand instance serialized in JSON.
* @param aResponse
* a MozStkResponse instance serialized in JSON.
*/
async StkResponse(nsString aCommand, nsString aResponse);
/**
* Send STK Menu Selection to the selected UICC.
*/
async StkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested);
/**
* Send STK Timer Expiration to the selected UICC.
*/
async StkTimerExpiration(uint16_t aTimerId, uint32_t aTimerValue);
/**
* Send STK Event Download to the selected UICC.
*
* @param aEvent
* a MozStkXxxEvent instance serialized in JSON.
*/
async StkEventDownload(nsString aEvent);
/**
* Sync call to initialize the updated IccInfo/CardState.
*/
sync Init()
returns (OptionalIccInfoData aInfoData, uint32_t aCardState);
};
} // namespace icc
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PIcc;
include PIccTypes;
namespace mozilla {
namespace dom {
namespace icc {
struct IccReplySuccess
{
};
struct IccReplySuccessWithBoolean
{
bool result;
};
struct IccReplyCardLockRetryCount
{
int32_t count;
};
struct IccReplyError
{
nsString message;
};
struct IccReplyCardLockError
{
int32_t retryCount;
nsString message;
};
struct IccReplyReadContacts
{
IccContactData[] contacts;
};
struct IccReplyUpdateContact
{
IccContactData contact;
};
union IccReply
{
// Success
IccReplySuccess;
IccReplySuccessWithBoolean;
IccReplyCardLockRetryCount;
IccReplyReadContacts;
IccReplyUpdateContact;
// Error
IccReplyError;
IccReplyCardLockError;
};
protocol PIccRequest
{
manager PIcc;
child:
/**
* Sent when the asynchronous request has completed.
*/
async __delete__(IccReply response);
};
} // namespace icc
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace mozilla {
namespace dom {
namespace icc {
struct IccInfoData
{
nsString iccType;
nsString iccid;
nsString mcc;
nsString mnc;
nsString spn;
bool isDisplayNetworkNameRequired;
bool isDisplaySpnRequired;
nsString phoneNumber;
int32_t prlVersion;
};
struct IccContactData
{
nsString id;
nsString[] names;
nsString[] numbers;
nsString[] emails;
};
} // namespace icc
} // namespace dom
} // namespace mozilla

57
dom/icc/moz.build Normal file
Просмотреть файл

@ -0,0 +1,57 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ['interfaces']
EXPORTS.mozilla.dom += [
'Icc.h',
'IccCardLockError.h',
'IccInfo.h',
'IccManager.h',
]
EXPORTS.mozilla.dom.icc += [
'ipc/IccChild.h',
'ipc/IccIPCUtils.h',
'ipc/IccParent.h'
]
UNIFIED_SOURCES += [
'Assertions.cpp',
'Icc.cpp',
'IccCallback.cpp',
'IccCardLockError.cpp',
'IccContact.cpp',
"IccInfo.cpp",
'IccListener.cpp',
'IccManager.cpp',
'ipc/IccChild.cpp',
'ipc/IccIPCService.cpp',
'ipc/IccIPCUtils.cpp',
'ipc/IccParent.cpp',
]
IPDL_SOURCES += [
'ipc/PIcc.ipdl',
'ipc/PIccRequest.ipdl',
'ipc/PIccTypes.ipdlh',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
EXTRA_COMPONENTS += [
'gonk/IccService.js',
'gonk/IccService.manifest',
'gonk/StkCmdFactory.js',
'gonk/StkCmdFactory.manifest'
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/system/gonk',
]

Просмотреть файл

@ -0,0 +1,539 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
const PREF_KEY_RIL_DEBUGGING_ENABLED = "ril.debugging.enabled";
// The pin code hard coded in emulator is "0000".
const DEFAULT_PIN = "0000";
// The puk code hard coded in emulator is "12345678".
const DEFAULT_PUK = "12345678";
const WHT = 0xFFFFFFFF;
const BLK = 0x000000FF;
const RED = 0xFF0000FF;
const GRN = 0x00FF00FF;
const BLU = 0x0000FFFF;
const TSP = 0;
// Basic Image, see record number 1 in EFimg.
const BASIC_ICON = {
width: 8,
height: 8,
codingScheme: "basic",
pixels: [WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT,
BLK, BLK, BLK, BLK, BLK, BLK, WHT, WHT,
WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT,
WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT,
WHT, WHT, BLK, BLK, BLK, BLK, WHT, WHT,
WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT]
};
// Color Image, see record number 3 in EFimg.
const COLOR_ICON = {
width: 8,
height: 8,
codingScheme: "color",
pixels: [BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU,
BLU, RED, RED, RED, RED, RED, RED, BLU,
BLU, RED, GRN, GRN, GRN, RED, RED, BLU,
BLU, RED, RED, GRN, GRN, RED, RED, BLU,
BLU, RED, RED, GRN, GRN, RED, RED, BLU,
BLU, RED, RED, GRN, GRN, GRN, RED, BLU,
BLU, RED, RED, RED, RED, RED, RED, BLU,
BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU]
};
// Color Image with Transparency, see record number 5 in EFimg.
const COLOR_TRANSPARENCY_ICON = {
width: 8,
height: 8,
codingScheme: "color-transparency",
pixels: [TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP,
TSP, RED, RED, RED, RED, RED, RED, TSP,
TSP, RED, GRN, GRN, GRN, RED, RED, TSP,
TSP, RED, RED, GRN, GRN, RED, RED, TSP,
TSP, RED, RED, GRN, GRN, RED, RED, TSP,
TSP, RED, RED, GRN, GRN, GRN, RED, TSP,
TSP, RED, RED, RED, RED, RED, RED, TSP,
TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP]
};
/**
* Helper function for checking stk icon.
*/
function isIcons(aIcons, aExpectedIcons) {
is(aIcons.length, aExpectedIcons.length, "icons.length");
for (let i = 0; i < aIcons.length; i++) {
let icon = aIcons[i];
let expectedIcon = aExpectedIcons[i];
is(icon.width, expectedIcon.width, "icon.width");
is(icon.height, expectedIcon.height, "icon.height");
is(icon.codingScheme, expectedIcon.codingScheme, "icon.codingScheme");
is(icon.pixels.length, expectedIcon.pixels.length);
for (let j = 0; j < icon.pixels.length; j++) {
is(icon.pixels[j], expectedIcon.pixels[j], "icon.pixels[" + j + "]");
}
}
}
/**
* Helper function for checking stk text.
*/
function isStkText(aStkText, aExpectedStkText) {
is(aStkText.text, aExpectedStkText.text, "stkText.text");
if (aExpectedStkText.icons) {
is(aStkText.iconSelfExplanatory, aExpectedStkText.iconSelfExplanatory,
"stkText.iconSelfExplanatory");
isIcons(aStkText.icons, aExpectedStkText.icons);
}
}
var _pendingEmulatorCmdCount = 0;
/**
* Send emulator command with safe guard.
*
* We should only call |finish()| after all emulator command transactions
* end, so here comes with the pending counter. Resolve when the emulator
* gives positive response, and reject otherwise.
*
* Fulfill params:
* result -- an array of emulator response lines.
* Reject params:
* result -- an array of emulator response lines.
*
* @param aCommand
* A string command to be passed to emulator through its telnet console.
*
* @return A deferred promise.
*/
function runEmulatorCmdSafe(aCommand) {
return new Promise(function(aResolve, aReject) {
++_pendingEmulatorCmdCount;
runEmulatorCmd(aCommand, function(aResult) {
--_pendingEmulatorCmdCount;
ok(true, "Emulator response: " + JSON.stringify(aResult));
if (Array.isArray(aResult) &&
aResult[aResult.length - 1] === "OK") {
aResolve(aResult);
} else {
aReject(aResult);
}
});
});
}
/**
* Send stk proactive pdu.
*
* Fulfill params:
* result -- an array of emulator response lines.
* Reject params:
* result -- an array of emulator response lines.
*
* @param aPdu
*
* @return A deferred promise.
*/
function sendEmulatorStkPdu(aPdu) {
let cmd = "stk pdu " + aPdu;
return runEmulatorCmdSafe(cmd);
}
/**
* Peek the last STK terminal response sent to modem.
*
* Fulfill params:
* result -- last terminal response in HEX String.
* Reject params:
* result -- an array of emulator response lines.
*
* @return A deferred promise.
*/
function peekLastStkResponse() {
return runEmulatorCmdSafe("stk lastresponse")
.then(aResult => aResult[0]);
}
/**
* Peek the last STK envelope sent to modem.
*
* Fulfill params:
* result -- last envelope in HEX String.
* Reject params:
* result -- an array of emulator response lines.
*
* @return A deferred promise.
*/
function peekLastStkEnvelope() {
return runEmulatorCmdSafe("stk lastenvelope")
.then(aResult => aResult[0]);
}
/**
* Verify with the peeked STK response.
*
* Fulfill params:
* result -- (none)
* Reject params:
* result -- an array of emulator response lines.
*
* @param aExpectResponse
* The expected Response PDU in HEX String.
*
* @return A deferred promise.
*/
function verifyWithPeekedStkResponse(aExpectResponse) {
return new Promise(function(aResolve, aReject) {
window.setTimeout(function() {
peekLastStkResponse().then(aResult => {
is(aResult, aExpectResponse, "Verify sent APDU");
aResolve();
});
}, 3000);
});
}
/**
* Verify with the peeked STK response.
*
* Fulfill params:
* result -- (none)
* Reject params:
* result -- an array of emulator response lines.
*
* @param aExpectEnvelope
* The expected Envelope PDU in HEX String.
*
* @return A deferred promise.
*/
function verifyWithPeekedStkEnvelope(aExpectEnvelope) {
return new Promise(function(aResolve, aReject) {
window.setTimeout(function() {
peekLastStkEnvelope().then(aResult => {
is(aResult, aExpectEnvelope, "Verify sent APDU");
aResolve();
});
}, 3000);
});
}
var workingFrame;
var iccManager;
/**
* Push required permissions and test if
* |navigator.mozIccManager| exists. Resolve if it does,
* reject otherwise.
*
* Fulfill params:
* iccManager -- an reference to navigator.mozIccManager.
*
* Reject params: (none)
*
* @param aAdditonalPermissions [optional]
* An array of permission strings other than "mobileconnection" to be
* pushed. Default: empty string.
*
* @return A deferred promise.
*/
function ensureIccManager(aAdditionalPermissions) {
return new Promise(function(aResolve, aReject) {
aAdditionalPermissions = aAdditionalPermissions || [];
if (aAdditionalPermissions.indexOf("mobileconnection") < 0) {
aAdditionalPermissions.push("mobileconnection");
}
let permissions = [];
for (let perm of aAdditionalPermissions) {
permissions.push({ "type": perm, "allow": 1, "context": document });
}
SpecialPowers.pushPermissions(permissions, function() {
ok(true, "permissions pushed: " + JSON.stringify(permissions));
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator.
workingFrame = document.createElement("iframe");
workingFrame.addEventListener("load", function load() {
workingFrame.removeEventListener("load", load);
iccManager = workingFrame.contentWindow.navigator.mozIccManager;
if (iccManager) {
ok(true, "navigator.mozIccManager is instance of " + iccManager.constructor);
} else {
ok(true, "navigator.mozIccManager is undefined");
}
if (iccManager instanceof MozIccManager) {
aResolve(iccManager);
} else {
aReject();
}
});
document.body.appendChild(workingFrame);
});
});
}
/**
* Get MozIcc by IccId
*
* @param aIccId [optional]
* Default: The first item of |aIccManager.iccIds|.
*
* @return A MozIcc.
*/
function getMozIcc(aIccId) {
aIccId = aIccId || iccManager.iccIds[0];
if (!aIccId) {
ok(true, "iccManager.iccIds[0] is undefined");
return null;
}
return iccManager.getIccById(aIccId);
}
/**
* Get MozMobileConnection by ServiceId
*
* @param aServiceId [optional]
* A numeric DSDS service id. Default: 0 if not indicated.
*
* @return A MozMobileConnection.
*/
function getMozMobileConnectionByServiceId(aServiceId) {
aServiceId = aServiceId || 0;
return workingFrame.contentWindow.navigator.mozMobileConnections[aServiceId];
}
/**
* Set radio enabling state.
*
* Resolve no matter the request succeeds or fails. Never reject.
*
* Fulfill params: (none)
*
* @param aEnabled
* A boolean state.
* @param aServiceId [optional]
* A numeric DSDS service id.
*
* @return A deferred promise.
*/
function setRadioEnabled(aEnabled, aServiceId) {
return getMozMobileConnectionByServiceId(aServiceId).setRadioEnabled(aEnabled)
.then(() => {
ok(true, "setRadioEnabled " + aEnabled + " on " + aServiceId + " success.");
}, (aError) => {
ok(false, "setRadioEnabled " + aEnabled + " on " + aServiceId + " " +
aError.name);
});
}
/**
* Wait for one named event.
*
* Resolve if that named event occurs. Never reject.
*
* Fulfill params: the DOMEvent passed.
*
* @param aEventTarget
* An EventTarget object.
* @param aEventName
* A string event name.
* @param aMatchFun [optional]
* A matching function returns true or false to filter the event.
*
* @return A deferred promise.
*/
function waitForTargetEvent(aEventTarget, aEventName, aMatchFun) {
return new Promise(function(aResolve, aReject) {
aEventTarget.addEventListener(aEventName, function onevent(aEvent) {
if (!aMatchFun || aMatchFun(aEvent)) {
aEventTarget.removeEventListener(aEventName, onevent);
ok(true, "Event '" + aEventName + "' got.");
aResolve(aEvent);
}
});
});
}
/**
* Wait for one named system message.
*
* Resolve if that named message is received. Never reject.
*
* Fulfill params: the message passed.
*
* @param aEventName
* A string message name.
* @param aMatchFun [optional]
* A matching function returns true or false to filter the message. If no
* matching function passed the promise is resolved after receiving the
* first message.
*
* @return A deferred promise.
*/
function waitForSystemMessage(aMessageName, aMatchFun) {
let target = workingFrame.contentWindow.navigator;
return new Promise(function(aResolve, aReject) {
target.mozSetMessageHandler(aMessageName, function(aMessage) {
if (!aMatchFun || aMatchFun(aMessage)) {
target.mozSetMessageHandler(aMessageName, null);
ok(true, "System message '" + aMessageName + "' got.");
aResolve(aMessage);
}
});
});
}
/**
* Set radio enabling state and wait for "radiostatechange" event.
*
* Resolve if radio state changed to the expected one. Never reject.
*
* Fulfill params: (none)
*
* @param aEnabled
* A boolean state.
* @param aServiceId [optional]
* A numeric DSDS service id. Default: the one indicated in
* start*TestCommon() or 0 if not indicated.
*
* @return A deferred promise.
*/
function setRadioEnabledAndWait(aEnabled, aServiceId) {
let mobileConn = getMozMobileConnectionByServiceId(aServiceId);
let promises = [];
promises.push(waitForTargetEvent(mobileConn, "radiostatechange", function() {
// To ignore some transient states, we only resolve that deferred promise
// when |radioState| equals to the expected one.
return mobileConn.radioState === (aEnabled ? "enabled" : "disabled");
}));
promises.push(setRadioEnabled(aEnabled, aServiceId));
return Promise.all(promises);
}
/**
* Restart radio and wait card state changes to expected one.
*
* Resolve if card state changed to the expected one. Never reject.
*
* Fulfill params: (none)
*
* @param aCardState
* Expected card state.
*
* @return A deferred promise.
*/
function restartRadioAndWait(aCardState) {
return setRadioEnabledAndWait(false).then(() => {
let promises = [];
promises.push(waitForTargetEvent(iccManager, "iccdetected")
.then((aEvent) => {
let icc = getMozIcc(aEvent.iccId);
if (icc.cardState !== aCardState) {
return waitForTargetEvent(icc, "cardstatechange", function() {
return icc.cardState === aCardState;
});
}
}));
promises.push(setRadioEnabledAndWait(true));
return Promise.all(promises);
});
}
/**
* Enable/Disable PIN-lock.
*
* Fulfill params: (none)
* Reject params:
* An object contains error name and remaining retry count.
* @see IccCardLockError
*
* @param aIcc
* A MozIcc object.
* @param aEnabled
* A boolean state.
*
* @return A deferred promise.
*/
function setPinLockEnabled(aIcc, aEnabled) {
let options = {
lockType: "pin",
enabled: aEnabled,
pin: DEFAULT_PIN
};
return aIcc.setCardLock(options);
}
/**
* Wait for pending emulator transactions and call |finish()|.
*/
function cleanUp() {
// Use ok here so that we have at least one test run.
ok(true, ":: CLEANING UP ::");
waitFor(finish, function() {
return _pendingEmulatorCmdCount === 0;
});
}
/**
* Basic test routine helper for icc tests.
*
* This helper does nothing but clean-ups.
*
* @param aTestCaseMain
* A function that takes no parameter.
*/
function startTestBase(aTestCaseMain) {
// Turn on debugging pref.
let debugPref = SpecialPowers.getBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED);
SpecialPowers.setBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED, true);
Promise.resolve()
.then(aTestCaseMain)
.catch((aError) => {
ok(false, "promise rejects during test: " + aError);
})
.then(() => {
// Restore debugging pref.
SpecialPowers.setBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED, debugPref);
cleanUp();
});
}
/**
* Common test routine helper for icc tests.
*
* This function ensures global variable |iccManager| and |icc| is available
* during the process and performs clean-ups as well.
*
* @param aTestCaseMain
* A function that takes one parameter -- icc.
* @param aAdditonalPermissions [optional]
* An array of permission strings other than "mobileconnection" to be
* pushed. Default: empty string..
*/
function startTestCommon(aTestCaseMain, aAdditionalPermissions) {
startTestBase(function() {
return ensureIccManager(aAdditionalPermissions)
.then(aTestCaseMain);
});
}

Просмотреть файл

@ -0,0 +1,41 @@
[DEFAULT]
run-if = buildapp == 'b2g'
[test_icc_contact_read.js]
[test_icc_contact_add.js]
[test_icc_contact_update.js]
[test_icc_card_lock_get_retry_count.js]
[test_icc_card_lock_change_pin.js]
[test_icc_card_lock_enable_pin.js]
[test_icc_card_lock_unlock_pin.js]
[test_icc_card_lock_unlock_puk.js]
[test_icc_card_state.js]
[test_icc_info.js]
[test_stk_refresh.js]
[test_stk_play_tone.js]
[test_stk_poll_off.js]
[test_stk_poll_interval.js]
[test_stk_setup_event_list.js]
[test_stk_setup_call.js]
[test_stk_send_ss.js]
[test_stk_send_ussd.js]
[test_stk_send_sms.js]
[test_stk_send_dtmf.js]
[test_stk_launch_browser.js]
[test_stk_display_text.js]
[test_stk_get_inkey.js]
[test_stk_get_input.js]
[test_stk_select_item.js]
[test_stk_setup_menu.js]
[test_stk_setup_idle_mode_text.js]
[test_stk_bip_command.js]
[test_stk_local_info.js]
[test_stk_timer_management.js]
[test_icc_access_invalid_object.js]
[test_icc_detected_undetected_event.js]
[test_icc_match_mvno.js]
[test_icc_service_state.js]
[test_stk_menu_selection.js]
[test_stk_timer_expiration.js]
[test_stk_event_download.js]
[test_stk_response.js]

Просмотреть файл

@ -0,0 +1,101 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = "head.js";
function testInvalidIccObject(aIcc) {
// Test access iccInfo.
try {
is(aIcc.iccInfo, null, "iccInfo: expect to get null");
} catch(e) {
ok(false, "access iccInfo should not get exception");
}
// Test access cardState.
try {
is(aIcc.cardState, null, "cardState: expect to get null");
} catch(e) {
ok(false, "access cardState should not get exception");
}
// Test STK related function.
try {
aIcc.sendStkResponse({}, {});
ok(false, "sendStkResponse() should get exception");
} catch(e) {}
try {
aIcc.sendStkMenuSelection(0, false);
ok(false, "sendStkMenuSelection() should get exception");
} catch(e) {}
try {
aIcc.sendStkTimerExpiration({});
ok(false, "sendStkTimerExpiration() should get exception");
} catch(e) {}
try {
aIcc.sendStkEventDownload({});
ok(false, "sendStkEventDownload() should get exception");
} catch(e) {}
// Test card lock related function.
try {
aIcc.getCardLock("pin");
ok(false, "getCardLock() should get exception");
} catch(e) {}
try {
aIcc.unlockCardLock({});
ok(false, "unlockCardLock() should get exception");
} catch(e) {}
try {
aIcc.setCardLock({});
ok(false, "setCardLock() should get exception");
} catch(e) {}
try {
aIcc.getCardLockRetryCount("pin");
ok(false, "getCardLockRetryCount() should get exception");
} catch(e) {}
// Test contact related function.
try {
aIcc.readContacts("adn");
ok(false, "readContacts() should get exception");
} catch(e) {}
try {
aIcc.updateContact("adn", {});
ok(false, "updateContact() should get exception");
} catch(e) {}
// Test mvno function.
try {
aIcc.matchMvno("imsi");
ok(false, "matchMvno() should get exception");
} catch(e) {}
// Test service state function.
return aIcc.getServiceState("fdn").then(() => {
ok(false, "getServiceState() should be rejected");
}, () => {});
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
return Promise.resolve()
// Turn off radio.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(false));
promises.push(waitForTargetEvent(iccManager, "iccundetected"));
return Promise.all(promises);
})
// Test accessing invalid icc object.
.then(() => testInvalidIccObject(icc))
// We should restore the radio status.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(true));
promises.push(waitForTargetEvent(iccManager, "iccdetected"));
return Promise.all(promises);
});
});

Просмотреть файл

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
const LOCK_TYPE = "pin";
function testChangePin(aIcc, aPin, aNewPin, aErrorName, aRetryCount) {
log("testChangePin for pin=" + aPin + " and newPin=" + aNewPin);
return aIcc.setCardLock({ lockType: LOCK_TYPE, pin: aPin, newPin: aNewPin })
.then((aResult) => {
if (aErrorName) {
ok(false, "changing pin should not success");
}
}, (aError) => {
if (!aErrorName) {
ok(false, "changing pin should not fail");
return;
}
// check the request error.
is(aError.name, aErrorName, "error.name");
is(aError.retryCount, aRetryCount, "error.retryCount");
});
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let retryCount;
return icc.getCardLockRetryCount(LOCK_TYPE)
// Get current PIN-lock retry count.
.then((aResult) => {
retryCount = aResult.retryCount;
ok(true, LOCK_TYPE + " retryCount is " + retryCount);
})
// Test PIN code changes fail.
// The retry count should be decreased by 1.
.then(() => testChangePin(icc, "1111", DEFAULT_PIN, "IncorrectPassword",
retryCount - 1))
// Test PIN code changes success. This will reset the retry count.
.then(() => testChangePin(icc, DEFAULT_PIN, DEFAULT_PIN));
});

Просмотреть файл

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
function setCardLockAndCheck(aIcc, aLockType, aPin, aEnabled, aErrorName,
aRetryCount) {
let options = {
lockType: aLockType,
enabled: aEnabled,
pin: aPin
};
return aIcc.setCardLock(options)
.then((aResult) => {
if (aErrorName) {
ok(false, "setting pin should not success");
return;
}
// Check lock state.
return aIcc.getCardLock(aLockType)
.then((aResult) => {
is(aResult.enabled, aEnabled, "result.enabled");
});
}, (aError) => {
if (!aErrorName) {
ok(false, "setting pin should not fail");
return;
}
// Check the request error.
is(aError.name, aErrorName, "error.name");
is(aError.retryCount, aRetryCount, "error.retryCount");
});
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let lockType = "pin";
let retryCount;
return icc.getCardLockRetryCount(lockType)
// Get current PIN-lock retry count.
.then((aResult) => {
retryCount = aResult.retryCount;
ok(true, lockType + " retryCount is " + retryCount);
})
// Test fail to enable PIN-lock by passing wrong pin.
// The retry count should be decreased by 1.
.then(() => setCardLockAndCheck(icc, lockType, "1111", true,
"IncorrectPassword", retryCount -1))
// Test enabling PIN-lock.
.then(() => setCardLockAndCheck(icc, lockType, DEFAULT_PIN, true))
// Restore pin state.
.then(() => setCardLockAndCheck(icc, lockType, DEFAULT_PIN, false));
});

Просмотреть файл

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
function testGetCardLockRetryCount(aIcc, aLockType, aRetryCount) {
log("testGetCardLockRetryCount for " + aLockType);
try {
return aIcc.getCardLockRetryCount(aLockType)
.then((aResult) => {
if (!aRetryCount) {
ok(false, "getCardLockRetryCount(" + aLockType + ") should not success");
return;
}
// Check the request result.
is(aResult.retryCount, aRetryCount, "result.retryCount");
}, (aError) => {
if (aRetryCount) {
ok(false, "getCardLockRetryCount(" + aLockType + ") should not fail" +
aError.name);
}
});
} catch (e) {
ok(!aRetryCount, "caught an exception: " + e);
return Promise.resolve();
}
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
// Read PIN-lock retry count.
// The default PIN-lock retry count hard coded in emulator is 3.
return testGetCardLockRetryCount(icc, "pin", 3)
// Read PUK-lock retry count.
// The default PUK-lock retry count hard coded in emulator is 6.
.then(() => testGetCardLockRetryCount(icc, "puk", 6))
// Read lock retry count for an invalid entries.
.then(() => testGetCardLockRetryCount(icc, "invalid-lock-type"));
});

Просмотреть файл

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
function testUnlockPin(aIcc, aPin, aErrorName, aRetryCount) {
log("testUnlockPin with pin=" + aPin);
return aIcc.unlockCardLock({ lockType: "pin", pin: aPin })
.then((aResult) => {
if (aErrorName) {
ok(false, "unlocking pin should not success");
}
}, (aError) => {
if (!aErrorName) {
ok(false, "unlocking pin should not fail");
return;
}
// Check the request error.
is(aError.name, aErrorName, "error.name");
is(aError.retryCount, aRetryCount, "error.retryCount");
});
}
function testUnlockPinAndWait(aIcc, aPin, aCardState) {
log("testUnlockPin with pin=" + aPin + ", and wait cardState changes to '" +
aCardState + "'");
let promises = [];
promises.push(waitForTargetEvent(aIcc, "cardstatechange", function() {
return aIcc.cardState === aCardState;
}));
promises.push(testUnlockPin(aIcc, aPin));
return Promise.all(promises);
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let retryCount;
// Enable PIN-lock.
return setPinLockEnabled(icc, true)
// Reset card state to "pinRequired" by restarting radio
.then(() => restartRadioAndWait("pinRequired"))
.then(() => { icc = getMozIcc(); })
// Get current PIN-lock retry count.
.then(() => icc.getCardLockRetryCount("pin"))
.then((aResult) => {
retryCount = aResult.retryCount;
ok(true, "pin retryCount is " + retryCount);
})
// Test fail to unlock PIN-lock.
// The retry count should be decreased by 1.
.then(() => testUnlockPin(icc, "1111", "IncorrectPassword", retryCount - 1))
// Test success to unlock PIN-lock.
.then(() => testUnlockPinAndWait(icc, DEFAULT_PIN, "ready"))
// Restore pin state.
.then(() => setPinLockEnabled(icc, false));
});

Просмотреть файл

@ -0,0 +1,97 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
function passingWrongPinAndWait(aIcc) {
return aIcc.getCardLockRetryCount("pin").then((aResult) => {
let promises = [];
let retryCount = aResult.retryCount;
ok(true, "pin retryCount is " + retryCount);
promises.push(waitForTargetEvent(aIcc, "cardstatechange", function() {
return aIcc.cardState === "pukRequired";
}));
for (let i = 0; i < retryCount; i++) {
promises.push(aIcc.unlockCardLock({ lockType: "pin", pin: "1111" })
.then(() => {
ok(false, "unlocking pin should not success");
}, function reject(aRetryCount, aError) {
// check the request error.
is(aError.name, "IncorrectPassword", "error.name");
is(aError.retryCount, aRetryCount, "error.retryCount");
}.bind(null, retryCount - i - 1)));
}
return Promise.all(promises);
});
}
function testUnlockPuk(aIcc, aPuk, aNewPin, aErrorName, aRetryCount) {
log("testUnlockPuk with puk=" + aPuk + " and newPin=" + aNewPin);
return aIcc.unlockCardLock({ lockType: "puk", puk: aPuk, newPin: aNewPin })
.then((aResult) => {
if (aErrorName) {
ok(false, "unlocking puk should not success");
}
}, (aError) => {
if (!aErrorName) {
ok(false, "unlocking puk should not fail");
return;
}
// Check the request error.
is(aError.name, aErrorName, "error.name");
is(aError.retryCount, aRetryCount, "error.retryCount");
});
}
function testUnlockPukAndWait(aIcc, aPuk, aNewPin, aCardState) {
log("testUnlockPuk with puk=" + aPuk + "/newPin=" + aNewPin +
", and wait card state changes to '" + aCardState + "'");
let promises = [];
promises.push(waitForTargetEvent(aIcc, "cardstatechange", function() {
return aIcc.cardState === aCardState;
}));
promises.push(testUnlockPuk(aIcc, aPuk, aNewPin));
return Promise.all(promises);
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let retryCount;
// Enable pin lock.
return setPinLockEnabled(icc, true)
// Reset card state to "pinRequired" by restarting radio
.then(() => restartRadioAndWait("pinRequired"))
.then(() => { icc = getMozIcc() })
// Switch cardState to "pukRequired" by entering wrong pin code.
.then(() => passingWrongPinAndWait(icc))
// Get current PUK-lock retry count.
.then(() => icc.getCardLockRetryCount("puk"))
.then((aResult) => {
retryCount = aResult.retryCount;
ok(true, "puk retryCount is " + retryCount);
})
// Test unlock PUK code fail.
// The retry count should be decreased by 1.
.then(() => testUnlockPuk(icc, "11111111", DEFAULT_PIN, "IncorrectPassword",
retryCount - 1))
// Test unlock PUK code success.
.then(() => testUnlockPukAndWait(icc, DEFAULT_PUK, DEFAULT_PIN, "ready"))
// Restore pin state.
.then(() => setPinLockEnabled(icc, false));
});

Просмотреть файл

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = "head.js";
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
// Basic test.
is(icc.cardState, "ready", "card state is " + icc.cardState);
// Test cardstatechange event by switching radio off.
return Promise.resolve()
// Turn off radio and expect to get card state changing to null.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(false));
promises.push(waitForTargetEvent(icc, "cardstatechange", function() {
return icc.cardState === null;
}));
return Promise.all(promises);
})
// Restore radio status and expect to get iccdetected event.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(true));
promises.push(waitForTargetEvent(iccManager, "iccdetected"));
return Promise.all(promises);
});
});

Просмотреть файл

@ -0,0 +1,119 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 120000;
MARIONETTE_HEAD_JS = "head.js";
var TEST_ADD_DATA = [{
// a contact without email and anr.
name: ["add1"],
tel: [{value: "0912345678"}],
}, {
// a contact over 20 digits.
name: ["add2"],
tel: [{value: "012345678901234567890123456789"}],
}, {
// a contact over 40 digits.
name: ["add3"],
tel: [{value: "01234567890123456789012345678901234567890123456789"}],
}, {
// a contact with email but without anr.
name: ["add4"],
tel: [{value: "01234567890123456789"}],
email:[{value: "test@mozilla.com"}],
}, {
// a contact with anr but without email.
name: ["add5"],
tel: [{value: "01234567890123456789"}, {value: "123456"}, {value: "123"}],
}, {
// a contact with email and anr.
name: ["add6"],
tel: [{value: "01234567890123456789"}, {value: "123456"}, {value: "123"}],
email:[{value: "test@mozilla.com"}],
}, {
// a contact without number.
name: ["add7"],
tel: [{value: ""}],
}, {
// a contact without name.
name: [""],
tel: [{value: "0987654321"}],
}];
function testAddContact(aIcc, aType, aMozContact, aPin2) {
log("testAddContact: type=" + aType + ", pin2=" + aPin2);
let contact = new mozContact(aMozContact);
return aIcc.updateContact(aType, contact, aPin2)
.then((aResult) => {
is(aResult.name[0], aMozContact.name[0]);
// Maximum digits of the Dialling Number is 20, and maximum digits of Extension is 20.
is(aResult.tel[0].value, aMozContact.tel[0].value.substring(0, 40));
// We only support SIM in emulator, so we don't have anr and email field.
ok(aResult.tel.length == 1);
ok(!aResult.email);
}, (aError) => {
if (aType === "fdn" && aPin2 === undefined) {
ok(aError.name === "SimPin2",
"expected error when pin2 is not provided");
} else {
ok(false, "Cannot add " + aType + " contact: " + aError.name);
}
});
}
function removeContacts(aIcc, aContacts, aType, aPin2) {
log("removeContacts: type=" + aType + ", pin2=" + aPin2);
let promise = Promise.resolve();
// Clean up contacts
for (let i = 0; i < aContacts.length ; i++) {
let contact = new mozContact({});
contact.id = aContacts[i].id;
promise = promise.then(() => aIcc.updateContact(aType, contact, aPin2));
}
return promise;
}
function testAddContacts(aIcc, aType, aPin2) {
let promise = Promise.resolve();
for (let i = 0; i < TEST_ADD_DATA.length; i++) {
let test_data = TEST_ADD_DATA[i];
promise = promise.then(() => testAddContact(aIcc, aType, test_data, aPin2));
}
// Get ICC contact for checking new contacts
promise = promise.then(() => aIcc.readContacts(aType))
.then((aResult) => {
aResult = aResult.slice(aResult.length - TEST_ADD_DATA.length);
for (let i = 0; i < aResult.length ; i++) {
let contact = aResult[i];
let expectedResult = TEST_ADD_DATA[i];
is(contact.name[0], expectedResult.name[0]);
// Maximum digits of the Dialling Number is 20, and maximum digits of Extension is 20.
is(contact.tel[0].value, expectedResult.tel[0].value.substring(0, 40));
is(contact.id.substring(0, aIcc.iccInfo.iccid.length), aIcc.iccInfo.iccid);
}
return removeContacts(aIcc, aResult, aType, aPin2);
});
return promise;
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
return Promise.resolve()
// Test add adn contacts
.then(() => testAddContacts(icc, "adn"))
// Test add fdn contacts
.then(() => testAddContacts(icc, "fdn", "0000"))
// Test one fdn contact without passing pin2
.then(() => testAddContact(icc, "fdn", TEST_ADD_DATA[0]));
});

Просмотреть файл

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
MARIONETTE_CONTEXT = "chrome";
function testReadContacts(aIcc, aType) {
log("testReadContacts: type=" + aType);
let iccId = aIcc.iccInfo.iccid;
return aIcc.readContacts(aType)
.then((aResult) => {
is(Array.isArray(aResult), true);
is(aResult.length, 6, "Check contact number.");
// Alpha Id(Encoded with GSM 8 bit): "Mozilla", Dialling Number: 15555218201
is(aResult[0].name[0], "Mozilla");
is(aResult[0].tel[0].value, "15555218201");
is(aResult[0].id, iccId + "1");
// Alpha Id(Encoded with UCS2 0x80: "Saßê\u9ec3", Dialling Number: 15555218202
is(aResult[1].name[0], "Saßê黃");
is(aResult[1].tel[0].value, "15555218202");
is(aResult[1].id, iccId + "2");
// Alpha Id(Encoded with UCS2 0x81): "Fire \u706b", Dialling Number: 15555218203
is(aResult[2].name[0], "Fire 火");
is(aResult[2].tel[0].value, "15555218203");
is(aResult[2].id, iccId + "3");
// Alpha Id(Encoded with UCS2 0x82): "Huang \u9ec3", Dialling Number: 15555218204
is(aResult[3].name[0], "Huang 黃");
is(aResult[3].tel[0].value, "15555218204");
is(aResult[3].id, iccId + "4");
// Alpha Id(Encoded with GSM 8 bit): "Contact001",
// Dialling Number: 9988776655443322110001234567890123456789
is(aResult[4].name[0], "Contact001");
is(aResult[4].tel[0].value, "9988776655443322110001234567890123456789");
is(aResult[4].id, iccId + "5");
// Alpha Id(Encoded with GSM 8 bit): "Contact002",
// Dialling Number: 0123456789012345678999887766554433221100
is(aResult[5].name[0], "Contact002");
is(aResult[5].tel[0].value, "0123456789012345678999887766554433221100");
is(aResult[5].id, iccId + "6");
}, (aError) => {
ok(false, "Cannot get " + aType + " contacts");
});
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
// Test read adn contacts
return testReadContacts(icc, "adn")
// Test read fdn contact
.then(() => testReadContacts(icc, "fdn"))
// Test read sdn contacts
.then(() => testReadContacts(icc, "sdn"));
});

Просмотреть файл

@ -0,0 +1,130 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 120000;
MARIONETTE_HEAD_JS = "head.js";
const TEST_UPDATE_DATA = [{
id: 1,
data: {
name: ["Mozilla"],
tel: [{value: "9876543210987654321001234"}]},
expect: {
number: "9876543210987654321001234"}
}, {
id:2,
data: {
name: ["Saßê黃"],
tel: [{value: "98765432109876543210998877665544332211001234"}]},
expect: {
// We don't support extension chain now.
number: "9876543210987654321099887766554433221100"}
}, {
id: 3,
data: {
name: ["Fire 火"],
tel: [{value: ""}]},
expect: {
number: ""}
}, {
id: 5,
data: {
name: ["Contact001"],
tel: [{value: "9988776655443322110098765432109876543210"}]},
expect: {
number: "9988776655443322110098765432109876543210"}
}, {
id: 6,
data: {
name: ["Contact002"],
tel: [{value: "+99887766554433221100"}]},
expect: {
number: "+99887766554433221100"}
}];
function testUpdateContact(aIcc, aType, aContactId, aMozContact, aExpect, aPin2) {
log("testUpdateContact: type=" + aType +
", mozContact=" + JSON.stringify(aMozContact) +
", expect=" + aExpect.number + ", pin2=" + aPin2);
let contact = new mozContact(aMozContact);
contact.id = aIcc.iccInfo.iccid + aContactId;
return aIcc.updateContact(aType, contact, aPin2)
.then((aResult) => {
is(aResult.tel[0].value, aExpect.number);
ok(aResult.tel.length == 1);
// We only support SIM in emulator, so we don't have anr and email field.
ok(!aResult.email);
is(contact.id, aIcc.iccInfo.iccid + aContactId);
}, (aError) => {
if (aType === "fdn" && aPin2 === undefined) {
ok(aError.name === "SimPin2",
"expected error when pin2 is not provided");
} else {
ok(false, "Cannot update " + aType + " contact: " + aError.name);
}
});
}
function revertContacts(aIcc, aContacts, aType, aPin2) {
log("revertContacts type=" + aType + ", pin2=" + aPin2);
let promise = Promise.resolve();
for (let i = 0; i < aContacts.length; i++) {
let aContact = aContacts[i];
promise = promise.then(() => aIcc.updateContact(aType, aContact, aPin2));
}
return promise;
}
function testUpdateContacts(aIcc, aType, aCacheContacts, aPin2) {
let promise = Promise.resolve();
for (let i = 0; i < TEST_UPDATE_DATA.length; i++) {
let test_data = TEST_UPDATE_DATA[i];
promise = promise.then(() => testUpdateContact(aIcc, aType, test_data.id,
test_data.data, test_data.expect,
aPin2));
}
// Get ICC contact for checking expect contacts
promise = promise.then(() => aIcc.readContacts(aType))
.then((aResult) => {
for (let i = 0; i < TEST_UPDATE_DATA.length; i++) {
let expectedResult = TEST_UPDATE_DATA[i];
let contact = aResult[expectedResult.id - 1];
is(contact.name[0], expectedResult.data.name[0]);
is(contact.id, aIcc.iccInfo.iccid + expectedResult.id);
is(contact.tel[0].value, expectedResult.expect.number);
}
return revertContacts(aIcc, aCacheContacts, aType, aPin2);
});
return promise;
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let adnContacts;
let fdnContacts;
return icc.readContacts("adn")
.then((aResult) => {
adnContacts = aResult;
})
.then(() => icc.readContacts("fdn"))
.then((aResult) => {
fdnContacts = aResult;
})
// Test update adn contacts
.then(() => testUpdateContacts(icc, "adn", adnContacts))
// Test update fdn contacts
.then(() => testUpdateContacts(icc, "fdn", fdnContacts, "0000"))
// Test one fdn contact without passing pin2
.then(() => testUpdateContact(icc, "fdn", TEST_UPDATE_DATA[0].id,
TEST_UPDATE_DATA[0].data,
TEST_UPDATE_DATA[0].expect));
});

Просмотреть файл

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = "head.js";
// Start tests
startTestCommon(function() {
let origNumIccs = iccManager.iccIds.length;
let icc = getMozIcc();
let iccId = icc.iccInfo.iccid;
let mobileConnection = getMozMobileConnectionByServiceId();
return Promise.resolve()
// Test iccundetected event.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(false));
promises.push(waitForTargetEvent(iccManager, "iccundetected").then((aEvt) => {
is(aEvt.iccId, iccId, "icc " + aEvt.iccId + " becomes undetected");
is(iccManager.iccIds.length, origNumIccs - 1,
"iccIds.length becomes to " + iccManager.iccIds.length);
is(iccManager.getIccById(aEvt.iccId), null,
"should not get a valid icc object here");
// The mozMobileConnection.iccId should be in sync.
is(mobileConnection.iccId, null, "check mozMobileConnection.iccId");
}));
return Promise.all(promises);
})
// Test iccdetected event.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(true));
promises.push(waitForTargetEvent(iccManager, "iccdetected").then((aEvt) => {
is(aEvt.iccId, iccId, "icc " + aEvt.iccId + " is detected");
is(iccManager.iccIds.length, origNumIccs,
"iccIds.length becomes to " + iccManager.iccIds.length);
ok(iccManager.getIccById(aEvt.iccId) instanceof MozIcc,
"should get a valid icc object here");
// The mozMobileConnection.iccId should be in sync.
is(mobileConnection.iccId, iccId, "check mozMobileConnection.iccId");
}));
return Promise.all(promises);
});
});

Просмотреть файл

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = "head.js";
/* Basic test */
function basicTest(aIcc) {
let iccInfo = aIcc.iccInfo;
// The emulator's hard coded iccid value.
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
is(iccInfo.iccid, 89014103211118510720);
if (iccInfo instanceof MozGsmIccInfo) {
log("Test Gsm IccInfo");
is(iccInfo.iccType, "sim");
is(iccInfo.spn, "Android");
// The emulator's hard coded mcc and mnc codes.
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
is(iccInfo.mcc, 310);
is(iccInfo.mnc, 410);
// Phone number is hardcoded in MSISDN
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io().
is(iccInfo.msisdn, "15555215554");
} else {
log("Test Cdma IccInfo");
is(iccInfo.iccType, "ruim");
// MDN is hardcoded as "8587777777".
// See it here {B2G_HOME}/hardware/ril/reference-ril/reference-ril.c,
// in requestCdmaSubscription().
is(iccInfo.mdn, "8587777777");
// PRL version is hardcoded as 1.
// See it here {B2G_HOME}/hardware/ril/reference-ril/reference-ril.c,
// in requestCdmaSubscription().
is(iccInfo.prlVersion, 1);
}
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
return Promise.resolve()
// Basic test
.then(() => basicTest(icc))
// Test iccInfo when card becomes undetected
.then(() => {
let promises = [];
promises.push(setRadioEnabled(false));
promises.push(waitForTargetEvent(icc, "iccinfochange", function() {
// Expect iccInfo changes to null
return icc.iccInfo === null;
}));
return Promise.all(promises);
})
// Restore radio status and expect to get iccdetected event.
.then(() => {
let promises = [];
promises.push(setRadioEnabled(true));
promises.push(waitForTargetEvent(iccManager, "iccdetected"));
return Promise.all(promises);
});
});

Просмотреть файл

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = "head.js";
const TEST_DATA = [
// mvno type, mvno data, request success, expected result
// Emulator's hard coded IMSI: 310410000000000
["imsi", "3104100", true, true ],
// x and X means skip the comparison.
["imsi", "31041xx0", true, true ],
["imsi", "310410x0x", true, true ],
["imsi", "310410X00", true, true ],
["imsi", "310410XX1", true, false ],
["imsi", "31041012", true, false ],
["imsi", "310410000000000", true, true ],
["imsi", "310410000000000123", true, false ],
["imsi", "", false, "InvalidParameter"],
// Emulator's hard coded SPN: Android
["spn", "Android", true, true ],
["spn", "", false, "InvalidParameter"],
["spn", "OneTwoThree", true, false ],
// Emulator's hard coded GID1: 5a4d
["gid", "", false, "InvalidParameter"],
["gid", "A1", true, false ],
["gid", "5A", true, true ],
["gid", "5a", true, true ],
["gid", "5a4d", true, true ],
["gid", "5A4D", true, true ],
["gid", "5a4d6c", true, false ]
];
function testMatchMvno(aIcc, aMvnoType, aMvnoData, aSuccess, aExpectedResult) {
log("matchMvno: " + aMvnoType + ", " + aMvnoData);
return aIcc.matchMvno(aMvnoType, aMvnoData)
.then((aResult) => {
log("onsuccess: " + aResult);
ok(aSuccess, "onsuccess while error expected");
is(aResult, aExpectedResult);
}, (aError) => {
log("onerror: " + aError.name);
ok(!aSuccess, "onerror while success expected");
is(aError.name, aExpectedResult);
});
}
// Start tests
startTestCommon(function() {
let icc = getMozIcc();
let promise = Promise.resolve();
for (let i = 0; i < TEST_DATA.length; i++) {
let data = TEST_DATA[i];
promise = promise.then(() => testMatchMvno.apply(null, [icc].concat(data)));
}
return promise;
});

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше