зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
62aec9f499
Коммит
16522e6c40
|
@ -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();
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
});
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче