# vim: se ft=diff : # HG changeset patch # User Brad Lassey # Date 1291658603 18000 imported patch contacts # HG changeset patch # User Brad Lassey # Date 1291658603 18000 # Node ID a4b4599f825c70950e1c65c12ec4ed3770d2a48e # Parent 34b0b3bc698409e3ff66770aa1b96567a017acd3 imported patch contacts diff --git a/dom/system/android/Makefile.in b/dom/system/android/Makefile.in --- a/dom/system/android/Makefile.in +++ b/dom/system/android/Makefile.in @@ -51,15 +51,16 @@ EXPORT_LIBRARY = 1 include $(topsrcdir)/config/config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk CPPSRCS = \ nsDeviceMotionSystem.cpp \ AndroidLocationProvider.cpp \ nsHapticFeedback.cpp \ + nsContacts.cpp \ $(NULL) LOCAL_INCLUDES += -I$(topsrcdir)/dom/src/geolocation \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/system/android/nsContacts.cpp b/dom/system/android/nsContacts.cpp new file mode 100644 --- /dev/null +++ b/dom/system/android/nsContacts.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mozilla/dom/ContentChild.h" +#include "nsContacts.h" +#include "AndroidBridge.h" + +using namespace mozilla; + +NS_IMPL_ISUPPORTS1(nsContacts, nsIContacts) + +NS_IMETHODIMP +nsContacts::QueryContacts(nsIContactsCallback* aCallback) +{ + AndroidBridge* bridge = AndroidBridge::Bridge(); + if (bridge) { + bridge->GetContacts(aCallback); + return NS_OK; + } + return NS_ERROR_FAILURE; +} diff --git a/dom/system/android/nsContacts.h b/dom/system/android/nsContacts.h new file mode 100644 --- /dev/null +++ b/dom/system/android/nsContacts.h @@ -0,0 +1,45 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIContacts.h" + +class nsContacts : public nsIContacts +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICONTACTS +}; diff --git a/embedding/android/AndroidManifest.xml.in b/embedding/android/AndroidManifest.xml.in --- a/embedding/android/AndroidManifest.xml.in +++ b/embedding/android/AndroidManifest.xml.in @@ -10,16 +10,17 @@ android:targetSdkVersion="5"/> + gPendingEvents = new LinkedList(); @@ -109,16 +115,17 @@ public class GeckoAppShell public static native void setSurfaceView(GeckoSurfaceView sv); public static native void putenv(String map); public static native void onResume(); public static native void onLowMemory(); public static native void callObserver(String observerKey, String topic, String data); public static native void removeObserver(String observerKey); public static native void loadLibs(String apkName, boolean shouldExtract); public static native void onChangeNetworkLinkStatus(String status, String type); + public static native void onQueryContactsComplete(String data); public static native void reportJavaCrash(String stack); // A looper thread, accessed by GeckoAppShell.getHandler private static class LooperThread extends Thread { public SynchronousQueue mHandlerQueue = new SynchronousQueue(); public void run() { @@ -1309,9 +1316,67 @@ public class GeckoAppShell if (resolveInfo == null) return null; ActivityInfo activityInfo = resolveInfo.activityInfo; return activityInfo.loadIcon(pm); } + + static void getContacts() { + long startnow = android.os.SystemClock.uptimeMillis(); + String[] projection = new String[] { + Contacts._ID, + Contacts.DISPLAY_NAME, + Contacts.HAS_PHONE_NUMBER + }; + + ContentResolver cr = GeckoApp.mAppContext.getContentResolver(); + Cursor cur = cr.query(Contacts.CONTENT_URI, projection, null, null, null); + try { + JSONArray array = new JSONArray(); + while (cur.moveToNext()) { + String id = cur.getString(0); + String name = cur.getString(1); + + JSONObject obj = new JSONObject(); + obj.put("fullName", name); + + if (Integer.parseInt(cur.getString(2)) > 0) { + Cursor phoneCur = cr.query( + Phone.CONTENT_URI, new String[] { Phone.NUMBER }, + Phone.CONTACT_ID +" = ?", new String[] { id }, null); + JSONArray phoneNumbers = new JSONArray(); + while (phoneCur.moveToNext()) { + phoneNumbers.put(phoneCur.getString(0)); + } + phoneCur.close(); + + // Add the phone numbers to the contact + obj.put("phoneNumbers", phoneNumbers); + } + + Cursor emailCur = cr.query( + Email.CONTENT_URI, new String[] { Email.DATA }, + Email.CONTACT_ID + " = ?", new String[] { id }, null); + JSONArray emails = new JSONArray(); + while (emailCur.moveToNext()) { + emails.put(emailCur.getString(0)); + } + emailCur.close(); + + // Add the email array to the contact + obj.put("emails", emails); + + // Add the contact to the JSON + array.put(obj); + } + cur.close(); + long endnow = android.os.SystemClock.uptimeMillis(); + Log.d("GeckoContacts", "Execution time: " + (endnow - startnow) + " ms"); + onQueryContactsComplete(array.toString()); + } catch(JSONException jsonEx) { + Log.e("GeckoContacts", "error", jsonEx); + } + onQueryContactsComplete(""); + } } diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -148,24 +148,31 @@ using mozilla::dom::indexedDB::IndexedDa #include "nsPrincipal.h" #include "nsSystemPrincipal.h" #include "nsNullPrincipal.h" #include "nsNetCID.h" #include "nsINodeInfo.h" #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) #include "nsHapticFeedback.h" #endif +#if defined(ANDROID) +#include "nsContacts.h" +#endif #define NS_EDITORCOMMANDTABLE_CID \ { 0x4f5e62b8, 0xd659, 0x4156, { 0x84, 0xfc, 0x2f, 0x60, 0x99, 0x40, 0x03, 0x69 }} #define NS_HAPTICFEEDBACK_CID \ { 0x1f15dbc8, 0xbfaa, 0x45de, \ { 0x8a, 0x46, 0x08, 0xe2, 0xe2, 0x63, 0x26, 0xb0 } } +#define NS_CONTACTS_CID \ +{ 0x897c80b4, 0xcbc7, 0x44e3, \ +{ 0xa0, 0x0f, 0x96, 0xd9, 0xb2, 0x0e, 0xdd, 0x10 } } + static NS_DEFINE_CID(kEditorCommandTableCID, NS_EDITORCOMMANDTABLE_CID); NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor) // Constructor of a controller which is set up to use, internally, a // singleton command-table pre-filled with editor commands. static nsresult nsEditorControllerConstructor(nsISupports *aOuter, REFNSIID aIID, @@ -322,16 +329,19 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR defined(android) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceMotionSystem) #endif NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsWorkerFactory) #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback) #endif +#if defined(ANDROID) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsContacts) +#endif //----------------------------------------------------------------------------- // Per bug 209804, it is necessary to observe the "xpcom-shutdown" event and // perform shutdown of the layout modules at that time instead of waiting for // our module destructor to run. If we do not do this, then we risk holding // references to objects in other component libraries that have already been // shutdown (and possibly unloaded if 60709 is ever fixed). @@ -869,16 +879,19 @@ NS_DEFINE_NAMED_CID(NS_STRUCTUREDCLONECO defined(_WINDOWS) || \ defined(machintosh) || \ defined(android) NS_DEFINE_NAMED_CID(NS_DEVICE_MOTION_CID); #endif #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID); #endif +#if defined(ANDROID) +NS_DEFINE_NAMED_CID(NS_CONTACTS_CID); +#endif static const mozilla::Module::CIDEntry kLayoutCIDs[] = { XPCONNECT_CIDENTRIES #ifdef DEBUG { &kNS_FRAME_UTIL_CID, false, NULL, CreateNewFrameUtil }, { &kNS_LAYOUT_DEBUGGER_CID, false, NULL, CreateNewLayoutDebugger }, #endif { &kNS_FRAMETRAVERSAL_CID, false, NULL, CreateNewFrameTraversal }, @@ -1009,16 +1022,19 @@ static const mozilla::Module::CIDEntry k defined(_WINDOWS) || \ defined(machintosh) || \ defined(android) { &kNS_DEVICE_MOTION_CID, false, NULL, nsDeviceMotionSystemConstructor }, #endif #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) { &kNS_HAPTICFEEDBACK_CID, false, NULL, nsHapticFeedbackConstructor }, #endif +#if defined(ANDROID) + { &kNS_CONTACTS_CID, false, NULL, nsContactsConstructor }, +#endif { &kTHIRDPARTYUTIL_CID, false, NULL, ThirdPartyUtilConstructor }, { &kNS_WORKERFACTORY_CID, false, NULL, nsWorkerFactoryConstructor }, { &kNS_STRUCTUREDCLONECONTAINER_CID, false, NULL, nsStructuredCloneContainerConstructor }, { NULL } }; static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { XPCONNECT_CONTRACTS @@ -1147,16 +1163,19 @@ static const mozilla::Module::ContractID defined(_WINDOWS) || \ defined(machintosh) || \ defined(android) { NS_DEVICE_MOTION_CONTRACTID, &kNS_DEVICE_MOTION_CID }, #endif #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID }, #endif +#if defined(ANDROID) + { "@mozilla.org/dom/contacts;1", &kNS_CONTACTS_CID }, +#endif { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID }, { NS_WORKERFACTORY_CONTRACTID, &kNS_WORKERFACTORY_CID }, { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID }, { NULL } }; static const mozilla::Module::CategoryEntry kLayoutCategories[] = { XPCONNECT_CATEGORIES diff --git a/mobile/components/FormAutoComplete.js b/mobile/components/FormAutoComplete.js --- a/mobile/components/FormAutoComplete.js +++ b/mobile/components/FormAutoComplete.js @@ -39,16 +39,18 @@ 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"); +const MAX_FORM_SUGGESTIONS = 10; + function LOG() { return; // comment out for verbose debugging let msg = Array.join(arguments, " "); dump(msg + "\n"); Cu.reportError(msg); } // Lazily get the base Form AutoComplete Search @@ -72,16 +74,22 @@ FormAutoComplete.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormAutoComplete]), // Specify the html5 types that we want and some values to guess contactTypes: { email: /^(?:.*(?:e-?mail|recipients?).*|(send_)?to(_b?cc)?)$/i, tel: /^(?:tel(?:ephone)?|.*phone.*)$/i }, + contactQuery: { + query: "", + type: "", + suggestions: [] + }, + checkQueryType: function checkQueryType(aName, aField) { // If we have an input field with the desired html5 type, take it! if (aField && "type" in aField) { let type = aField.type; if (type && type in this.contactTypes) return type; } @@ -98,48 +106,61 @@ FormAutoComplete.prototype = { for (let [type, regex] in Iterator(this.contactTypes)) { if (props.some(function(prop) prop.search(regex) != -1)) return type; } return null; }, findContact: function findContact(aQuery, aType, aResult, aDupCheck) { + // Reset the query cache if we need to start fresh + if (aQuery.indexOf(this.contactQuery.query) != 0 || this.contactQuery.type != aType) { + this.contactQuery.query = aQuery; + this.contactQuery.type = aType; + this.contactQuery.contacts = Contacts.get(); + } + + this.contactQuery.query = aQuery; + + this.contactQuery.contacts = this.contactQuery.contacts.filter(function(aContact) { + return aContact.fullName.toLowerCase().indexOf(aQuery) != -1; + }); + + LOG("findContact", "# of Contacts: " + this.contactQuery.contacts.length); + + // Set the property we'll use to get suggestions + let typeProperty; + switch (aType) { + case "email": + typeProperty = "emails"; + break; + case "tel": + typeProperty = "phoneNumbers"; + break; + } + // Match the name and show the email for now.. - Contacts.find({ fullName: aQuery }).forEach(function(contact) { - // Might not have an email for some reason... ? + let contacts = this.contactQuery.contacts + for (let c=0; c"; aResult.appendMatch(suggestion, data, null, "contact"); } } catch(ex) { LOG("findContact error", ex); } - }); + + if (aResult.matchCount >= MAX_FORM_SUGGESTIONS) + break; + } }, autoCompleteSearch: function autoCompleteSearch(aName, aQuery, aField, aPrev) { if (!Services.prefs.getBoolPref("browser.formfill.enable")) return null; LOG("autocomplete search", Array.slice(arguments)); let result = Cc["@mozilla.org/autocomplete/simple-result;1"].createInstance(Ci.nsIAutoCompleteSimpleResult); diff --git a/mobile/modules/contacts.jsm b/mobile/modules/contacts.jsm --- a/mobile/modules/contacts.jsm +++ b/mobile/modules/contacts.jsm @@ -32,16 +32,18 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ let EXPORTED_SYMBOLS = ["Contacts"]; const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; Cu.import("resource://gre/modules/ctypes.jsm"); let Contacts = { _providers: [], _contacts: [], _load: function _load() { @@ -62,45 +64,56 @@ let Contacts = { this._load(); }, addProvider: function(aProvider) { this._providers.push(aProvider); this.refresh(); }, - find: function find(aMatch) { - let results = []; - - if (!this._contacts.length) - return results; - - for (let field in aMatch) { - // Simple string-only partial matching - let match = aMatch[field]; - this._contacts.forEach(function(aContact) { - if (field in aContact && aContact[field].indexOf(match) != -1) - results.push(aContact); - }); - } - return results; + get: function get() { + this.refresh(); + return this._contacts; } }; -#ifndef ANDROID +#ifdef ANDROID +function AndroidContactsProvider() { + _contacts = []; + + Cc["@mozilla.org/dom/contacts;1"].getService(Ci.nsIContacts).queryContacts(this); +} + +AndroidContactsProvider.prototype = { + notify: function(aJSON) { + this._contacts = JSON.parse(aJSON); + }, + + getContacts: function() { + return this._contacts; + } +}; + +Contacts.addProvider(new AndroidContactsProvider()); +#else #ifndef XP_MACOSX #ifdef XP_UNIX Cu.import("resource:///modules/linuxTypes.jsm"); function EBookProvider() { EBook.init(); + _contacts = this._queryContacts(); } EBookProvider.prototype = { getContacts: function() { + return this._contacts; + }, + + _queryContacts: function() { if (!EBook.lib) { Cu.reportError("EBook not loaded") return []; } let gError = new GLib.GError.ptr; let book = EBook.openSystem(gError.address()); if (!book) { @@ -147,13 +160,13 @@ EBookProvider.prototype = { gList = ctypes.cast(gList.contents.next, GLib.GList.ptr); } return contacts; } return []; } }; -Contacts.addProvider(new EBookProvider); +Contacts.addProvider(new EBookProvider()); # XP_UNIX #endif #endif #endif diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -234,16 +234,17 @@ SHELL_WRAPPER0(nativeInit) SHELL_WRAPPER1(nativeRun, jstring) SHELL_WRAPPER1(notifyGeckoOfEvent, jobject) SHELL_WRAPPER1(setSurfaceView, jobject) SHELL_WRAPPER0(onResume) SHELL_WRAPPER0(onLowMemory) SHELL_WRAPPER3(callObserver, jstring, jstring, jstring) SHELL_WRAPPER1(removeObserver, jstring) SHELL_WRAPPER2(onChangeNetworkLinkStatus, jstring, jstring) +SHELL_WRAPPER1(onQueryContactsComplete, jstring) SHELL_WRAPPER1(reportJavaCrash, jstring) static void * xul_handle = NULL; static time_t apk_mtime = 0; #ifdef DEBUG extern "C" int extractLibs = 1; #else extern "C" int extractLibs = 0; @@ -677,16 +678,17 @@ loadLibs(const char *apkName) GETFUNC(nativeRun); GETFUNC(notifyGeckoOfEvent); GETFUNC(setSurfaceView); GETFUNC(onResume); GETFUNC(onLowMemory); GETFUNC(callObserver); GETFUNC(removeObserver); GETFUNC(onChangeNetworkLinkStatus); + GETFUNC(onQueryContactsComplete); GETFUNC(reportJavaCrash); #undef GETFUNC gettimeofday(&t1, 0); struct rusage usage2; getrusage(RUSAGE_SELF, &usage2); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %dms total, %dms user, %dms system, %d faults", (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000, diff --git a/widget/src/android/AndroidBridge.cpp b/widget/src/android/AndroidBridge.cpp --- a/widget/src/android/AndroidBridge.cpp +++ b/widget/src/android/AndroidBridge.cpp @@ -142,16 +142,17 @@ AndroidBridge::Init(JNIEnv *jEnv, jSetKeepScreenOn = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setKeepScreenOn", "(Z)V"); jIsNetworkLinkUp = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkUp", "()Z"); jIsNetworkLinkKnown = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkKnown", "()Z"); jGetNetworkLinkType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNetworkLinkType", "()I"); jSetSelectedLocale = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setSelectedLocale", "(Ljava/lang/String;)V"); jScanMedia = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V"); jGetSystemColors = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getSystemColors", "()[I"); jGetIconForExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B"); + jGetContacts = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getContacts", "()V;"); jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext")); jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10")); jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl")); jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl")); jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl")); jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl")); @@ -750,16 +751,33 @@ AndroidBridge::GetIconForExtension(const NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!"); if (len == bufSize) memcpy(aBuf, elements, bufSize); mJNIEnv->ReleaseByteArrayElements(arr, elements, 0); } void +AndroidBridge::GetContacts(nsIContactsCallback* aCallback) +{ + //jstring jstr = static_cast(mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetContacts)); + mContactsCallback = aCallback; + mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetContacts); +} + +void +AndroidBridge::DoContactsCallback(const nsAString& aContacts) +{ + if (mContactsCallback) { + mContactsCallback->Notify(aContacts); + mContactsCallback = nsnull; + } +} + +void AndroidBridge::SetSurfaceView(jobject obj) { mSurfaceView.Init(obj); } void AndroidBridge::ShowInputMethodPicker() { diff --git a/widget/src/android/AndroidBridge.h b/widget/src/android/AndroidBridge.h --- a/widget/src/android/AndroidBridge.h +++ b/widget/src/android/AndroidBridge.h @@ -46,16 +46,18 @@ #include "nsIObserver.h" #include "AndroidJavaWrappers.h" #include "nsIMutableArray.h" #include "nsIMIMEInfo.h" #include "nsColor.h" +#include "nsIContacts.h" + // Some debug #defines // #define ANDROID_DEBUG_EVENTS // #define ANDROID_DEBUG_WIDGET class nsWindow; namespace mozilla { @@ -207,16 +209,19 @@ public: int GetNetworkLinkType(); void SetSelectedLocale(const nsAString&); void GetSystemColors(AndroidSystemColors *aColors); void GetIconForExtension(const nsACString& aFileExt, PRUint32 aIconSize, PRUint8 * const aBuf); + void GetContacts(nsIContactsCallback* aCallback); + void DoContactsCallback(const nsAString& aContacts); + struct AutoLocalJNIFrame { AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) { // Make sure there is enough space to store a local ref to the // exception. I am not completely sure this is needed, but does // not hurt. AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries + 1); } // Note! Calling Purge makes all previous local refs created in @@ -277,16 +282,19 @@ protected: AndroidBridge() { } PRBool Init(JNIEnv *jEnv, jclass jGeckoApp); void EnsureJNIThread(); bool mOpenedBitmapLibrary; bool mHasNativeBitmapAccess; + // the callback for querying contacts + nsCOMPtr mContactsCallback; + // other things jmethodID jNotifyIME; jmethodID jNotifyIMEEnabled; jmethodID jNotifyIMEChange; jmethodID jAcknowledgeEventSync; jmethodID jEnableDeviceMotion; jmethodID jEnableLocation; jmethodID jReturnIMEQueryResult; @@ -314,16 +322,17 @@ protected: jmethodID jSetKeepScreenOn; jmethodID jIsNetworkLinkUp; jmethodID jIsNetworkLinkKnown; jmethodID jGetNetworkLinkType; jmethodID jSetSelectedLocale; jmethodID jScanMedia; jmethodID jGetSystemColors; jmethodID jGetIconForExtension; + jmethodID jGetContacts; // stuff we need for CallEglCreateWindowSurface jclass jEGLSurfaceImplClass; jclass jEGLContextImplClass; jclass jEGLConfigImplClass; jclass jEGLDisplayImplClass; jclass jEGLContextClass; jclass jEGL10Class; diff --git a/widget/src/android/AndroidJNI.cpp b/widget/src/android/AndroidJNI.cpp --- a/widget/src/android/AndroidJNI.cpp +++ b/widget/src/android/AndroidJNI.cpp @@ -65,16 +65,17 @@ extern "C" { NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *, jclass); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *, jclass, jobject event); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *, jclass); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *, jclass, jstring observerKey, jstring topic, jstring data); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *, jclass, jstring status, jstring type); + NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onQueryContactsComplete(JNIEnv *, jclass, jstring data); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack); } /* * Incoming JNI methods */ @@ -157,16 +158,27 @@ Java_org_mozilla_gecko_GeckoAppShell_onC nsJNIString sType(jType, jenv); nsAppShell::gAppShell->NotifyObservers(nsnull, NS_NETWORK_LINK_TYPE_TOPIC, sType.get()); } NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_onQueryContactsComplete(JNIEnv *jenv, jclass, jstring jData) +{ + if (!nsAppShell::gAppShell) + return; + + const jchar *json = jenv->GetStringChars(jData, NULL); + nsString sJSON(json); + AndroidBridge::Bridge()->DoContactsCallback(sJSON); +} + +NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack) { #ifdef MOZ_CRASHREPORTER nsJNIString javaStack(stack); CrashReporter::AppendAppNotesToCrashReport( NS_ConvertUTF16toUTF8(javaStack)); #endif abort(); diff --git a/xpcom/system/Makefile.in b/xpcom/system/Makefile.in --- a/xpcom/system/Makefile.in +++ b/xpcom/system/Makefile.in @@ -51,15 +51,16 @@ XPIDLSRCS = \ nsIGConfService.idl \ nsIGnomeVFSService.idl \ nsIBlocklistService.idl \ nsIGIOService.idl \ nsIGSettingsService.idl \ nsIDeviceMotion.idl \ nsIGeolocationProvider.idl \ nsIHapticFeedback.idl \ + nsIContacts.idl \ $(NULL) ifdef MOZ_CRASHREPORTER XPIDLSRCS += nsICrashReporter.idl endif include $(topsrcdir)/config/rules.mk diff --git a/xpcom/system/nsIContacts.idl b/xpcom/system/nsIContacts.idl new file mode 100644 --- /dev/null +++ b/xpcom/system/nsIContacts.idl @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +[function, scriptable, uuid(71d61e95-3b71-4052-b3c8-920320cc2ce0)] +interface nsIContactsCallback : nsISupports +{ + /** + * @param aContacts the array of contacts pulled from the system + */ + void notify(in AString aContacts); +}; + +[scriptable, uuid(f32b9c77-4eb4-48f4-84d6-6374de6ba6db)] +interface nsIContacts : nsISupports { + /** + * @param aCallback the callback to notify when the async query completes + */ + void queryContacts(in nsIContactsCallback aCallback); +};