Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const DEBUG = false;
8 function debug(s) { dump("-*- Android ContactService component: " + s + "\n"); }
10 const Cu = Components.utils;
11 const Cc = Components.classes;
12 const Ci = Components.interfaces;
14 this.EXPORTED_SYMBOLS = [];
16 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
17 Cu.import("resource://gre/modules/Services.jsm");
18 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
20 XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1",
21 "nsIMessageListenerManager");
23 let ContactService = {
24 init: function() {
25 if (DEBUG) debug("Init");
26 this._requestMessages = {};
28 // Add listeners for all messages from ContactManager.js
29 let messages = ["Contacts:Clear", "Contacts:Find", "Contacts:GetAll",
30 "Contacts:GetAll:SendNow", "Contacts:GetCount", "Contacts:GetRevision",
31 "Contact:Remove", "Contact:Save",];
32 messages.forEach(function(msgName) {
33 ppmm.addMessageListener(msgName, this);
34 }.bind(this));
36 // Add listeners for all messages from ContactService.java
37 let returnMessages = ["Android:Contacts:Count",
38 "Android:Contacts:Clear:Return:OK", "Android:Contacts:Clear:Return:KO",
39 "Android:Contacts:Find:Return:OK", "Android:Contacts:Find:Return:KO",
40 "Android:Contacts:GetAll:Next", "Android:Contacts:RegisterForMessages",
41 "Android:Contact:Remove:Return:OK", "Android:Contact:Remove:Return:KO",
42 "Android:Contact:Save:Return:OK", "Android:Contact:Save:Return:KO",];
44 returnMessages.forEach(function(msgName) {
45 Services.obs.addObserver(this, msgName, false);
46 }.bind(this));
47 },
49 _sendMessageToJava: function(aMsg) {
50 Services.androidBridge.handleGeckoMessage(aMsg);
51 },
53 _sendReturnMessage: function(aTopic, aRequestID, aResult) {
54 this._requestMessages[aRequestID].target.sendAsyncMessage(aTopic, aResult);
55 },
57 _sendAndDeleteReturnMessage: function(aTopic, aRequestID, aResult) {
58 this._sendReturnMessage(aTopic, aRequestID, aResult)
59 delete this._requestMessages[aRequestID];
60 },
62 observe: function(aSubject, aTopic, aData) {
63 if (DEBUG) {
64 debug("observe: subject: " + aSubject + " topic: " + aTopic + " data: " + aData);
65 }
67 let message = JSON.parse(aData, function date_reviver(k, v) {
68 // The Java service sends dates as strings, so convert them to Dates before
69 // sending them back to the child.
70 if (v != null && v != "null" &&
71 ["updated", "published", "anniversary", "bday"].indexOf(k) != -1) {
72 return new Date(v);
73 }
74 return v;
75 });
76 let requestID = message.requestID;
78 // The return message topic is the same as the current topic, but without the "Android:" prefix
79 let returnMessageTopic = aTopic.substring(8);
81 switch (aTopic) {
82 case "Android:Contacts:Find:Return:OK":
83 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID, contacts: message.contacts});
84 break;
86 case "Android:Contacts:Find:Return:KO":
87 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID});
88 break;
90 case "Android:Contact:Save:Return:OK":
91 this._sendReturnMessage(returnMessageTopic, requestID, {requestID: requestID, contactID: message.contactID});
92 this._sendAndDeleteReturnMessage("Contact:Changed", requestID, {contactID: message.contactID, reason: message.reason});
93 break;
95 case "Android:Contact:Save:Return:KO":
96 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID});
97 break;
99 case "Android:Contact:Remove:Return:OK":
100 this._sendReturnMessage(returnMessageTopic, requestID, {requestID: requestID, contactID: message.contactID});
101 this._sendAndDeleteReturnMessage("Contact:Changed", requestID, {contactID: message.contactID, reason: "remove"});
102 break;
104 case "Android:Contact:Remove:Return:KO":
105 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID});
106 break;
108 case "Android:Contacts:Clear:Return:OK":
109 this._sendReturnMessage(returnMessageTopic, requestID, {requestID: requestID});
110 this._sendAndDeleteReturnMessage("Contact:Changed", requestID, {reason: "remove"});
111 break;
113 case "Android:Contact:Clear:Return:KO":
114 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID});
115 break;
117 case "Android:Contacts:GetAll:Next":
118 // GetAll uses a cursor ID instead of a request ID. Translate the request ID back to the cursor ID
119 this._sendReturnMessage(returnMessageTopic, requestID, {cursorId: requestID, contacts: message.contacts});
121 // Send a message with no contacts to denote the end of contacts returned by the query
122 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {cursorId: requestID});
123 break;
125 case "Android:Contacts:Count":
126 this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID, count: message.count});
127 break;
129 default:
130 throw "Wrong message received: " + aTopic;
131 }
132 },
134 assertPermission: function(aMessage, aPerm) {
135 if (!aMessage.target.assertPermission(aPerm)) {
136 Cu.reportError("Contacts message " + aMessage.name +
137 " from a content process with no" + aPerm + " privileges.");
138 return false;
139 }
140 return true;
141 },
143 receiveMessage: function(aMessage) {
144 if (DEBUG) debug("receiveMessage " + aMessage.name);
146 // GetAll uses a cursor ID instead of a request ID, but they can be treated the same from here
147 if (!aMessage.data.requestID && aMessage.data.cursorId) {
148 aMessage.data.requestID = aMessage.data.cursorId;
149 }
150 let requestID = aMessage.data.requestID;
152 // Store the message so it the request callback can be called when the Java side is finished
153 this._requestMessages[requestID] = aMessage;
155 switch (aMessage.name) {
156 case "Contacts:Find":
157 this.findContacts(aMessage);
158 break;
160 case "Contacts:GetAll":
161 this.getAllContacts(aMessage);
162 break;
164 case "Contacts:GetAll:SendNow":
165 // Send an empty message to denote there are no most contacts for the getAll query
166 this._sendAndDeleteReturnMessage("Contacts:GetAll:Next", requestID, {cursorId: requestID});
167 break;
169 case "Contact:Save":
170 this.saveContact(aMessage);
171 break;
173 case "Contact:Remove":
174 this.removeContact(aMessage);
175 break;
177 case "Contacts:Clear":
178 this.clearContacts(aMessage);
179 break;
181 case "Contacts:GetCount":
182 this.getContactsCount(aMessage);
183 break;
185 case "Contacts:GetRevision":
186 // Android does not support the get revision function
187 this._sendAndDeleteReturnMessage("Contacts:GetRevision:Return:KO", requestID, {requestID: requestID,
188 errorMsg: "Android does not support the revision function."});
189 break;
191 case "Contacts:RegisterForMessages":
192 delete this._requestMessages[requestID];
193 break;
195 default:
196 delete this._requestMessages[requestID];
197 throw "Wrong message received: " + aMessage.name;
198 }
199 },
201 findContacts: function(aMessage) {
202 if (!this.assertPermission(aMessage, "contacts-read")) {
203 return;
204 }
206 let countryName = PhoneNumberUtils.getCountryName();
207 let substringmatchingPref = "dom.phonenumber.substringmatching." + countryName;
208 let substringmatchingValue = 0;
209 if (Services.prefs.getPrefType(substringmatchingPref) == Ci.nsIPrefBranch.PREF_INT) {
210 substringmatchingValue = Services.prefs.getIntPref(substringmatchingPref);
211 }
213 // Add the substring matching value to the find options JSON
214 aMessage.data.options.findOptions.substringMatching = substringmatchingValue;
216 this._sendMessageToJava({type: "Android:Contacts:Find", data: aMessage.data});
217 },
219 getAllContacts: function(aMessage) {
220 if (!this.assertPermission(aMessage, "contacts-read")) {
221 return;
222 }
224 this._sendMessageToJava({type: "Android:Contacts:GetAll", data: aMessage.data});
225 },
227 saveContact: function(aMessage) {
228 if ((aMessage.data.options.reason === "create" &&
229 !this.assertPermission(aMessage, "contacts-create")) ||
230 !this.assertPermission(aMessage, "contacts-write")) {
231 return;
232 }
234 this._sendMessageToJava({type: "Android:Contact:Save", data: aMessage.data});
235 },
237 removeContact: function(aMessage) {
238 if (!this.assertPermission(aMessage, "contacts-write")) {
239 return;
240 }
242 this._sendMessageToJava({type: "Android:Contact:Remove", data: aMessage.data});
243 },
245 clearContacts: function(aMessage) {
246 if (!this.assertPermission(aMessage, "contacts-write")) {
247 return;
248 }
250 this._sendMessageToJava({type: "Android:Contacts:Clear", data: aMessage.data});
251 },
253 getContactsCount: function(aMessage) {
254 if (!this.assertPermission(aMessage, "contacts-read")) {
255 return;
256 }
258 this._sendMessageToJava({type: "Android:Contacts:GetCount", data: aMessage.data});
259 },
260 }
262 ContactService.init();