Merge m-i into m-c.
Merge m-i into m-c.
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -151,16 +151,17 @@
@BINPATH@/components/dom_system_b2g.xpt
#endif
@BINPATH@/components/dom_battery.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt
@BINPATH@/components/dom_events.xpt
@BINPATH@/components/dom_geolocation.xpt
+@BINPATH@/components/dom_network.xpt
@BINPATH@/components/dom_notification.xpt
@BINPATH@/components/dom_html.xpt
@BINPATH@/components/dom_indexeddb.xpt
@BINPATH@/components/dom_offline.xpt
@BINPATH@/components/dom_json.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_sms.xpt
--- a/browser/components/preferences/main.js
+++ b/browser/components/preferences/main.js
@@ -366,17 +366,17 @@ var gMainPane = {
// With 3.0, a new desktop folder - 'Downloads' was introduced for
// platforms and versions that don't support a default system downloads
// folder. See nsDownloadManager for details.
downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
iconUrlSpec = fph.getURLSpecFromFile(this._indexToFolder(1));
} else {
// 'Desktop'
downloadFolder.label = bundlePreferences.getString("desktopFolderName");
- iconUrlSpec = fph.getURLSpecFromFile(desk);
+ iconUrlSpec = fph.getURLSpecFromFile(this._getDownloadsFolder("Desktop"));
}
downloadFolder.image = "moz-icon://" + iconUrlSpec + "?size=16";
// don't override the preference's value in UI
return undefined;
},
/**
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -141,16 +141,17 @@
@BINPATH@/components/dom_system_b2g.xpt
#endif
@BINPATH@/components/dom_battery.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt
@BINPATH@/components/dom_events.xpt
@BINPATH@/components/dom_geolocation.xpt
+@BINPATH@/components/dom_network.xpt
@BINPATH@/components/dom_notification.xpt
@BINPATH@/components/dom_html.xpt
@BINPATH@/components/dom_indexeddb.xpt
@BINPATH@/components/dom_offline.xpt
@BINPATH@/components/dom_json.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_sms.xpt
--- a/browser/installer/windows/nsis/maintenanceservice_installer.nsi
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -116,19 +116,18 @@ ShowUnInstDetails nevershow
!define MUI_UNICON setup.ico
!define MUI_WELCOMEPAGE_TITLE_3LINES
!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
;Interface Settings
!define MUI_ABORTWARNING
; Uninstaller Pages
-!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
-!insertmacro MUI_UNPAGE_FINISH
################################################################################
# Language
!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
!verbose push
!verbose 3
!include "overrideLocale.nsh"
@@ -252,16 +251,18 @@ FunctionEnd
Section "Uninstall"
; Delete the service so that no updates will be attempted
nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
Push "$INSTDIR\maintenanceservice.exe"
Call un.RenameDelete
Push "$INSTDIR\maintenanceservice_tmp.exe"
Call un.RenameDelete
+ Push "$INSTDIR\maintenanceservice.old"
+ Call un.RenameDelete
Push "$INSTDIR\Uninstall.exe"
Call un.RenameDelete
RMDir /REBOOTOK "$INSTDIR"
DeleteRegKey HKLM "${MaintUninstallKey}"
SetRegView 64
DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -141,16 +141,17 @@ MOZ_INSTALLER = @MOZ_INSTALLER@
MOZ_MAINTENANCE_SERVICE = @MOZ_MAINTENANCE_SERVICE@
MOZ_UPDATER = @MOZ_UPDATER@
MOZ_UPDATE_CHANNEL = @MOZ_UPDATE_CHANNEL@
MOZ_UPDATE_PACKAGING = @MOZ_UPDATE_PACKAGING@
MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
NS_ENABLE_TSF = @NS_ENABLE_TSF@
MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
+MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
MOZ_FEEDS = @MOZ_FEEDS@
MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@
MOZ_PLACES = @MOZ_PLACES@
MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
--- a/configure.in
+++ b/configure.in
@@ -4624,16 +4624,17 @@ MOZ_DISABLE_DOMCRYPTO=
NSS_DISABLE_DBM=
NECKO_WIFI=1
NECKO_COOKIES=1
NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg device"
USE_ARM_KUSER=
BUILD_CTYPES=1
MOZ_USE_NATIVE_POPUP_WINDOWS=
MOZ_ANDROID_HISTORY=
+MOZ_WEBSMS_BACKEND=1
MOZ_GRAPHITE=1
case "${target}" in
*darwin*)
ACCESSIBILITY=
;;
*)
ACCESSIBILITY=1
@@ -5460,16 +5461,28 @@ AC_SUBST(MOZ_DBUS_GLIB_LIBS)
dnl ========================================================
dnl = Enable Android History instead of Places
dnl ========================================================
if test -n "$MOZ_ANDROID_HISTORY"; then
dnl Do this if defined in confvars.sh
AC_DEFINE(MOZ_ANDROID_HISTORY)
fi
+dnl ========================================================
+dnl = Disable WebSMS backend
+dnl ========================================================
+MOZ_ARG_DISABLE_BOOL(websms-backend,
+[ --disable-websms-backend
+ Disable WebSMS backend],
+ MOZ_WEBSMS_BACKEND=,
+ MOZ_WEBSMS_BACKEND=1)
+
+if test $MOZ_WEBSMS_BACKEND -eq 1; then
+ AC_DEFINE(MOZ_WEBSMS_BACKEND)
+fi
dnl ========================================================
dnl = Build Personal Security Manager
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(crypto,
[ --disable-crypto Disable crypto support (Personal Security Manager)],
MOZ_PSM=,
MOZ_PSM=1 )
@@ -8440,16 +8453,17 @@ AC_SUBST(MOZ_DIRECTX_SDK_PATH)
AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
AC_SUBST(MOZ_D3DX9_VERSION)
AC_SUBST(MOZ_D3DX9_CAB)
AC_SUBST(MOZ_D3DCOMPILER_CAB)
AC_SUBST(MOZ_D3DX9_DLL)
AC_SUBST(MOZ_D3DCOMPILER_DLL)
AC_SUBST(MOZ_ANDROID_HISTORY)
+AC_SUBST(MOZ_WEBSMS_BACKEND)
AC_SUBST(ENABLE_STRIP)
AC_SUBST(PKG_SKIP_STRIP)
AC_SUBST(USE_ELF_DYNSTR_GC)
AC_SUBST(USE_ELF_HACK)
AC_SUBST(INCREMENTAL_LINKER)
AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
AC_SUBST(MOZ_COMPONENT_NSPR_LIBS)
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -70,16 +70,17 @@ DIRS = \
$(NULL)
DIRS += \
base \
battery \
sms \
src \
locales \
+ network \
plugins/base \
plugins/ipc \
indexedDB \
system \
ipc \
workers \
$(NULL)
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -69,16 +69,17 @@
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "BatteryManager.h"
#include "SmsManager.h"
#include "nsISmsService.h"
#include "mozilla/Hal.h"
#include "nsIWebNavigation.h"
#include "mozilla/ClearOnShutdown.h"
+#include "Connection.h"
#ifdef MOZ_B2G_RIL
#include "TelephonyFactory.h"
#endif
// This should not be in the namespace.
DOMCI_DATA(Navigator, mozilla::dom::Navigator)
@@ -125,16 +126,17 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
#ifdef MOZ_B2G_RIL
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
#endif
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorNetwork)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(Navigator)
NS_IMPL_RELEASE(Navigator)
void
Navigator::Invalidate()
@@ -167,16 +169,21 @@ Navigator::Invalidate()
mSmsManager = nsnull;
}
#ifdef MOZ_B2G_RIL
if (mTelephony) {
mTelephony = nsnull;
}
#endif
+
+ if (mConnection) {
+ mConnection->Shutdown();
+ mConnection = nsnull;
+ }
}
nsPIDOMWindow *
Navigator::GetWindow()
{
nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
return win;
@@ -989,23 +996,27 @@ Navigator::IsSmsAllowed() const
// The current page hasn't been whitelisted.
return false;
}
bool
Navigator::IsSmsSupported() const
{
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+#ifdef MOZ_WEBSMS_BACKEND
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, false);
bool result = false;
smsService->HasSupport(&result);
return result;
+#else
+ return false;
+#endif
}
NS_IMETHODIMP
Navigator::GetMozSms(nsIDOMMozSmsManager** aSmsManager)
{
*aSmsManager = nsnull;
if (!mSmsManager) {
@@ -1054,16 +1065,43 @@ Navigator::GetMozTelephony(nsIDOMTelepho
}
telephony.forget(aTelephony);
return NS_OK;
}
#endif // MOZ_B2G_RIL
+//*****************************************************************************
+// Navigator::nsIDOMNavigatorNetwork
+//*****************************************************************************
+
+NS_IMETHODIMP
+Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
+{
+ *aConnection = nsnull;
+
+ if (!mConnection) {
+ nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+ NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
+
+ nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
+ NS_ENSURE_TRUE(sgo, NS_OK);
+
+ nsIScriptContext* scx = sgo->GetContext();
+ NS_ENSURE_TRUE(scx, NS_OK);
+
+ mConnection = new network::Connection();
+ mConnection->Init(window, scx);
+ }
+
+ NS_ADDREF(*aConnection = mConnection);
+ return NS_OK;
+}
+
PRInt64
Navigator::SizeOf() const
{
PRInt64 size = sizeof(*this);
// TODO: add SizeOf() to nsMimeTypeArray, bug 674113.
size += mMimeTypes ? sizeof(*mMimeTypes.get()) : 0;
// TODO: add SizeOf() to nsPluginArray, bug 674114.
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -44,24 +44,26 @@
#define mozilla_dom_Navigator_h
#include "nsIDOMNavigator.h"
#include "nsIDOMNavigatorGeolocation.h"
#include "nsIDOMNavigatorDesktopNotification.h"
#include "nsIDOMClientInformation.h"
#include "nsIDOMNavigatorBattery.h"
#include "nsIDOMNavigatorSms.h"
+#include "nsIDOMNavigatorNetwork.h"
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
class nsPluginArray;
class nsMimeTypeArray;
class nsGeolocation;
class nsDesktopNotificationCenter;
class nsPIDOMWindow;
+class nsIDOMMozConnection;
#ifdef MOZ_B2G_RIL
#include "nsIDOMNavigatorTelephony.h"
class nsIDOMTelephony;
#endif
//*****************************************************************************
// Navigator: Script "navigator" object
@@ -73,41 +75,46 @@ namespace dom {
namespace battery {
class BatteryManager;
} // namespace battery
namespace sms {
class SmsManager;
} // namespace sms
-class Navigator : public nsIDOMNavigator,
- public nsIDOMClientInformation,
- public nsIDOMNavigatorGeolocation,
- public nsIDOMNavigatorDesktopNotification,
- public nsIDOMMozNavigatorBattery,
- public nsIDOMMozNavigatorSms
+namespace network {
+class Connection;
+} // namespace Connection;
+
+class Navigator : public nsIDOMNavigator
+ , public nsIDOMClientInformation
+ , public nsIDOMNavigatorGeolocation
+ , public nsIDOMNavigatorDesktopNotification
+ , public nsIDOMMozNavigatorBattery
+ , public nsIDOMMozNavigatorSms
#ifdef MOZ_B2G_RIL
, public nsIDOMNavigatorTelephony
#endif
+ , public nsIDOMMozNavigatorNetwork
{
public:
Navigator(nsPIDOMWindow *aInnerWindow);
virtual ~Navigator();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMNAVIGATOR
NS_DECL_NSIDOMCLIENTINFORMATION
NS_DECL_NSIDOMNAVIGATORGEOLOCATION
NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION
NS_DECL_NSIDOMMOZNAVIGATORBATTERY
NS_DECL_NSIDOMMOZNAVIGATORSMS
-
#ifdef MOZ_B2G_RIL
NS_DECL_NSIDOMNAVIGATORTELEPHONY
#endif
+ NS_DECL_NSIDOMMOZNAVIGATORNETWORK
static void Init();
void Invalidate();
nsPIDOMWindow *GetWindow();
void RefreshMIMEArray();
@@ -128,16 +135,17 @@ private:
nsRefPtr<nsPluginArray> mPlugins;
nsRefPtr<nsGeolocation> mGeolocation;
nsRefPtr<nsDesktopNotificationCenter> mNotification;
nsRefPtr<battery::BatteryManager> mBatteryManager;
nsRefPtr<sms::SmsManager> mSmsManager;
#ifdef MOZ_B2G_RIL
nsCOMPtr<nsIDOMTelephony> mTelephony;
#endif
+ nsRefPtr<network::Connection> mConnection;
nsWeakPtr mWindow;
};
} // namespace dom
} // namespace mozilla
nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -34,16 +34,21 @@
* 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/Util.h"
+#include "SmsFilter.h" // On top because it includes basictypes.h.
+
+#ifdef XP_WIN
+#undef GetClassName
+#endif
// JavaScript includes
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jsprvtd.h" // we are using private JS typedefs...
#include "jsdbgapi.h"
#include "WrapperFactory.h"
#include "AccessCheck.h"
@@ -159,21 +164,16 @@
#include "nsIDOMHTMLSelectElement.h"
// HTMLEmbed/ObjectElement helper includes
#include "nsNPAPIPluginInstance.h"
#include "nsIObjectFrame.h"
#include "nsIObjectLoadingContent.h"
#include "nsIPluginHost.h"
-// Oh, did I mention that I hate Microsoft for doing this to me?
-#ifdef XP_WIN
-#undef GetClassName
-#endif
-
// HTMLOptionsCollection includes
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMHTMLOptionsCollection.h"
// ContentList includes
#include "nsContentList.h"
#include "nsGenericElement.h"
@@ -509,17 +509,22 @@
#include "nsWrapperCacheInlines.h"
#include "dombindings.h"
#include "nsIDOMBatteryManager.h"
#include "BatteryManager.h"
#include "nsIDOMSmsManager.h"
#include "nsIDOMSmsMessage.h"
#include "nsIDOMSmsEvent.h"
+#include "nsIDOMSmsRequest.h"
+#include "nsIDOMSmsFilter.h"
+#include "nsIDOMSmsCursor.h"
#include "nsIPrivateDOMEvent.h"
+#include "nsIDOMConnection.h"
+#include "mozilla/dom/network/Utils.h"
#ifdef MOZ_B2G_RIL
#include "Telephony.h"
#include "TelephonyCall.h"
#include "CallEvent.h"
#endif
using namespace mozilla;
@@ -1406,16 +1411,28 @@ static nsDOMClassInfoData sClassInfoData
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozSmsEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
+ NS_DEFINE_CLASSINFO_DATA(MozSmsRequest, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+ NS_DEFINE_CLASSINFO_DATA(MozSmsFilter, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+ NS_DEFINE_CLASSINFO_DATA(MozSmsCursor, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+ NS_DEFINE_CLASSINFO_DATA(MozConnection, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceStyleDecl, nsCSSStyleDeclSH,
ARRAY_SCRIPTABLE_FLAGS)
#if defined(MOZ_MEDIA)
NS_DEFINE_CLASSINFO_DATA(HTMLVideoElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
@@ -1632,16 +1649,17 @@ static const nsConstructorFuncMapData kC
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
+ NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
};
nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull;
nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull;
bool nsDOMClassInfo::sIsInitialized = false;
bool nsDOMClassInfo::sDisableDocumentAllSupport = false;
bool nsDOMClassInfo::sDisableGlobalScopePollutionSupport = false;
@@ -2354,16 +2372,18 @@ nsDOMClassInfo::Init()
Navigator::HasDesktopNotificationSupport())
DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientInformation)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery,
battery::BatteryManager::HasSupport())
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms)
#ifdef MOZ_B2G_RIL
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony)
#endif
+ DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorNetwork,
+ network::IsAPIEnabled())
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMPlugin)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(PluginArray, nsIDOMPluginArray)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMPluginArray)
@@ -3981,16 +4001,33 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MozSmsEvent, nsIDOMMozSmsEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
+ DOM_CLASSINFO_MAP_BEGIN(MozSmsRequest, nsIDOMMozSmsRequest)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsRequest)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+ DOM_CLASSINFO_MAP_END
+
+ DOM_CLASSINFO_MAP_BEGIN(MozSmsFilter, nsIDOMMozSmsFilter)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsFilter)
+ DOM_CLASSINFO_MAP_END
+
+ DOM_CLASSINFO_MAP_BEGIN(MozSmsCursor, nsIDOMMozSmsCursor)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsCursor)
+ DOM_CLASSINFO_MAP_END
+
+ DOM_CLASSINFO_MAP_BEGIN(MozConnection, nsIDOMMozConnection)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozConnection)
+ DOM_CLASSINFO_MAP_END
+
DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSFontFaceStyleDecl,
nsIDOMCSSStyleDeclaration)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleDeclaration)
DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -428,16 +428,21 @@ DOMCI_CLASS(GeoPositionCoords)
DOMCI_CLASS(GeoPositionAddress)
DOMCI_CLASS(GeoPositionError)
DOMCI_CLASS(MozBatteryManager)
DOMCI_CLASS(MozSmsManager)
DOMCI_CLASS(MozSmsMessage)
DOMCI_CLASS(MozSmsEvent)
+DOMCI_CLASS(MozSmsRequest)
+DOMCI_CLASS(MozSmsFilter)
+DOMCI_CLASS(MozSmsCursor)
+
+DOMCI_CLASS(MozConnection)
// @font-face in CSS
DOMCI_CLASS(CSSFontFaceRule)
DOMCI_CLASS(CSSFontFaceStyleDecl)
#if defined(MOZ_MEDIA)
// WhatWG Video Element
DOMCI_CLASS(HTMLVideoElement)
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -1,11 +1,12 @@
DOM_SRCDIRS = \
dom/base \
dom/battery \
+ dom/network/src \
dom/sms/src \
dom/src/events \
dom/src/storage \
dom/src/offline \
dom/src/geolocation \
dom/src/notification \
dom/workers \
content/xbl/src \
new file mode 100644
--- /dev/null
+++ b/dom/network/Makefile.in
@@ -0,0 +1,50 @@
+# ***** 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 build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+PARALLEL_DIRS = interfaces src
+
+ifdef ENABLE_TESTS
+DIRS += tests
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/Makefile.in
@@ -0,0 +1,53 @@
+# ***** 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 build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+XPIDL_MODULE = dom_network
+
+include $(topsrcdir)/dom/dom-config.mk
+
+XPIDLSRCS = \
+ nsIDOMNavigatorNetwork.idl \
+ nsIDOMConnection.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsIDOMConnection.idl
@@ -0,0 +1,48 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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"
+
+interface nsIDOMEventListener;
+
+[scriptable, uuid(8c6b574d-1135-4387-a6e3-6d8ba38d79a1)]
+interface nsIDOMMozConnection : nsISupports
+{
+ readonly attribute double bandwidth;
+ readonly attribute boolean metered;
+
+ attribute nsIDOMEventListener onchange;
+};
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsIDOMNavigatorNetwork.idl
@@ -0,0 +1,45 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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"
+
+interface nsIDOMMozConnection;
+
+[scriptable, uuid(1dd6773e-30dc-419b-9766-b05458fd96c8)]
+interface nsIDOMMozNavigatorNetwork : nsISupports
+{
+ readonly attribute nsIDOMMozConnection mozConnection;
+};
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Connection.cpp
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 <limits>
+#include "mozilla/Hal.h"
+#include "Connection.h"
+#include "nsIDOMClassInfo.h"
+#include "mozilla/Preferences.h"
+#include "nsDOMEvent.h"
+#include "Constants.h"
+
+/**
+ * We have to use macros here because our leak analysis tool things we are
+ * leaking strings when we have |static const nsString|. Sad :(
+ */
+#define CHANGE_EVENT_NAME NS_LITERAL_STRING("change")
+
+DOMCI_DATA(MozConnection, mozilla::dom::network::Connection)
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+const char* Connection::sMeteredPrefName = "dom.network.metered";
+const bool Connection::sMeteredDefaultValue = false;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Connection)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Connection,
+ nsDOMEventTargetWrapperCache)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Connection,
+ nsDOMEventTargetWrapperCache)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Connection)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMozConnection)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozConnection)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozConnection)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+
+Connection::Connection()
+ : mCanBeMetered(kDefaultCanBeMetered)
+ , mBandwidth(kDefaultBandwidth)
+{
+}
+
+void
+Connection::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+{
+ // Those vars come from nsDOMEventTargetHelper.
+ mOwner = aWindow;
+ mScriptContext = aScriptContext;
+
+ hal::RegisterNetworkObserver(this);
+
+ hal::NetworkInformation networkInfo;
+ hal::GetCurrentNetworkInformation(&networkInfo);
+
+ UpdateFromNetworkInfo(networkInfo);
+}
+
+void
+Connection::Shutdown()
+{
+ hal::UnregisterNetworkObserver(this);
+}
+
+NS_IMETHODIMP
+Connection::GetBandwidth(double* aBandwidth)
+{
+ if (mBandwidth == kDefaultBandwidth) {
+ *aBandwidth = std::numeric_limits<double>::infinity();
+ return NS_OK;
+ }
+
+ *aBandwidth = mBandwidth;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Connection::GetMetered(bool* aMetered)
+{
+ if (!mCanBeMetered) {
+ *aMetered = false;
+ return NS_OK;
+ }
+
+ *aMetered = Preferences::GetBool(sMeteredPrefName,
+ sMeteredDefaultValue);
+ return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(Connection, change)
+
+nsresult
+Connection::DispatchTrustedEventToSelf(const nsAString& aEventName)
+{
+ nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+ nsresult rv = event->InitEvent(aEventName, false, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = event->SetTrusted(PR_TRUE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool dummy;
+ rv = DispatchEvent(event, &dummy);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+void
+Connection::UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo)
+{
+ mBandwidth = aNetworkInfo.bandwidth();
+ mCanBeMetered = aNetworkInfo.canBeMetered();
+}
+
+void
+Connection::Notify(const hal::NetworkInformation& aNetworkInfo)
+{
+ double previousBandwidth = mBandwidth;
+ bool previousCanBeMetered = mCanBeMetered;
+
+ UpdateFromNetworkInfo(aNetworkInfo);
+
+ if (previousBandwidth == mBandwidth &&
+ previousCanBeMetered == mCanBeMetered) {
+ return;
+ }
+
+ DispatchTrustedEventToSelf(CHANGE_EVENT_NAME);
+}
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Connection.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_network_Connection_h
+#define mozilla_dom_network_Connection_h
+
+#include "nsIDOMConnection.h"
+#include "nsDOMEventTargetWrapperCache.h"
+#include "nsCycleCollectionParticipant.h"
+#include "mozilla/Observer.h"
+#include "Types.h"
+
+namespace mozilla {
+
+namespace hal {
+class NetworkInformation;
+} // namespace hal
+
+namespace dom {
+namespace network {
+
+class Connection : public nsDOMEventTargetWrapperCache
+ , public nsIDOMMozConnection
+ , public NetworkObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDOMMOZCONNECTION
+
+ NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
+
+ Connection();
+
+ void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+ void Shutdown();
+
+ // For IObserver
+ void Notify(const hal::NetworkInformation& aNetworkInfo);
+
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Connection,
+ nsDOMEventTargetWrapperCache)
+
+private:
+ /**
+ * Dispatch a trusted non-cancellable and non-bubbling event to itself.
+ */
+ nsresult DispatchTrustedEventToSelf(const nsAString& aEventName);
+
+ /**
+ * Update the connection information stored in the object using a
+ * NetworkInformation object.
+ */
+ void UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo);
+
+ /**
+ * If the connection is of a type that can be metered.
+ */
+ bool mCanBeMetered;
+
+ /**
+ * The connection bandwidth.
+ */
+ double mBandwidth;
+
+ NS_DECL_EVENT_HANDLER(change)
+
+ static const char* sMeteredPrefName;
+ static const bool sMeteredDefaultValue;
+};
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Connection_h
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Constants.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_network_Constants_h__
+#define mozilla_dom_network_Constants_h__
+
+/**
+ * A set of constants to be used by network backends.
+ */
+namespace mozilla {
+namespace dom {
+namespace network {
+
+ static const double kDefaultBandwidth = -1.0;
+ static const bool kDefaultCanBeMetered = false;
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Constants_h__
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Makefile.in
@@ -0,0 +1,69 @@
+# ***** 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 build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = $(srcdir)
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME = dom_network_s
+LIBXUL_LIBRARY = 1
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/dom/dom-config.mk
+
+EXPORTS_NAMESPACES = mozilla/dom/network
+
+EXPORTS_mozilla/dom/network = \
+ Utils.h \
+ Types.h \
+ Constants.h \
+ $(NULL)
+
+CPPSRCS = \
+ Connection.cpp \
+ Utils.cpp \
+ $(NULL)
+
+LOCAL_INCLUDES = \
+ -I$(topsrcdir)/content/events/src \
+ $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Types.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_network_Types_h
+#define mozilla_dom_network_Types_h
+
+namespace mozilla {
+namespace hal {
+class NetworkInformation;
+} // namespace hal
+
+template <class T>
+class Observer;
+
+typedef Observer<hal::NetworkInformation> NetworkObserver;
+
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Types_h
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Utils.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "Utils.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+/* extern */ bool
+IsAPIEnabled()
+{
+ return Preferences::GetBool("dom.network.enabled", true);
+}
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Utils.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_network_Utils_h
+#define mozilla_dom_network_Utils_h
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+/**
+ * Returns whether the Network API is enabled.
+ * @return whether the Network API is enabled.
+ */
+extern bool IsAPIEnabled();
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Utils_h
+
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/Makefile.in
@@ -0,0 +1,62 @@
+# ***** 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 build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+relativesrcdir = dom/network/tests
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+ test_network_basics.html \
+ $(NULL)
+
+_CHROME_TEST_FILES = \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+#libs:: $(_CHROME_TEST_FILES)
+# $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/test_network_basics.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Network API</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Network API **/
+
+function checkInterface(aInterface) {
+ ok(!(aInterface in window), aInterface + " should be prefixed");
+ ok(("Moz" + aInterface) in window, aInterface + " should be prefixed");
+}
+
+ok('mozConnection' in navigator, "navigator.mozConnection should exist");
+
+ok(navigator.mozConnection, "navigator.mozConnection returns an object");
+
+ok(navigator.mozConnection instanceof MozConnection,
+ "navigator.mozConnection is a MozConnection object");
+
+checkInterface("Connection");
+
+ok('bandwidth' in navigator.mozConnection,
+ "bandwidth should be a Connection attribute");
+is(navigator.mozConnection.bandwidth, Infinity,
+ "By default connection.bandwidth is equals to Infinity");
+
+ok('metered' in navigator.mozConnection,
+ "metered should be a Connection attribute");
+is(navigator.mozConnection.metered, false,
+ "By default the connection is not metered");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2502,17 +2502,17 @@ NPError NP_CALLBACK
else {
return NPERR_GENERIC_ERROR;
}
}
#endif
#ifdef MOZ_WIDGET_ANDROID
case kRequestDrawingModel_ANPSetValue:
if (inst)
- inst->SetDrawingModel(NS_PTR_TO_INT32(result));
+ inst->SetANPDrawingModel(NS_PTR_TO_INT32(result));
return NPERR_NO_ERROR;
case kAcceptEvents_ANPSetValue:
return NPERR_NO_ERROR;
#endif
default:
return NPERR_GENERIC_ERROR;
}
}
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -84,17 +84,17 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
#ifdef NP_NO_QUICKDRAW
mDrawingModel(NPDrawingModelCoreGraphics),
#else
mDrawingModel(NPDrawingModelQuickDraw),
#endif
#endif
#ifdef MOZ_WIDGET_ANDROID
mSurface(nsnull),
- mDrawingModel(0),
+ mANPDrawingModel(0),
#endif
mRunning(NOT_STARTED),
mWindowless(false),
mWindowlessLocal(false),
mTransparent(false),
mCached(false),
mUsesDOMForCursor(false),
mInPluginInitCall(false),
@@ -726,20 +726,21 @@ void nsNPAPIPluginInstance::SetEventMode
return;
}
owner->SetEventModel(aModel);
}
#endif
#if defined(MOZ_WIDGET_ANDROID)
-void nsNPAPIPluginInstance::SetDrawingModel(PRUint32 aModel)
+void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel)
{
- mDrawingModel = aModel;
+ mANPDrawingModel = aModel;
}
+
class SurfaceGetter : public nsRunnable {
public:
SurfaceGetter(nsNPAPIPluginInstance* aInstance, NPPluginFuncs* aPluginFunctions, NPP_t aNPP) :
mInstance(aInstance), mPluginFunctions(aPluginFunctions), mNPP(aNPP) {
}
~SurfaceGetter() {
}
nsresult Run() {
@@ -755,17 +756,17 @@ private:
nsNPAPIPluginInstance* mInstance;
NPP_t mNPP;
NPPluginFuncs* mPluginFunctions;
};
void* nsNPAPIPluginInstance::GetJavaSurface()
{
- if (mDrawingModel != kSurface_ANPDrawingModel)
+ if (mANPDrawingModel != kSurface_ANPDrawingModel)
return nsnull;
return mSurface;
}
void nsNPAPIPluginInstance::SetJavaSurface(void* aSurface)
{
mSurface = aSurface;
@@ -780,17 +781,17 @@ void nsNPAPIPluginInstance::RequestJavaS
((SurfaceGetter*)mSurfaceGetter.get())->RequestSurface();
}
#endif
nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)
{
-#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
+#if defined(XP_MACOSX)
*aModel = (PRInt32)mDrawingModel;
return NS_OK;
#else
return NS_ERROR_FAILURE;
#endif
}
nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -145,17 +145,18 @@ public:
bool UsesDOMForCursor();
#ifdef XP_MACOSX
void SetDrawingModel(NPDrawingModel aModel);
void SetEventModel(NPEventModel aModel);
#endif
#ifdef MOZ_WIDGET_ANDROID
- void SetDrawingModel(PRUint32 aModel);
+ PRUint32 GetANPDrawingModel() { return mANPDrawingModel; }
+ void SetANPDrawingModel(PRUint32 aModel);
void* GetJavaSurface();
void SetJavaSurface(void* aSurface);
void RequestJavaSurface();
#endif
nsresult NewStreamListener(const char* aURL, void* notifyData,
nsIPluginStreamListener** listener);
@@ -224,17 +225,17 @@ protected:
// the browser.
NPP_t mNPP;
#ifdef XP_MACOSX
NPDrawingModel mDrawingModel;
#endif
#ifdef MOZ_WIDGET_ANDROID
- PRUint32 mDrawingModel;
+ PRUint32 mANPDrawingModel;
nsCOMPtr<nsIRunnable> mSurfaceGetter;
#endif
enum {
NOT_STARTED,
RUNNING,
DESTROYING,
DESTROYED
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2863,18 +2863,17 @@ void nsPluginInstanceOwner::Paint(const
void nsPluginInstanceOwner::Paint(gfxContext* aContext,
const gfxRect& aFrameRect,
const gfxRect& aDirtyRect)
{
if (!mInstance || !mObjectFrame)
return;
- PRInt32 model;
- mInstance->GetDrawingModel(&model);
+ PRInt32 model = mInstance->GetANPDrawingModel();
if (model == kSurface_ANPDrawingModel) {
if (!AddPluginView(aFrameRect)) {
NPRect rect;
rect.left = rect.top = 0;
rect.right = aFrameRect.width;
rect.bottom = aFrameRect.height;
InvalidateRect(&rect);
--- a/dom/sms/interfaces/Makefile.in
+++ b/dom/sms/interfaces/Makefile.in
@@ -46,11 +46,15 @@ XPIDL_MODULE = dom_sms
include $(topsrcdir)/dom/dom-config.mk
XPIDLSRCS = \
nsIDOMNavigatorSms.idl \
nsIDOMSmsManager.idl \
nsISmsService.idl \
nsIDOMSmsMessage.idl \
nsIDOMSmsEvent.idl \
+ nsISmsDatabaseService.idl \
+ nsIDOMSmsRequest.idl \
+ nsIDOMSmsFilter.idl \
+ nsIDOMSmsCursor.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsCursor.idl
@@ -0,0 +1,48 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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"
+
+interface nsIDOMMozSmsFilter;
+interface nsIDOMMozSmsMessage;
+
+[scriptable, function, uuid(77b41d7e-ccb1-4480-8322-2af7bc437a3c)]
+interface nsIDOMMozSmsCursor : nsISupports
+{
+ // Can be null if there is no more results.
+ readonly attribute nsIDOMMozSmsMessage message;
+ void continue();
+};
--- a/dom/sms/interfaces/nsIDOMSmsEvent.idl
+++ b/dom/sms/interfaces/nsIDOMSmsEvent.idl
@@ -34,13 +34,14 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#include "nsIDOMEvent.idl"
interface nsIDOMMozSmsMessage;
-[scriptable, uuid(34dda4c3-4683-4323-9ee3-2a7bfef7df3b)]
+[scriptable, uuid(fa8d1c86-85b1-4e5b-978c-12dd296cd1cc)]
interface nsIDOMMozSmsEvent : nsIDOMEvent
{
+ [binaryname(MessageMoz)]
readonly attribute nsIDOMMozSmsMessage message;
};
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsFilter.idl
@@ -0,0 +1,57 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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"
+
+[scriptable, builtinclass, uuid(7da08e45-ee81-4293-912b-2f2fea5b6935)]
+interface nsIDOMMozSmsFilter : nsISupports
+{
+ // A date that can return null.
+ [implicit_jscontext]
+ attribute jsval startDate;
+
+ // A date that can return null.
+ [implicit_jscontext]
+ attribute jsval endDate;
+
+ // An array of DOMString that can return null.
+ [implicit_jscontext]
+ attribute jsval numbers;
+
+ // A DOMString that can return and be set to "sent", "received" or null.
+ [Null(Empty)]
+ attribute DOMString delivery;
+};
--- a/dom/sms/interfaces/nsIDOMSmsManager.idl
+++ b/dom/sms/interfaces/nsIDOMSmsManager.idl
@@ -32,17 +32,33 @@
* 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 "nsIDOMEventTarget.idl"
interface nsIDOMEventListener;
+interface nsIDOMMozSmsRequest;
+interface nsIDOMMozSmsFilter;
-[scriptable, function, uuid(807d593c-09cb-4aa3-afa5-aa0a671bd0d3)]
+[scriptable, function, uuid(c9916dce-2947-41bb-95c2-818f792a020c)]
interface nsIDOMMozSmsManager : nsIDOMEventTarget
{
- unsigned short getNumberOfMessagesForText(in DOMString text);
- void send(in DOMString number, in DOMString message);
+ unsigned short getNumberOfMessagesForText(in DOMString text);
+
+ // The first parameter can be either a DOMString (only one number) or an array
+ // of DOMStrings.
+ // The method returns a SmsRequest object if one number has been passed.
+ // An array of SmsRequest objects otherwise.
+ jsval send(in jsval number, in DOMString message);
+
+ [binaryname(GetMessageMoz)] nsIDOMMozSmsRequest getMessage(in long id);
+
+ // The parameter can be either a message id or a SmsMessage.
+ nsIDOMMozSmsRequest delete(in jsval param);
+
+ nsIDOMMozSmsRequest getMessages(in nsIDOMMozSmsFilter filter, in boolean reverse);
attribute nsIDOMEventListener onreceived;
+ attribute nsIDOMEventListener onsent;
+ attribute nsIDOMEventListener ondelivered;
};
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsRequest.idl
@@ -0,0 +1,53 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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 "nsIDOMEventTarget.idl"
+
+interface nsIDOMEventListener;
+
+[scriptable, function, uuid(1b24469d-cfb7-4667-aaf0-c1d17289ae7c)]
+interface nsIDOMMozSmsRequest : nsIDOMEventTarget
+{
+ // Returns whether "processing" or "done".
+ readonly attribute DOMString readyState;
+ // Can be null.
+ readonly attribute DOMString error;
+ // Can be bool, nsIDOMSmsMessage, nsIDOMSmsIterator or null.
+ readonly attribute jsval result;
+
+ attribute nsIDOMEventListener onsuccess;
+ attribute nsIDOMEventListener onerror;
+};
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsISmsDatabaseService.idl
@@ -0,0 +1,60 @@
+/* ***** 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.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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"
+
+%{C++
+#define SMS_DATABASE_SERVICE_CID \
+{ 0x2454c2a1, 0xefdd, 0x4d96, \
+{ 0x83, 0xbd, 0x51, 0xa2, 0x9a, 0x21, 0xf5, 0xab } }
+#define SMS_DATABASE_SERVICE_CONTRACTID "@mozilla.org/sms/smsdatabaseservice;1"
+%}
+
+interface nsIDOMMozSmsFilter;
+
+[scriptable, function, uuid(3ddf7dc3-626c-47ee-8b41-3f55d5af49c9)]
+interface nsISmsDatabaseService : nsISupports
+{
+ // Takes some information required to save the message and returns its id.
+ long saveSentMessage(in DOMString aReceiver, in DOMString aBody, in unsigned long long aDate);
+
+ [binaryname(GetMessageMoz)] void getMessage(in long messageId, in long requestId, [optional] in unsigned long long processId);
+ void deleteMessage(in long messageId, in long requestId, [optional] in unsigned long long processId);
+
+ void createMessageList(in nsIDOMMozSmsFilter filter, in boolean reverse, in long requestId, [optional] in unsigned long long processId);
+ void getNextMessageInList(in long listId, in long requestId, in unsigned long long processId);
+ void clearMessageList(in long listId);
+};
--- a/dom/sms/interfaces/nsISmsService.idl
+++ b/dom/sms/interfaces/nsISmsService.idl
@@ -35,26 +35,27 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIDOMMozSmsMessage;
%{C++
-#define NS_SMSSERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
-#define SMSSERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
+#define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
+#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
%}
[scriptable, builtinclass, uuid(a0fbbe74-5d61-4b7e-b7ab-9b5224f9e5e9)]
interface nsISmsService : nsISupports
{
boolean hasSupport();
unsigned short getNumberOfMessagesForText(in DOMString text);
- void send(in DOMString number, in DOMString message);
+ void send(in DOMString number, in DOMString message,
+ in long requestId, [optional] in unsigned long long processId);
[implicit_jscontext]
nsIDOMMozSmsMessage createSmsMessage(in long id,
in DOMString delivery,
in DOMString sender,
in DOMString receiver,
in DOMString body,
in jsval timestamp);
--- a/dom/sms/src/Constants.cpp
+++ b/dom/sms/src/Constants.cpp
@@ -34,13 +34,15 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
namespace mozilla {
namespace dom {
namespace sms {
-const char* kSmsReceivedObserverTopic = "sms-received";
+const char* kSmsReceivedObserverTopic = "sms-received";
+const char* kSmsSentObserverTopic = "sms-sent";
+const char* kSmsDeliveredObserverTopic = "sms-delivered";
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/Constants.h
+++ b/dom/sms/src/Constants.h
@@ -37,17 +37,19 @@
#ifndef mozilla_dom_sms_Constants_h
#define mozilla_dom_sms_Constants_h
namespace mozilla {
namespace dom {
namespace sms {
-extern const char* kSmsReceivedObserverTopic; // Defined in the .cpp.
+extern const char* kSmsReceivedObserverTopic; // Defined in the .cpp.
+extern const char* kSmsSentObserverTopic; // Defined in the .cpp.
+extern const char* kSmsDeliveredObserverTopic; // Defined in the .cpp.
#define DELIVERY_RECEIVED NS_LITERAL_STRING("received")
#define DELIVERY_SENT NS_LITERAL_STRING("sent")
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/Makefile.in
+++ b/dom/sms/src/Makefile.in
@@ -58,36 +58,44 @@ FORCE_STATIC_LIB = 1
include $(topsrcdir)/dom/dom-config.mk
EXPORTS_NAMESPACES = mozilla/dom/sms
EXPORTS_mozilla/dom/sms = \
SmsChild.h \
SmsParent.h \
- SmsServiceFactory.h \
+ SmsServicesFactory.h \
Constants.h \
Types.h \
SmsMessage.h \
+ SmsRequestManager.h \
+ SmsRequest.h \
$(NULL)
CPPSRCS = \
SmsManager.cpp \
SmsService.cpp \
SmsIPCService.cpp \
- SmsServiceFactory.cpp \
+ SmsServicesFactory.cpp \
SmsParent.cpp \
SmsMessage.cpp \
SmsEvent.cpp \
Constants.cpp \
SmsChild.cpp \
+ SmsDatabaseService.cpp \
+ SmsRequest.cpp \
+ SmsRequestManager.cpp \
+ SmsFilter.cpp \
+ SmsCursor.cpp \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/content/events/src \
+ -I$(topsrcdir)/dom/base \
$(NULL)
# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
# subdirectory (and the ipc one).
LOCAL_INCLUDES += $(VPATH:%=-I%)
ifdef MOZ_B2G_RIL
LOCAL_INCLUDES += \
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsCursor.cpp
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsCursor.h"
+#include "nsIDOMClassInfo.h"
+#include "nsDOMError.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsRequest.h"
+#include "SmsRequest.h"
+#include "SmsRequestManager.h"
+#include "nsISmsDatabaseService.h"
+
+DOMCI_DATA(MozSmsCursor, mozilla::dom::sms::SmsCursor)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SmsCursor)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsCursor)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsCursor)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_2(SmsCursor, mRequest, mMessage)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(SmsCursor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(SmsCursor)
+
+SmsCursor::SmsCursor()
+ : mListId(-1)
+{
+}
+
+SmsCursor::SmsCursor(PRInt32 aListId, nsIDOMMozSmsRequest* aRequest)
+ : mListId(aListId)
+ , mRequest(aRequest)
+{
+}
+
+SmsCursor::~SmsCursor()
+{
+ NS_ASSERTION(!mMessage, "mMessage shouldn't be set!");
+
+ if (mListId != -1) {
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+
+ if (!smsDBService) {
+ NS_ERROR("Can't find SmsDBService!");
+ }
+
+ smsDBService->ClearMessageList(mListId);
+ }
+}
+
+void
+SmsCursor::Disconnect()
+{
+ NS_ASSERTION(!mMessage, "mMessage shouldn't be set!");
+
+ mRequest = nsnull;
+ mListId = -1;
+}
+
+NS_IMETHODIMP
+SmsCursor::GetMessage(nsIDOMMozSmsMessage** aMessage)
+{
+ NS_IF_ADDREF(*aMessage = mMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsCursor::Continue()
+{
+ // No message means we are waiting for a message or we got the last one.
+ if (!mMessage) {
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ }
+
+ mMessage = nsnull;
+ static_cast<SmsRequest*>(mRequest.get())->Reset();
+
+ PRInt32 requestId = SmsRequestManager::GetInstance()->AddRequest(mRequest);
+
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+ smsDBService->GetNextMessageInList(mListId, requestId, 0);
+
+ return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsCursor.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsCursor_h
+#define mozilla_dom_sms_SmsCursor_h
+
+#include "nsIDOMSmsCursor.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+
+class nsIDOMMozSmsMessage;
+class nsIDOMMozSmsRequest;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsCursor : public nsIDOMMozSmsCursor
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_NSIDOMMOZSMSCURSOR
+
+ NS_DECL_CYCLE_COLLECTION_CLASS(SmsCursor)
+
+ SmsCursor();
+ SmsCursor(PRInt32 aListId, nsIDOMMozSmsRequest* aRequest);
+
+ ~SmsCursor();
+
+ void SetMessage(nsIDOMMozSmsMessage* aMessage);
+
+ void Disconnect();
+
+private:
+ PRInt32 mListId;
+ nsCOMPtr<nsIDOMMozSmsRequest> mRequest;
+ nsCOMPtr<nsIDOMMozSmsMessage> mMessage;
+};
+
+inline void
+SmsCursor::SetMessage(nsIDOMMozSmsMessage* aMessage)
+{
+ mMessage = aMessage;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsCursor_h
--- a/dom/sms/src/SmsEvent.cpp
+++ b/dom/sms/src/SmsEvent.cpp
@@ -72,17 +72,17 @@ SmsEvent::Init(const nsAString& aEventTy
aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mMessage = aMessage;
return NS_OK;
}
NS_IMETHODIMP
-SmsEvent::GetMessage(nsIDOMMozSmsMessage** aMessage)
+SmsEvent::GetMessageMoz(nsIDOMMozSmsMessage** aMessage)
{
NS_IF_ADDREF(*aMessage = mMessage);
return NS_OK;
}
} // namespace sms
} // namespace dom
} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsFilter.cpp
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsFilter.h"
+#include "nsIDOMClassInfo.h"
+#include "Constants.h"
+#include "nsError.h"
+#include "Constants.h"
+#include "jsapi.h"
+#include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch.
+#include "js/Utility.h"
+#include "nsJSUtils.h"
+#include "nsDOMString.h"
+
+DOMCI_DATA(MozSmsFilter, mozilla::dom::sms::SmsFilter)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_INTERFACE_MAP_BEGIN(SmsFilter)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsFilter)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsFilter)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(SmsFilter)
+NS_IMPL_RELEASE(SmsFilter)
+
+SmsFilter::SmsFilter()
+{
+ mData.startDate() = 0;
+ mData.endDate() = 0;
+ mData.delivery() = eDeliveryState_Unknown;
+}
+
+SmsFilter::SmsFilter(const SmsFilterData& aData)
+ : mData(aData)
+{
+}
+
+/* static */ nsresult
+SmsFilter::NewSmsFilter(nsISupports** aSmsFilter)
+{
+ NS_ADDREF(*aSmsFilter = new SmsFilter());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetStartDate(JSContext* aCx, jsval* aStartDate)
+{
+ if (mData.startDate() == 0) {
+ *aStartDate = JSVAL_NULL;
+ return NS_OK;
+ }
+
+ aStartDate->setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.startDate()));
+ NS_ENSURE_TRUE(aStartDate->isObject(), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetStartDate(JSContext* aCx, const jsval& aStartDate)
+{
+ if (aStartDate == JSVAL_NULL) {
+ mData.startDate() = 0;
+ return NS_OK;
+ }
+
+ if (!aStartDate.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JSObject& obj = aStartDate.toObject();
+ if (!JS_ObjectIsDate(aCx, &obj)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ mData.startDate() = js_DateGetMsecSinceEpoch(aCx, &obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetEndDate(JSContext* aCx, jsval* aEndDate)
+{
+ if (mData.endDate() == 0) {
+ *aEndDate = JSVAL_NULL;
+ return NS_OK;
+ }
+
+ aEndDate->setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.endDate()));
+ NS_ENSURE_TRUE(aEndDate->isObject(), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetEndDate(JSContext* aCx, const jsval& aEndDate)
+{
+ if (aEndDate == JSVAL_NULL) {
+ mData.endDate() = 0;
+ return NS_OK;
+ }
+
+ if (!aEndDate.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JSObject& obj = aEndDate.toObject();
+ if (!JS_ObjectIsDate(aCx, &obj)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ mData.endDate() = js_DateGetMsecSinceEpoch(aCx, &obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetNumbers(JSContext* aCx, jsval* aNumbers)
+{
+ PRUint32 length = mData.numbers().Length();
+
+ if (length == 0) {
+ *aNumbers = JSVAL_NULL;
+ return NS_OK;
+ }
+
+ jsval* numbers = new jsval[length];
+
+ for (PRUint32 i=0; i<length; ++i) {
+ numbers[i].setString(JS_NewUCStringCopyN(aCx, mData.numbers()[i].get(),
+ mData.numbers()[i].Length()));
+ }
+
+ aNumbers->setObjectOrNull(JS_NewArrayObject(aCx, length, numbers));
+ NS_ENSURE_TRUE(aNumbers->isObject(), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetNumbers(JSContext* aCx, const jsval& aNumbers)
+{
+ if (aNumbers == JSVAL_NULL) {
+ mData.numbers().Clear();
+ return NS_OK;
+ }
+
+ if (!aNumbers.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JSObject& obj = aNumbers.toObject();
+ if (!JS_IsArrayObject(aCx, &obj)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ jsuint size;
+ JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, &obj, &size));
+
+ nsTArray<nsString> numbers;
+
+ for (jsuint i=0; i<size; ++i) {
+ jsval jsNumber;
+ if (!JS_GetElement(aCx, &obj, i, &jsNumber)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!jsNumber.isString()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsDependentJSString number;
+ number.init(aCx, jsNumber.toString());
+
+ numbers.AppendElement(number);
+ }
+
+ mData.numbers().Clear();
+ mData.numbers().AppendElements(numbers);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetDelivery(nsAString& aDelivery)
+{
+ switch (mData.delivery()) {
+ case eDeliveryState_Received:
+ aDelivery = DELIVERY_RECEIVED;
+ break;
+ case eDeliveryState_Sent:
+ aDelivery = DELIVERY_SENT;
+ break;
+ case eDeliveryState_Unknown:
+ SetDOMStringToNull(aDelivery);
+ break;
+ default:
+ NS_ASSERTION(false, "We shouldn't get another delivery state!");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetDelivery(const nsAString& aDelivery)
+{
+ if (aDelivery.IsEmpty()) {
+ mData.delivery() = eDeliveryState_Unknown;
+ return NS_OK;
+ }
+
+ if (aDelivery.Equals(DELIVERY_RECEIVED)) {
+ mData.delivery() = eDeliveryState_Received;
+ return NS_OK;
+ }
+
+ if (aDelivery.Equals(DELIVERY_SENT)) {
+ mData.delivery() = eDeliveryState_Sent;
+ return NS_OK;
+ }
+
+ return NS_ERROR_INVALID_ARG;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsFilter.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsFilter_h
+#define mozilla_dom_sms_SmsFilter_h
+
+#include "mozilla/dom/sms/PSms.h"
+#include "nsIDOMSmsFilter.h"
+#include "Types.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsFilter : public nsIDOMMozSmsFilter
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDOMMOZSMSFILTER
+
+ SmsFilter();
+ SmsFilter(const SmsFilterData& aData);
+
+ const SmsFilterData& GetData() const;
+
+ static nsresult NewSmsFilter(nsISupports** aSmsFilter);
+
+private:
+ SmsFilterData mData;
+};
+
+inline const SmsFilterData&
+SmsFilter::GetData() const {
+ return mData;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsFilter_h
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -30,47 +30,60 @@
* 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 "SmsFilter.h"
#include "SmsManager.h"
#include "nsIDOMClassInfo.h"
#include "nsISmsService.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "Constants.h"
#include "SmsEvent.h"
#include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsRequest.h"
+#include "SmsRequestManager.h"
+#include "nsJSUtils.h"
+#include "nsContentUtils.h"
+#include "nsISmsDatabaseService.h"
+#include "nsIXPConnect.h"
/**
* We have to use macros here because our leak analysis tool things we are
* leaking strings when we have |static const nsString|. Sad :(
*/
-#define RECEIVED_EVENT_NAME NS_LITERAL_STRING("received")
+#define RECEIVED_EVENT_NAME NS_LITERAL_STRING("received")
+#define SENT_EVENT_NAME NS_LITERAL_STRING("sent")
+#define DELIVERED_EVENT_NAME NS_LITERAL_STRING("delivered")
DOMCI_DATA(MozSmsManager, mozilla::dom::sms::SmsManager)
namespace mozilla {
namespace dom {
namespace sms {
NS_IMPL_CYCLE_COLLECTION_CLASS(SmsManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SmsManager,
nsDOMEventTargetWrapperCache)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(received)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(sent)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(delivered)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SmsManager,
nsDOMEventTargetWrapperCache)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(received)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(sent)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(delivered)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SmsManager)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsManager)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozSmsManager)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsManager)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
@@ -86,53 +99,205 @@ SmsManager::Init(nsPIDOMWindow *aWindow,
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
// GetObserverService() can return null is some situations like shutdown.
if (!obs) {
return;
}
obs->AddObserver(this, kSmsReceivedObserverTopic, false);
+ obs->AddObserver(this, kSmsSentObserverTopic, false);
+ obs->AddObserver(this, kSmsDeliveredObserverTopic, false);
}
void
SmsManager::Shutdown()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
// GetObserverService() can return null is some situations like shutdown.
if (!obs) {
return;
}
obs->RemoveObserver(this, kSmsReceivedObserverTopic);
+ obs->RemoveObserver(this, kSmsSentObserverTopic);
+ obs->RemoveObserver(this, kSmsDeliveredObserverTopic);
}
NS_IMETHODIMP
SmsManager::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
{
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, NS_OK);
smsService->GetNumberOfMessagesForText(aText, aResult);
return NS_OK;
}
+nsresult
+SmsManager::Send(JSContext* aCx, JSObject* aGlobal, JSString* aNumber,
+ const nsAString& aMessage, jsval* aRequest)
+{
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+ if (!smsService) {
+ NS_ERROR("No SMS Service!");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsRequest> request;
+
+ int requestId =
+ SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext,
+ getter_AddRefs(request));
+ NS_ASSERTION(request, "The request object must have been created!");
+
+ nsDependentJSString number;
+ number.init(aCx, aNumber);
+
+ smsService->Send(number, aMessage, requestId, 0);
+
+ nsresult rv = nsContentUtils::WrapNative(aCx, aGlobal, request, aRequest);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to create the js value!");
+ return rv;
+ }
+
+ return NS_OK;
+}
+
NS_IMETHODIMP
-SmsManager::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsManager::Send(const jsval& aNumber, const nsAString& aMessage, jsval* aReturn)
{
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
- NS_ENSURE_TRUE(smsService, NS_OK);
+ JSContext* cx = mScriptContext->GetNativeContext();
+ NS_ASSERTION(cx, "Failed to get a context!");
+
+ if (!aNumber.isString() &&
+ !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JSObject* global = mScriptContext->GetNativeGlobal();
+ NS_ASSERTION(global, "Failed to get global object!");
+
+ JSAutoRequest ar(cx);
+ JSAutoEnterCompartment ac;
+ if (!ac.enter(cx, global)) {
+ NS_ERROR("Failed to enter the js compartment!");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (aNumber.isString()) {
+ return Send(cx, global, aNumber.toString(), aMessage, aReturn);
+ }
+
+ // Must be an array then.
+ JSObject& numbers = aNumber.toObject();
+
+ jsuint size;
+ JS_ALWAYS_TRUE(JS_GetArrayLength(cx, &numbers, &size));
+
+ jsval* requests = new jsval[size];
+
+ for (jsuint i=0; i<size; ++i) {
+ jsval number;
+ if (!JS_GetElement(cx, &numbers, i, &number)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsresult rv = Send(cx, global, number.toString(), aMessage, &requests[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ aReturn->setObjectOrNull(JS_NewArrayObject(cx, size, requests));
+ NS_ENSURE_TRUE(aReturn->isObject(), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsManager::GetMessageMoz(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
+{
+ int requestId =
+ SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+ NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+ smsDBService->GetMessageMoz(aId, requestId, 0);
- smsService->Send(aNumber, aMessage);
+ return NS_OK;
+}
+
+nsresult
+SmsManager::Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
+{
+ int requestId =
+ SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+ NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+ smsDBService->DeleteMessage(aId, requestId, 0);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsManager::Delete(const jsval& aParam, nsIDOMMozSmsRequest** aRequest)
+{
+ if (aParam.isInt32()) {
+ return Delete(aParam.toInt32(), aRequest);
+ }
+
+ if (!aParam.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsMessage> message =
+ do_QueryInterface(nsContentUtils::XPConnect()->GetNativeOfWrapper(
+ mScriptContext->GetNativeContext(), &aParam.toObject()));
+ NS_ENSURE_TRUE(message, NS_ERROR_INVALID_ARG);
+
+ PRInt32 id;
+ message->GetId(&id);
+
+ return Delete(id, aRequest);
+}
+
+NS_IMETHODIMP
+SmsManager::GetMessages(nsIDOMMozSmsFilter* aFilter, bool aReverse,
+ nsIDOMMozSmsRequest** aRequest)
+{
+ nsCOMPtr<nsIDOMMozSmsFilter> filter = aFilter;
+
+ if (!filter) {
+ filter = new SmsFilter();
+ }
+
+ int requestId =
+ SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+ NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+ smsDBService->CreateMessageList(filter, aReverse, requestId, 0);
return NS_OK;
}
NS_IMPL_EVENT_HANDLER(SmsManager, received)
+NS_IMPL_EVENT_HANDLER(SmsManager, sent)
+NS_IMPL_EVENT_HANDLER(SmsManager, delivered)
nsresult
SmsManager::DispatchTrustedSmsEventToSelf(const nsAString& aEventName, nsIDOMMozSmsMessage* aMessage)
{
nsRefPtr<nsDOMEvent> event = new SmsEvent(nsnull, nsnull);
nsresult rv = static_cast<SmsEvent*>(event.get())->Init(aEventName, false,
false, aMessage);
NS_ENSURE_SUCCESS(rv, rv);
@@ -154,16 +319,39 @@ SmsManager::Observe(nsISupports* aSubjec
if (!strcmp(aTopic, kSmsReceivedObserverTopic)) {
nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
if (!message) {
NS_ERROR("Got a 'sms-received' topic without a valid message!");
return NS_OK;
}
DispatchTrustedSmsEventToSelf(RECEIVED_EVENT_NAME, message);
+ return NS_OK;
+ }
+
+ if (!strcmp(aTopic, kSmsSentObserverTopic)) {
+ nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+ if (!message) {
+ NS_ERROR("Got a 'sms-sent' topic without a valid message!");
+ return NS_OK;
+ }
+
+ DispatchTrustedSmsEventToSelf(SENT_EVENT_NAME, message);
+ return NS_OK;
+ }
+
+ if (!strcmp(aTopic, kSmsDeliveredObserverTopic)) {
+ nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+ if (!message) {
+ NS_ERROR("Got a 'sms-delivered' topic without a valid message!");
+ return NS_OK;
+ }
+
+ DispatchTrustedSmsEventToSelf(DELIVERED_EVENT_NAME, message);
+ return NS_OK;
}
return NS_OK;
}
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/SmsManager.h
+++ b/dom/sms/src/SmsManager.h
@@ -61,18 +61,31 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SmsManager,
nsDOMEventTargetWrapperCache)
void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
void Shutdown();
private:
+ /**
+ * Internal Send() method used to send one message.
+ */
+ nsresult Send(JSContext* aCx, JSObject* aGlobal, JSString* aNumber,
+ const nsAString& aMessage, jsval* aRequest);
+
+ /**
+ * Internal Delete() method used to delete a message.
+ */
+ nsresult Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest);
+
nsresult DispatchTrustedSmsEventToSelf(const nsAString& aEventName,
nsIDOMMozSmsMessage* aMessage);
NS_DECL_EVENT_HANDLER(received)
+ NS_DECL_EVENT_HANDLER(sent)
+ NS_DECL_EVENT_HANDLER(delivered)
};
} // namespace sms
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_sms_SmsManager_h
--- a/dom/sms/src/SmsMessage.cpp
+++ b/dom/sms/src/SmsMessage.cpp
@@ -52,16 +52,23 @@ NS_INTERFACE_MAP_BEGIN(SmsMessage)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsMessage)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsMessage)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(SmsMessage)
NS_IMPL_RELEASE(SmsMessage)
+SmsMessage::SmsMessage(PRInt32 aId, DeliveryState aDelivery,
+ const nsString& aSender, const nsString& aReceiver,
+ const nsString& aBody, PRUint64 aTimestamp)
+ : mData(aId, aDelivery, aSender, aReceiver, aBody, aTimestamp)
+{
+}
+
SmsMessage::SmsMessage(const SmsMessageData& aData)
: mData(aData)
{
}
/* static */ nsresult
SmsMessage::Create(PRInt32 aId,
const nsAString& aDelivery,
@@ -126,24 +133,25 @@ SmsMessage::GetId(PRInt32* aId)
return NS_OK;
}
NS_IMETHODIMP
SmsMessage::GetDelivery(nsAString& aDelivery)
{
switch (mData.delivery()) {
case eDeliveryState_Received:
- aDelivery.AssignLiteral("received");
+ aDelivery = DELIVERY_RECEIVED;
break;
case eDeliveryState_Sent:
- aDelivery.AssignLiteral("sent");
+ aDelivery = DELIVERY_SENT;
break;
case eDeliveryState_Unknown:
+ case eDeliveryState_EndGuard:
default:
- NS_ASSERTION(true, "We shouldn't get an unknown delivery state!");
+ NS_ASSERTION(true, "We shouldn't get any other delivery state!");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
NS_IMETHODIMP
SmsMessage::GetSender(nsAString& aSender)
--- a/dom/sms/src/SmsMessage.h
+++ b/dom/sms/src/SmsMessage.h
@@ -37,27 +37,31 @@
#ifndef mozilla_dom_sms_SmsMessage_h
#define mozilla_dom_sms_SmsMessage_h
#include "mozilla/dom/sms/PSms.h"
#include "nsIDOMSmsMessage.h"
#include "nsString.h"
#include "jspubtd.h"
+#include "Types.h"
namespace mozilla {
namespace dom {
namespace sms {
class SmsMessage : public nsIDOMMozSmsMessage
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZSMSMESSAGE
+ SmsMessage(PRInt32 aId, DeliveryState aDelivery, const nsString& aSender,
+ const nsString& aReceiver, const nsString& aBody,
+ PRUint64 aTimestamp);
SmsMessage(const SmsMessageData& aData);
static nsresult Create(PRInt32 aId,
const nsAString& aDelivery,
const nsAString& aSender,
const nsAString& aReceiver,
const nsAString& aBody,
const JS::Value& aTimestamp,
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequest.cpp
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsRequest.h"
+#include "nsIDOMClassInfo.h"
+#include "nsDOMString.h"
+#include "nsContentUtils.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsCursor.h"
+
+DOMCI_DATA(MozSmsRequest, mozilla::dom::sms::SmsRequest)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(SmsRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SmsRequest,
+ nsDOMEventTargetWrapperCache)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCursor)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SmsRequest,
+ nsDOMEventTargetWrapperCache)
+ if (tmp->mResultRooted) {
+ tmp->mResult = JSVAL_VOID;
+ tmp->UnrootResult();
+ }
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(SmsRequest,
+ nsDOMEventTargetWrapperCache)
+ if (JSVAL_IS_GCTHING(tmp->mResult)) {
+ void *gcThing = JSVAL_TO_GCTHING(tmp->mResult);
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResult")
+ }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SmsRequest)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsRequest)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozSmsRequest)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsRequest)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(SmsRequest, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(SmsRequest, nsDOMEventTargetWrapperCache)
+
+NS_IMPL_EVENT_HANDLER(SmsRequest, success)
+NS_IMPL_EVENT_HANDLER(SmsRequest, error)
+
+SmsRequest::SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext)
+ : mResult(JSVAL_VOID)
+ , mResultRooted(false)
+ , mError(eNoError)
+ , mDone(false)
+{
+ // Those vars come from nsDOMEventTargetHelper.
+ mOwner = aWindow;
+ mScriptContext = aScriptContext;
+}
+
+SmsRequest::~SmsRequest()
+{
+ if (mResultRooted) {
+ UnrootResult();
+ }
+}
+
+void
+SmsRequest::Reset()
+{
+ NS_ASSERTION(mDone, "mDone should be true if we try to reset!");
+ NS_ASSERTION(mResult != JSVAL_VOID, "mResult should be set if we try to reset!");
+ NS_ASSERTION(mError == eNoError, "There should be no error if we try to reset!");
+
+ if (mResultRooted) {
+ UnrootResult();
+ }
+
+ mResult = JSVAL_VOID;
+ mDone = false;
+}
+
+void
+SmsRequest::RootResult()
+{
+ NS_ASSERTION(!mResultRooted, "Don't call RootResult() if already rooted!");
+ NS_HOLD_JS_OBJECTS(this, SmsRequest);
+ mResultRooted = true;
+}
+
+void
+SmsRequest::UnrootResult()
+{
+ NS_ASSERTION(mResultRooted, "Don't call UnrotResult() if not rooted!");
+ NS_DROP_JS_OBJECTS(this, SmsRequest);
+ mResultRooted = false;
+}
+
+void
+SmsRequest::SetSuccess(nsIDOMMozSmsMessage* aMessage)
+{
+ SetSuccessInternal(aMessage);
+}
+
+void
+SmsRequest::SetSuccess(bool aResult)
+{
+ NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+ NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+ NS_PRECONDITION(mResult == JSVAL_NULL, "mResult shouldn't have been set!");
+
+ mResult.setBoolean(aResult);
+ mDone = true;
+}
+
+void
+SmsRequest::SetSuccess(nsIDOMMozSmsCursor* aCursor)
+{
+ if (!SetSuccessInternal(aCursor)) {
+ return;
+ }
+
+ NS_ASSERTION(!mCursor || mCursor == aCursor,
+ "SmsRequest can't change it's cursor!");
+
+ if (!mCursor) {
+ mCursor = aCursor;
+ }
+}
+
+bool
+SmsRequest::SetSuccessInternal(nsISupports* aObject)
+{
+ NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+ NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+ NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
+
+ JSContext* cx = mScriptContext->GetNativeContext();
+ NS_ASSERTION(cx, "Failed to get a context!");
+
+ JSObject* global = mScriptContext->GetNativeGlobal();
+ NS_ASSERTION(global, "Failed to get global object!");
+
+ JSAutoRequest ar(cx);
+ JSAutoEnterCompartment ac;
+ if (!ac.enter(cx, global)) {
+ SetError(eInternalError);
+ return false;
+ }
+
+ RootResult();
+
+ if (NS_FAILED(nsContentUtils::WrapNative(cx, global, aObject, &mResult))) {
+ UnrootResult();
+ mResult = JSVAL_VOID;
+ SetError(eInternalError);
+ return false;
+ }
+
+ mDone = true;
+ return true;
+}
+
+void
+SmsRequest::SetError(ErrorType aError)
+{
+ NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+ NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+ NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
+
+ mDone = true;
+ mError = aError;
+ mCursor = nsnull;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetReadyState(nsAString& aReadyState)
+{
+ if (mDone) {
+ aReadyState.AssignLiteral("done");
+ } else {
+ aReadyState.AssignLiteral("processing");
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetError(nsAString& aError)
+{
+ if (!mDone) {
+ NS_ASSERTION(mError == eNoError,
+ "There should be no error if the request is still processing!");
+
+ SetDOMStringToNull(aError);
+ return NS_OK;
+ }
+
+ NS_ASSERTION(mError == eNoError || mResult == JSVAL_VOID,
+ "mResult should be void when there is an error!");
+
+ switch (mError) {
+ case eNoError:
+ SetDOMStringToNull(aError);
+ break;
+ case eNoSignalError:
+ aError.AssignLiteral("NoSignalError");
+ break;
+ case eNotFoundError:
+ aError.AssignLiteral("NotFoundError");
+ break;
+ case eUnknownError:
+ aError.AssignLiteral("UnknownError");
+ break;
+ case eInternalError:
+ aError.AssignLiteral("InternalError");
+ break;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetResult(jsval* aResult)
+{
+ if (!mDone) {
+ NS_ASSERTION(mResult == JSVAL_VOID,
+ "When not done, result should be null!");
+
+ *aResult = JSVAL_VOID;
+ return NS_OK;
+ }
+
+ *aResult = mResult;
+ return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequest.h
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsRequest_h
+#define mozilla_dom_sms_SmsRequest_h
+
+#include "nsIDOMSmsRequest.h"
+#include "nsDOMEventTargetWrapperCache.h"
+
+class nsIDOMMozSmsMessage;
+class nsIDOMMozSmsCursor;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsRequest : public nsIDOMMozSmsRequest
+ , public nsDOMEventTargetWrapperCache
+{
+public:
+ friend class SmsRequestManager;
+
+ /**
+ * All SMS related errors that could apply to SmsRequest objects.
+ * Make sure to keep this list in sync with the list in:
+ * embedding/android/GeckoSmsManager.java
+ */
+ enum ErrorType {
+ eNoError = 0,
+ eNoSignalError,
+ eNotFoundError,
+ eUnknownError,
+ eInternalError,
+ };
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDOMMOZSMSREQUEST
+
+ NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
+
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(SmsRequest,
+ nsDOMEventTargetWrapperCache)
+
+ void Reset();
+
+private:
+ SmsRequest() MOZ_DELETE;
+
+ SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext);
+ ~SmsRequest();
+
+ /**
+ * Root mResult (jsval) to prevent garbage collection.
+ */
+ void RootResult();
+
+ /**
+ * Unroot mResult (jsval) to allow garbage collection.
+ */
+ void UnrootResult();
+
+ /**
+ * Set the object in a success state with the result being aMessage.
+ */
+ void SetSuccess(nsIDOMMozSmsMessage* aMessage);
+
+ /**
+ * Set the object in a success state with the result being a boolean.
+ */
+ void SetSuccess(bool aResult);
+
+ /**
+ * Set the object in a success state with the result being a SmsCursor.
+ */
+ void SetSuccess(nsIDOMMozSmsCursor* aCursor);
+
+ /**
+ * Set the object in an error state with the error type being aError.
+ */
+ void SetError(ErrorType aError);
+
+ /**
+ * Set the object in a success state with the result being the nsISupports
+ * object in parameter.
+ * @return whether setting the object was a success
+ */
+ bool SetSuccessInternal(nsISupports* aObject);
+
+ /**
+ * Return the internal cursor that is saved when
+ * SetSuccess(nsIDOMMozSmsCursor*) is used.
+ * Returns null if this request isn't associated to an cursor.
+ */
+ nsIDOMMozSmsCursor* GetCursor();
+
+ jsval mResult;
+ bool mResultRooted;
+ ErrorType mError;
+ bool mDone;
+ nsCOMPtr<nsIDOMMozSmsCursor> mCursor;
+
+ NS_DECL_EVENT_HANDLER(success)
+ NS_DECL_EVENT_HANDLER(error)
+};
+
+inline nsIDOMMozSmsCursor*
+SmsRequest::GetCursor()
+{
+ return mCursor;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsRequest_h
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequestManager.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsRequestManager.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsDOMEvent.h"
+#include "SmsCursor.h"
+
+/**
+ * We have to use macros here because our leak analysis tool things we are
+ * leaking strings when we have |static const nsString|. Sad :(
+ */
+#define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success")
+#define ERROR_EVENT_NAME NS_LITERAL_STRING("error")
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+SmsRequestManager* SmsRequestManager::sInstance = nsnull;
+
+void
+SmsRequestManager::Init()
+{
+ NS_PRECONDITION(!sInstance,
+ "sInstance shouldn't be set. Did you call Init() twice?");
+ sInstance = new SmsRequestManager();
+}
+
+void
+SmsRequestManager::Shutdown()
+{
+ NS_PRECONDITION(sInstance, "sInstance should be set. Did you call Init()?");
+
+ delete sInstance;
+ sInstance = nsnull;
+}
+
+/* static */ SmsRequestManager*
+SmsRequestManager::GetInstance()
+{
+ return sInstance;
+}
+
+PRInt32
+SmsRequestManager::AddRequest(nsIDOMMozSmsRequest* aRequest)
+{
+ // TODO: merge with CreateRequest
+ PRInt32 size = mRequests.Count();
+
+ // Look for empty slots.
+ for (PRInt32 i=0; i<size; ++i) {
+ if (mRequests[i]) {
+ continue;
+ }
+
+ mRequests.ReplaceObjectAt(aRequest, i);
+ return i;
+ }
+
+ mRequests.AppendObject(aRequest);
+ return size;
+}
+
+PRInt32
+SmsRequestManager::CreateRequest(nsPIDOMWindow* aWindow,
+ nsIScriptContext* aScriptContext,
+ nsIDOMMozSmsRequest** aRequest)
+{
+ nsCOMPtr<nsIDOMMozSmsRequest> request =
+ new SmsRequest(aWindow, aScriptContext);
+
+ PRInt32 size = mRequests.Count();
+
+ // Look for empty slots.
+ for (PRInt32 i=0; i<size; ++i) {
+ if (mRequests[i]) {
+ continue;
+ }
+
+ mRequests.ReplaceObjectAt(request, i);
+ NS_ADDREF(*aRequest = request);
+ return i;
+ }
+
+ mRequests.AppendObject(request);
+ NS_ADDREF(*aRequest = request);
+ return size;
+}
+
+nsresult
+SmsRequestManager::DispatchTrustedEventToRequest(const nsAString& aEventName,
+ nsIDOMMozSmsRequest* aRequest)
+{
+ nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+ nsresult rv = event->InitEvent(aEventName, false, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = event->SetTrusted(PR_TRUE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool dummy;
+ return aRequest->DispatchEvent(event, &dummy);
+}
+
+SmsRequest*
+SmsRequestManager::GetRequest(PRInt32 aRequestId)
+{
+ NS_ASSERTION(mRequests.Count() > aRequestId && mRequests[aRequestId],
+ "Got an invalid request id or it has been already deleted!");
+
+ // It's safe to use the static_cast here given that we did call
+ // |new SmsRequest()|.
+ return static_cast<SmsRequest*>(mRequests[aRequestId]);
+}
+
+template <class T>
+void
+SmsRequestManager::NotifySuccess(PRInt32 aRequestId, T aParam)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+ request->SetSuccess(aParam);
+
+ DispatchTrustedEventToRequest(SUCCESS_EVENT_NAME, request);
+
+ mRequests.ReplaceObjectAt(nsnull, aRequestId);
+}
+
+void
+SmsRequestManager::NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+ request->SetError(aError);
+
+ DispatchTrustedEventToRequest(ERROR_EVENT_NAME, request);
+
+ mRequests.ReplaceObjectAt(nsnull, aRequestId);
+}
+
+void
+SmsRequestManager::NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+ NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+}
+
+void
+SmsRequestManager::NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+ NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+ NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+}
+
+void
+SmsRequestManager::NotifyGetSmsFailed(PRInt32 aRequestId,
+ SmsRequest::ErrorType aError)
+{
+ NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted)
+{
+ NotifySuccess<bool>(aRequestId, aDeleted);
+}
+
+void
+SmsRequestManager::NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+ NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifyNoMessageInList(PRInt32 aRequestId)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+
+ nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
+ if (!cursor) {
+ cursor = new SmsCursor();
+ } else {
+ static_cast<SmsCursor*>(cursor.get())->Disconnect();
+ }
+
+ NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId,
+ nsIDOMMozSmsMessage* aMessage)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+
+ nsCOMPtr<SmsCursor> cursor = new SmsCursor(aListId, request);
+ cursor->SetMessage(aMessage);
+
+ NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+
+ nsCOMPtr<SmsCursor> cursor = static_cast<SmsCursor*>(request->GetCursor());
+ NS_ASSERTION(cursor, "Request should have an cursor in that case!");
+ cursor->SetMessage(aMessage);
+
+ NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyReadMessageListFailed(PRInt32 aRequestId,
+ SmsRequest::ErrorType aError)
+{
+ SmsRequest* request = GetRequest(aRequestId);
+
+ nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
+ if (cursor) {
+ static_cast<SmsCursor*>(cursor.get())->Disconnect();
+ }
+
+ NotifyError(aRequestId, aError);
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequestManager.h
@@ -0,0 +1,96 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsRequestManager_h
+#define mozilla_dom_sms_SmsRequestManager_h
+
+#include "nsCOMArray.h"
+#include "SmsRequest.h"
+
+class nsIDOMMozSmsRequest;
+class nsPIDOMWindow;
+class nsIScriptContext;
+class nsIDOMMozSmsMessage;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsRequestManager
+{
+public:
+ static void Init();
+ static void Shutdown();
+ static SmsRequestManager* GetInstance();
+
+ PRInt32 CreateRequest(nsPIDOMWindow* aWindow,
+ nsIScriptContext* aScriptContext,
+ nsIDOMMozSmsRequest** aRequest);
+
+ PRInt32 AddRequest(nsIDOMMozSmsRequest* aRequest);
+
+ void NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+ void NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+ void NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+ void NotifyGetSmsFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+ void NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted);
+ void NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+ void NotifyNoMessageInList(PRInt32 aRequestId);
+ void NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId, nsIDOMMozSmsMessage* aMessage);
+ void NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+ void NotifyReadMessageListFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+
+private:
+ static SmsRequestManager* sInstance;
+
+ nsresult DispatchTrustedEventToRequest(const nsAString& aEventName,
+ nsIDOMMozSmsRequest* aRequest);
+ SmsRequest* GetRequest(PRInt32 aRequestId);
+
+ template <class T>
+ void NotifySuccess(PRInt32 aRequestId, T aParam);
+ void NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+
+ nsCOMArray<nsIDOMMozSmsRequest> mRequests;
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsRequestManager_h
rename from dom/sms/src/SmsServiceFactory.cpp
rename to dom/sms/src/SmsServicesFactory.cpp
--- a/dom/sms/src/SmsServiceFactory.cpp
+++ b/dom/sms/src/SmsServicesFactory.cpp
@@ -30,34 +30,49 @@
* 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 "SmsServiceFactory.h"
+#include "SmsServicesFactory.h"
#include "nsXULAppAPI.h"
#include "SmsService.h"
+#include "SmsDatabaseService.h"
#include "SmsIPCService.h"
namespace mozilla {
namespace dom {
namespace sms {
/* static */ already_AddRefed<nsISmsService>
-SmsServiceFactory::Create()
+SmsServicesFactory::CreateSmsService()
{
nsCOMPtr<nsISmsService> smsService;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
smsService = new SmsIPCService();
} else {
smsService = new SmsService();
}
return smsService.forget();
}
+/* static */ already_AddRefed<nsISmsDatabaseService>
+SmsServicesFactory::CreateSmsDatabaseService()
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService;
+
+ if (XRE_GetProcessType() == GeckoProcessType_Content) {
+ smsDBService = new SmsIPCService();
+ } else {
+ smsDBService = new SmsDatabaseService();
+ }
+
+ return smsDBService.forget();
+}
+
} // namespace sms
} // namespace dom
} // namespace mozilla
rename from dom/sms/src/SmsServiceFactory.h
rename to dom/sms/src/SmsServicesFactory.h
--- a/dom/sms/src/SmsServiceFactory.h
+++ b/dom/sms/src/SmsServicesFactory.h
@@ -30,30 +30,32 @@
* 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 ***** */
-#ifndef mozilla_dom_sms_SmsServiceFactory_h
-#define mozilla_dom_sms_SmsServiceFactory_h
+#ifndef mozilla_dom_sms_SmsServicesFactory_h
+#define mozilla_dom_sms_SmsServicesFactory_h
#include "nsCOMPtr.h"
class nsISmsService;
+class nsISmsDatabaseService;
namespace mozilla {
namespace dom {
namespace sms {
-class SmsServiceFactory
+class SmsServicesFactory
{
public:
- static already_AddRefed<nsISmsService> Create();
+ static already_AddRefed<nsISmsService> CreateSmsService();
+ static already_AddRefed<nsISmsDatabaseService> CreateSmsDatabaseService();
};
} // namespace sms
} // namespace dom
} // namespace mozilla
-#endif // mozilla_dom_sms_SmsServiceFactory_h
+#endif // mozilla_dom_sms_SmsServicesFactory_h
--- a/dom/sms/src/Types.h
+++ b/dom/sms/src/Types.h
@@ -33,39 +33,44 @@
* 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 ***** */
#ifndef mozilla_dom_sms_Types_h
#define mozilla_dom_sms_Types_h
+#include "IPCMessageUtils.h"
+
namespace mozilla {
namespace dom {
namespace sms {
// For SmsMessageDate.delivery.
+// Please keep the following files in sync with enum below:
+// embedding/android/GeckoSmsManager.java
enum DeliveryState {
- eDeliveryState_Sent,
+ eDeliveryState_Sent = 0,
eDeliveryState_Received,
+ eDeliveryState_Unknown,
// This state should stay at the end.
- eDeliveryState_Unknown
+ eDeliveryState_EndGuard
};
} // namespace sms
} // namespace dom
} // namespace mozilla
namespace IPC {
/**
* Delivery state serializer.
*/
template <>
struct ParamTraits<mozilla::dom::sms::DeliveryState>
: public EnumSerializer<mozilla::dom::sms::DeliveryState,
mozilla::dom::sms::eDeliveryState_Sent,
- mozilla::dom::sms::eDeliveryState_Unknown>
+ mozilla::dom::sms::eDeliveryState_EndGuard>
{};
} // namespace IPC
#endif // mozilla_dom_sms_Types_h
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/android/SmsDatabaseService.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsFilter.h"
+#include "SmsDatabaseService.h"
+#include "AndroidBridge.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_ISUPPORTS1(SmsDatabaseService, nsISmsDatabaseService)
+
+NS_IMETHODIMP
+SmsDatabaseService::SaveSentMessage(const nsAString& aReceiver,
+ const nsAString& aBody,
+ PRUint64 aDate, PRInt32* aId)
+{
+ *aId = -1;
+
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ *aId = AndroidBridge::Bridge()->SaveSentMessage(aReceiver, aBody, aDate);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ AndroidBridge::Bridge()->GetMessage(aMessageId, aRequestId, aProcessId);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ AndroidBridge::Bridge()->DeleteMessage(aMessageId, aRequestId, aProcessId);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
+ bool aReverse, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ AndroidBridge::Bridge()->CreateMessageList(
+ static_cast<SmsFilter*>(aFilter)->GetData(), aReverse, aRequestId, aProcessId
+ );
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ AndroidBridge::Bridge()->GetNextMessageInList(aListId, aRequestId, aProcessId);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::ClearMessageList(PRInt32 aListId)
+{
+ if (!AndroidBridge::Bridge()) {
+ return NS_OK;
+ }
+
+ AndroidBridge::Bridge()->ClearMessageList(aListId);
+ return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/android/SmsDatabaseService.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsDatabaseService_h
+#define mozilla_dom_sms_SmsDatabaseService_h
+
+#include "nsISmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsDatabaseService : public nsISmsDatabaseService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISMSDATABASESERVICE
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsDatabaseService_h
--- a/dom/sms/src/android/SmsService.cpp
+++ b/dom/sms/src/android/SmsService.cpp
@@ -62,23 +62,25 @@ SmsService::GetNumberOfMessagesForText(c
return NS_OK;
}
*aResult = AndroidBridge::Bridge()->GetNumberOfMessagesForText(aText);
return NS_OK;
}
NS_IMETHODIMP
-SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsService::Send(const nsAString& aNumber, const nsAString& aMessage,
+ PRInt32 aRequestId, PRUint64 aProcessId)
{
if (!AndroidBridge::Bridge()) {
return NS_OK;
}
- AndroidBridge::Bridge()->SendMessage(aNumber, aMessage);
+ AndroidBridge::Bridge()->SendMessage(aNumber, aMessage, aRequestId,
+ aProcessId);
return NS_OK;
}
NS_IMETHODIMP
SmsService::CreateSmsMessage(PRInt32 aId,
const nsAString& aDelivery,
const nsAString& aSender,
const nsAString& aReceiver,
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/fallback/SmsDatabaseService.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "SmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_ISUPPORTS1(SmsDatabaseService, nsISmsDatabaseService)
+
+NS_IMETHODIMP
+SmsDatabaseService::SaveSentMessage(const nsAString& aReceiver,
+ const nsAString& aBody,
+ PRUint64 aDate, PRInt32* aId)
+{
+ *aId = -1;
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
+ bool aReverse, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::ClearMessageList(PRInt32 aListId)
+{
+ NS_ERROR("We should not be here!");
+ return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/fallback/SmsDatabaseService.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef mozilla_dom_sms_SmsDatabaseService_h
+#define mozilla_dom_sms_SmsDatabaseService_h
+
+#include "nsISmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsDatabaseService : public nsISmsDatabaseService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISMSDATABASESERVICE
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsDatabaseService_h
--- a/dom/sms/src/fallback/SmsService.cpp
+++ b/dom/sms/src/fallback/SmsService.cpp
@@ -57,17 +57,18 @@ NS_IMETHODIMP
SmsService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
{
NS_ERROR("We should not be here!");
*aResult = 0;
return NS_OK;
}
NS_IMETHODIMP
-SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsService::Send(const nsAString& aNumber, const nsAString& aMessage,
+ PRInt32 aRequestId, PRUint64 aProcessId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsService::CreateSmsMessage(PRInt32 aId,
const nsAString& aDelivery,
--- a/dom/sms/src/ipc/PSms.ipdl
+++ b/dom/sms/src/ipc/PSms.ipdl
@@ -50,29 +50,81 @@ struct SmsMessageData {
PRInt32 id;
DeliveryState delivery;
nsString sender;
nsString receiver;
nsString body;
PRUint64 timestamp; // ms since epoch.
};
+struct SmsFilterData {
+ PRUint64 startDate;
+ PRUint64 endDate;
+ nsString[] numbers;
+ DeliveryState delivery;
+};
+
sync protocol PSms {
manager PContent;
child:
NotifyReceivedMessage(SmsMessageData aMessageData);
+ NotifySentMessage(SmsMessageData aMessageData);
+
+ NotifyDeliveredMessage(SmsMessageData aMessageData);
+
+ NotifyRequestSmsSent(SmsMessageData aMessageData, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestSmsSendFailed(PRInt32 aError, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestGotSms(SmsMessageData aMessageData, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestGetSmsFailed(PRInt32 aError, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestSmsDeleted(bool aDeleted, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestSmsDeleteFailed(PRInt32 aError, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ NotifyRequestNoMessageInList(PRInt32 aRequestId, PRUint64 aProcessId);
+
+ NotifyRequestCreateMessageList(PRInt32 aListId, SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ NotifyRequestGotNextMessage(SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ NotifyRequestReadListFailed(PRInt32 aError, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
parent:
sync HasSupport()
returns (bool aHasSupport);
sync GetNumberOfMessagesForText(nsString aText)
returns (PRUint16 aNumber);
- SendMessage(nsString aNumber, nsString aMessage);
+ SendMessage(nsString aNumber, nsString aMessage, PRInt32 aRequestId,
+ PRUint64 aProcessId);
+
+ sync SaveSentMessage(nsString aReceiver, nsString aBody, PRUint64 aDate)
+ returns (PRInt32 aId);
+
+ GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ CreateMessageList(SmsFilterData aFilter, bool aReverse, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+ ClearMessageList(PRInt32 aListId);
__delete__();
};
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/ipc/SmsChild.cpp
+++ b/dom/sms/src/ipc/SmsChild.cpp
@@ -35,16 +35,19 @@
*
* ***** END LICENSE BLOCK ***** */
#include "SmsChild.h"
#include "SmsMessage.h"
#include "Constants.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
+#include "mozilla/dom/ContentChild.h"
+#include "SmsRequestManager.h"
+#include "SmsRequest.h"
namespace mozilla {
namespace dom {
namespace sms {
bool
SmsChild::RecvNotifyReceivedMessage(const SmsMessageData& aMessageData)
{
@@ -54,11 +57,183 @@ SmsChild::RecvNotifyReceivedMessage(cons
}
nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
obs->NotifyObservers(message, kSmsReceivedObserverTopic, nsnull);
return true;
}
+bool
+SmsChild::RecvNotifySentMessage(const SmsMessageData& aMessageData)
+{
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ if (!obs) {
+ return true;
+ }
+
+ nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
+ obs->NotifyObservers(message, kSmsSentObserverTopic, nsnull);
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyDeliveredMessage(const SmsMessageData& aMessageData)
+{
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ if (!obs) {
+ return true;
+ }
+
+ nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
+ obs->NotifyObservers(message, kSmsDeliveredObserverTopic, nsnull);
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsSent(const SmsMessageData& aMessage,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
+ SmsRequestManager::GetInstance()->NotifySmsSent(aRequestId, message);
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsSendFailed(const PRInt32& aError,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifySmsSendFailed(aRequestId,
+ SmsRequest::ErrorType(aError));
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGotSms(const SmsMessageData& aMessage,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
+ SmsRequestManager::GetInstance()->NotifyGotSms(aRequestId, message);
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGetSmsFailed(const PRInt32& aError,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifyGetSmsFailed(aRequestId,
+ SmsRequest::ErrorType(aError));
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsDeleted(const bool& aDeleted,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifySmsDeleted(aRequestId, aDeleted);
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifySmsDeleteFailed(aRequestId,
+ SmsRequest::ErrorType(aError));
+
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifyNoMessageInList(aRequestId);
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestCreateMessageList(const PRInt32& aListId,
+ const SmsMessageData& aMessageData,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
+ SmsRequestManager::GetInstance()->NotifyCreateMessageList(aRequestId, aListId, message);
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessageData,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
+ SmsRequestManager::GetInstance()->NotifyGotNextMessage(aRequestId, message);
+ return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestReadListFailed(const PRInt32& aError,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+ return true;
+ }
+
+ SmsRequestManager::GetInstance()->NotifyReadMessageListFailed(aRequestId,
+ SmsRequest::ErrorType(aError));
+ return true;
+}
+
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/ipc/SmsChild.h
+++ b/dom/sms/src/ipc/SmsChild.h
@@ -43,15 +43,27 @@
namespace mozilla {
namespace dom {
namespace sms {
class SmsChild : public PSmsChild
{
public:
NS_OVERRIDE virtual bool RecvNotifyReceivedMessage(const SmsMessageData& aMessage);
+ NS_OVERRIDE virtual bool RecvNotifySentMessage(const SmsMessageData& aMessage);
+ NS_OVERRIDE virtual bool RecvNotifyDeliveredMessage(const SmsMessageData& aMessage);
+ NS_OVERRIDE virtual bool RecvNotifyRequestSmsSent(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestSmsSendFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestGotSms(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestGetSmsFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleted(const bool& aDeleted, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestCreateMessageList(const PRInt32& aListId, const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvNotifyRequestReadListFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
};
} // namespace sms
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_sms_SmsChild_h
--- a/dom/sms/src/ipc/SmsIPCService.cpp
+++ b/dom/sms/src/ipc/SmsIPCService.cpp
@@ -36,35 +36,39 @@
* ***** END LICENSE BLOCK ***** */
#include "mozilla/dom/ContentChild.h"
#include "SmsIPCService.h"
#include "nsXULAppAPI.h"
#include "jsapi.h"
#include "mozilla/dom/sms/SmsChild.h"
#include "mozilla/dom/sms/SmsMessage.h"
+#include "SmsFilter.h"
namespace mozilla {
namespace dom {
namespace sms {
PSmsChild* SmsIPCService::sSmsChild = nsnull;
-NS_IMPL_ISUPPORTS1(SmsIPCService, nsISmsService)
+NS_IMPL_ISUPPORTS2(SmsIPCService, nsISmsService, nsISmsDatabaseService)
/* static */ PSmsChild*
SmsIPCService::GetSmsChild()
{
if (!sSmsChild) {
sSmsChild = ContentChild::GetSingleton()->SendPSmsConstructor();
}
return sSmsChild;
}
+/*
+ * Implementation of nsISmsService.
+ */
NS_IMETHODIMP
SmsIPCService::HasSupport(bool* aHasSupport)
{
GetSmsChild()->SendHasSupport(aHasSupport);
return NS_OK;
}
@@ -72,19 +76,21 @@ NS_IMETHODIMP
SmsIPCService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
{
GetSmsChild()->SendGetNumberOfMessagesForText(nsString(aText), aResult);
return NS_OK;
}
NS_IMETHODIMP
-SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage,
+ PRInt32 aRequestId, PRUint64 aProcessId)
{
- GetSmsChild()->SendSendMessage(nsString(aNumber), nsString(aMessage));
+ GetSmsChild()->SendSendMessage(nsString(aNumber), nsString(aMessage),
+ aRequestId, ContentChild::GetSingleton()->GetID());
return NS_OK;
}
NS_IMETHODIMP
SmsIPCService::CreateSmsMessage(PRInt32 aId,
const nsAString& aDelivery,
const nsAString& aSender,
@@ -93,11 +99,70 @@ SmsIPCService::CreateSmsMessage(PRInt32
const jsval& aTimestamp,
JSContext* aCx,
nsIDOMMozSmsMessage** aMessage)
{
return SmsMessage::Create(
aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
}
+/*
+ * Implementation of nsISmsDatabaseService.
+ */
+NS_IMETHODIMP
+SmsIPCService::SaveSentMessage(const nsAString& aReceiver,
+ const nsAString& aBody,
+ PRUint64 aDate, PRInt32* aId)
+{
+ GetSmsChild()->SendSaveSentMessage(nsString(aReceiver), nsString(aBody),
+ aDate, aId);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ GetSmsChild()->SendGetMessage(aMessageId, aRequestId,
+ ContentChild::GetSingleton()->GetID());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ GetSmsChild()->SendDeleteMessage(aMessageId, aRequestId,
+ ContentChild::GetSingleton()->GetID());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::CreateMessageList(nsIDOMMozSmsFilter* aFilter, bool aReverse,
+ PRInt32 aRequestId, PRUint64 aProcessId)
+{
+ SmsFilter* filter = static_cast<SmsFilter*>(aFilter);
+ GetSmsChild()->SendCreateMessageList(filter->GetData(), aReverse, aRequestId,
+ ContentChild::GetSingleton()->GetID());
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+ PRUint64 aProcessId)
+{
+ GetSmsChild()->SendGetNextMessageInList(aListId, aRequestId,
+ ContentChild::GetSingleton()->GetID());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::ClearMessageList(PRInt32 aListId)
+{
+ GetSmsChild()->SendClearMessageList(aListId);
+ return NS_OK;
+}
+
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/ipc/SmsIPCService.h
+++ b/dom/sms/src/ipc/SmsIPCService.h
@@ -34,28 +34,31 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_sms_SmsIPCService_h
#define mozilla_dom_sms_SmsIPCService_h
#include "nsISmsService.h"
+#include "nsISmsDatabaseService.h"
namespace mozilla {
namespace dom {
namespace sms {
class PSmsChild;
class SmsIPCService : public nsISmsService
+ , public nsISmsDatabaseService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISMSSERVICE
+ NS_DECL_NSISMSDATABASESERVICE
private:
static PSmsChild* GetSmsChild();
static PSmsChild* sSmsChild;
};
} // namespace sms
} // namespace dom
--- a/dom/sms/src/ipc/SmsParent.cpp
+++ b/dom/sms/src/ipc/SmsParent.cpp
@@ -38,42 +38,74 @@
#include "SmsParent.h"
#include "nsISmsService.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "Constants.h"
#include "nsIDOMSmsMessage.h"
#include "mozilla/unused.h"
#include "SmsMessage.h"
+#include "nsISmsDatabaseService.h"
+#include "SmsFilter.h"
namespace mozilla {
namespace dom {
namespace sms {
+nsTArray<SmsParent*>* SmsParent::gSmsParents = nsnull;
+
NS_IMPL_ISUPPORTS1(SmsParent, nsIObserver)
+/* static */ void
+SmsParent::GetAll(nsTArray<SmsParent*>& aArray)
+{
+ if (!gSmsParents) {
+ aArray.Clear();
+ return;
+ }
+
+ aArray = *gSmsParents;
+}
+
SmsParent::SmsParent()
{
+ if (!gSmsParents) {
+ gSmsParents = new nsTArray<SmsParent*>();
+ }
+
+ gSmsParents->AppendElement(this);
+
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
return;
}
obs->AddObserver(this, kSmsReceivedObserverTopic, false);
+ obs->AddObserver(this, kSmsSentObserverTopic, false);
+ obs->AddObserver(this, kSmsDeliveredObserverTopic, false);
}
void
SmsParent::ActorDestroy(ActorDestroyReason why)
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
return;
}
obs->RemoveObserver(this, kSmsReceivedObserverTopic);
+ obs->RemoveObserver(this, kSmsSentObserverTopic);
+ obs->RemoveObserver(this, kSmsDeliveredObserverTopic);
+
+ NS_ASSERTION(gSmsParents, "gSmsParents can't be null at that point!");
+ gSmsParents->RemoveElement(this);
+ if (gSmsParents->Length() == 0) {
+ delete gSmsParents;
+ gSmsParents = nsnull;
+ }
}
NS_IMETHODIMP
SmsParent::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (!strcmp(aTopic, kSmsReceivedObserverTopic)) {
nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
@@ -81,48 +113,152 @@ SmsParent::Observe(nsISupports* aSubject
NS_ERROR("Got a 'sms-received' topic without a valid message!");
return NS_OK;
}
unused << SendNotifyReceivedMessage(static_cast<SmsMessage*>(message.get())->GetData());
return NS_OK;
}
+ if (!strcmp(aTopic, kSmsSentObserverTopic)) {
+ nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+ if (!message) {
+ NS_ERROR("Got a 'sms-sent' topic without a valid message!");
+ return NS_OK;
+ }
+
+ unused << SendNotifySentMessage(static_cast<SmsMessage*>(message.get())->GetData());
+ return NS_OK;
+ }
+
+ if (!strcmp(aTopic, kSmsDeliveredObserverTopic)) {
+ nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+ if (!message) {
+ NS_ERROR("Got a 'sms-delivered' topic without a valid message!");
+ return NS_OK;
+ }
+
+ unused << SendNotifyDeliveredMessage(static_cast<SmsMessage*>(message.get())->GetData());
+ return NS_OK;
+ }
+
return NS_OK;
}
bool
SmsParent::RecvHasSupport(bool* aHasSupport)
{
*aHasSupport = false;
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, true);
smsService->HasSupport(aHasSupport);
return true;
}
bool
SmsParent::RecvGetNumberOfMessagesForText(const nsString& aText, PRUint16* aResult)
{
*aResult = 0;
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, true);
smsService->GetNumberOfMessagesForText(aText, aResult);
return true;
}
bool
-SmsParent::RecvSendMessage(const nsString& aNumber, const nsString& aMessage)
+SmsParent::RecvSendMessage(const nsString& aNumber, const nsString& aMessage,
+ const PRInt32& aRequestId, const PRUint64& aProcessId)
{
- nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+ nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, true);
- smsService->Send(aNumber, aMessage);
+ smsService->Send(aNumber, aMessage, aRequestId, aProcessId);
+ return true;
+}
+
+bool
+SmsParent::RecvSaveSentMessage(const nsString& aRecipient,
+ const nsString& aBody,
+ const PRUint64& aDate, PRInt32* aId)
+{
+ *aId = -1;
+
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ smsDBService->SaveSentMessage(aRecipient, aBody, aDate, aId);
+ return true;
+}
+
+bool
+SmsParent::RecvGetMessage(const PRInt32& aMessageId, const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ smsDBService->GetMessageMoz(aMessageId, aRequestId, aProcessId);
+ return true;
+}
+
+bool
+SmsParent::RecvDeleteMessage(const PRInt32& aMessageId, const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ smsDBService->DeleteMessage(aMessageId, aRequestId, aProcessId);
+ return true;
+}
+
+bool
+SmsParent::RecvCreateMessageList(const SmsFilterData& aFilter,
+ const bool& aReverse,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ nsCOMPtr<nsIDOMMozSmsFilter> filter = new SmsFilter(aFilter);
+ smsDBService->CreateMessageList(filter, aReverse, aRequestId, aProcessId);
+
+ return true;
+}
+
+bool
+SmsParent::RecvGetNextMessageInList(const PRInt32& aListId,
+ const PRInt32& aRequestId,
+ const PRUint64& aProcessId)
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ smsDBService->GetNextMessageInList(aListId, aRequestId, aProcessId);
+
+ return true;
+}
+
+bool
+SmsParent::RecvClearMessageList(const PRInt32& aListId)
+{
+ nsCOMPtr<nsISmsDatabaseService> smsDBService =
+ do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(smsDBService, true);
+
+ smsDBService->ClearMessageList(aListId);
+
return true;
}
} // namespace sms
} // namespace dom
} // namespace mozilla
--- a/dom/sms/src/ipc/SmsParent.h
+++ b/dom/sms/src/ipc/SmsParent.h
@@ -47,23 +47,34 @@ namespace sms {
class SmsParent : public PSmsParent
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
+ static void GetAll(nsTArray<SmsParent*>& aArray);
+
SmsParent();
NS_OVERRIDE virtual bool RecvHasSupport(bool* aHasSupport);
NS_OVERRIDE virtual bool RecvGetNumberOfMessagesForText(const nsString& aText, PRUint16* aResult);
- NS_OVERRIDE virtual bool RecvSendMessage(const nsString& aNumber, const nsString& aMessage);
+ NS_OVERRIDE virtual bool RecvSendMessage(const nsString& aNumber, const nsString& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvSaveSentMessage(const nsString& aRecipient, const nsString& aBody, const PRUint64& aDate, PRInt32* aId);
+ NS_OVERRIDE virtual bool RecvGetMessage(const PRInt32& aMessageId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvDeleteMessage(const PRInt32& aMessageId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvCreateMessageList(const SmsFilterData& aFilter, const bool& aReverse, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvGetNextMessageInList(const PRInt32& aListId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+ NS_OVERRIDE virtual bool RecvClearMessageList(const PRInt32& aListId);
protected:
virtual void ActorDestroy(ActorDestroyReason why);
+
+private:
+ static nsTArray<SmsParent*>* gSmsParents;
};
} // namespace sms
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_sms_SmsParent_h
--- a/dom/sms/tests/Makefile.in
+++ b/dom/sms/tests/Makefile.in
@@ -45,16 +45,17 @@ include $(DEPTH)/config/autoconf.mk
DIRS = \
$(NULL)
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_sms_basics.html \
+ test_smsfilter.html \
$(NULL)
_CHROME_TEST_FILES = \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/dom/sms/tests/test_sms_basics.html
+++ b/dom/sms/tests/test_sms_basics.html
@@ -40,16 +40,19 @@ function checkInterface(aInterface) {
function test() {
var gSmsEnabled = SpecialPowers.getBoolPref("dom.sms.enabled");
var gSmsWhiteList = SpecialPowers.getCharPref("dom.sms.whitelist");
checkInterface("SmsManager");
checkInterface("NavigatorSms");
checkInterface("SmsMessage");
checkInterface("SmsEvent");
+ checkInterface("SmsRequest");
+ checkInterface("SmsFilter");
+ checkInterface("SmsCursor");
// If sms are disabled and whitelist is empty, sms is disabled.
SpecialPowers.setBoolPref("dom.sms.enabled", false);
SpecialPowers.setCharPref("dom.sms.whitelist", "");
checkSmsDisabled();
// If sms are enabled and whitelist is empty, sms are disabled.
SpecialPowers.setBoolPref("dom.sms.enabled", true);
new file mode 100644
--- /dev/null
+++ b/dom/sms/tests/test_smsfilter.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test SmsFilter</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test SmsFilter **/
+
+function throwingCheck(aFilter, aProperty, disallowedValue)
+{
+ disallowedValue.forEach(function(v) {
+ var exception = false;
+ try {
+ aFilter[aProperty] = v;
+ } catch (e) {
+ exception = true;
+ }
+ ok(exception, "An exception should have been thrown");
+ });
+}
+
+var filter = new MozSmsFilter();
+
+isnot(filter, null, "filter should be set");
+
+is(filter.startDate, null, "Parameters shouldn't be initialized");
+is(filter.endDate, null, "Parameters shouldn't be initialized");
+is(filter.numbers, null, "Parameters shouldn't be initialized");
+is(filter.delivery, null, "Parameters shouldn't be initialized");
+
+var date = new Date();
+filter.startDate = date;
+is(filter.startDate, "" + date, "Setters and getters should work!");
+filter.startDate = null;
+is(filter.startDate, null, "null should revert the value to default");
+throwingCheck(filter, 'startDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
+
+filter.endDate = date;
+is(filter.endDate, "" + date, "Setters and getters should work!");
+filter.endDate = null;
+is(filter.endDate, null, "null should revert the value to default");
+throwingCheck(filter, 'endDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
+
+var numbers = [ "foo", "bar" ];
+filter.numbers = numbers;
+is(filter.numbers, "" + numbers, "Setters and getters should work!");
+filter.numbers = null;
+is(filter.numbers, null, "null should revert the value to default");
+throwingCheck(filter, 'numbers', [ "foo", 42, function () {}, new Date(), undefined ]);
+
+filter.delivery = "sent";
+is(filter.delivery, "sent", "Setters and getters should work!");
+filter.delivery = "received";
+is(filter.delivery, "received", "Setters and getters should work!");
+filter.delivery = "";
+is(filter.delivery, null, "The empty string should revert the value to default.");
+filter.delivery = null;
+is(filter.delivery, null, "'null' should revert the value to default.");
+throwingCheck(filter, 'delivery', [ "foo", 42, [1, 2], function () {}, new Date(), undefined ]);
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/telephony/nsITelephone.idl
+++ b/dom/telephony/nsITelephone.idl
@@ -48,32 +48,63 @@ interface nsITelephoneCallback : nsISupp
// 'callState' uses the CALL_STATE values from nsITelephone. Return true to
// continue enumeration or false to cancel.
boolean enumerateCallState(in unsigned long callIndex,
in unsigned short callState,
in AString number,
in boolean isActive);
};
-[scriptable, uuid(5be6e41d-3aee-4f5c-8284-95cf529dd6fe)]
+[scriptable, uuid(8399fddd-471c-41ac-8f35-99f7dbb738ec)]
+interface nsIDataCallInfo : nsISupports
+{
+ readonly attribute unsigned long callState;
+ readonly attribute AString cid;
+ readonly attribute AString apn;
+};
+
+[scriptable, uuid(36cc4b89-0338-4ff7-a3c2-d78e60f2ea98)]
+interface nsIPhoneDataCallCallback : nsISupports
+{
+ /**
+ * This method is called when the state of a data call is changed.
+ *
+ * @param dataState use DATACALL_STATE_* values from nsITelephone.
+ */
+ void dataCallStateChanged(in AString cid,
+ in AString interfaceName,
+ in unsigned short callState);
+
+ void receiveDataCallList([array,size_is(aLength)] in nsIDataCallInfo aDataCalls,
+ in unsigned long aLength);
+};
+
+[scriptable, uuid(78ed0beb-d6ad-42f8-929a-8d003285784f)]
interface nsITelephone : nsISupports
{
const unsigned short CALL_STATE_UNKNOWN = 0;
const unsigned short CALL_STATE_DIALING = 1;
const unsigned short CALL_STATE_RINGING = 2;
const unsigned short CALL_STATE_BUSY = 3;
const unsigned short CALL_STATE_CONNECTING = 4;
const unsigned short CALL_STATE_CONNECTED = 5;
const unsigned short CALL_STATE_HOLDING = 6;
const unsigned short CALL_STATE_HELD = 7;
const unsigned short CALL_STATE_RESUMING = 8;
const unsigned short CALL_STATE_DISCONNECTING = 9;
const unsigned short CALL_STATE_DISCONNECTED = 10;
const unsigned short CALL_STATE_INCOMING = 11;
+ // Keep consistent with GECKO_DATACALL_STATE_* values in ril_consts.js
+ const unsigned short DATACALL_STATE_UNKNOWN = 0;
+ const unsigned short DATACALL_STATE_CONNECTING = 1;
+ const unsigned short DATACALL_STATE_CONNECTED = 2;
+ const unsigned short DATACALL_STATE_DISCONNECTING = 3;
+ const unsigned short DATACALL_STATE_DISCONNECTED = 4;
+
readonly attribute jsval currentState;
void registerCallback(in nsITelephoneCallback callback);
void unregisterCallback(in nsITelephoneCallback callback);
/**
* Will continue calling callback.enumerateCallState until the callback
* returns false.
@@ -90,14 +121,28 @@ interface nsITelephone : nsISupports
void stopTone();
void answerCall(in unsigned long callIndex);
void rejectCall(in unsigned long callIndex);
attribute bool microphoneMuted;
attribute bool speakerEnabled;
+ // PDP APIs
+ void setupDataCall(in long radioTech,
+ in DOMString apn,
+ in DOMString user,
+ in DOMString passwd,
+ in long chappap,
+ in DOMString pdptype);
+ void deactivateDataCall(in DOMString cid,
+ in DOMString reason);
+ void getDataCallList();
+
+ void registerDataCallCallback(in nsIPhoneDataCallCallback callback);
+ void unregisterDataCallCallback(in nsIPhoneDataCallCallback callback);
+
/**
* SMS-related functionality.
*/
unsigned short getNumberOfMessagesForText(in DOMString text);
void sendSMS(in DOMString number, in DOMString message);
};
--- a/dom/telephony/nsTelephonyWorker.js
+++ b/dom/telephony/nsTelephonyWorker.js
@@ -45,16 +45,18 @@ Cu.import("resource://gre/modules/Servic
var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
const DEBUG = true; // set to false to suppress debug messages
const TELEPHONYWORKER_CID =
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
+const DATACALLINFO_CID =
+ Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
const nsIAudioManager = Ci.nsIAudioManager;
const nsITelephone = Ci.nsITelephone;
const kSmsReceivedObserverTopic = "sms-received";
const DOM_SMS_DELIVERY_RECEIVED = "received";
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
@@ -105,16 +107,30 @@ XPCOMUtils.defineLazyGetter(this, "gAudi
} catch (ex) {
//TODO on the phone this should not fall back as silently.
debug("Using fake audio manager.");
return FakeAudioManager;
}
});
+function DataCallInfo(state, cid, apn) {
+ this.callState = state;
+ this.cid = cid;
+ this.apn = apn;
+}
+DataCallInfo.protoptype = {
+ classID: DATACALLINFO_CID,
+ classInfo: XPCOMUtils.generateCI({classID: DATACALLINFO_CID,
+ classDescription: "DataCallInfo",
+ interfaces: [Ci.nsIDataCallInfo]}),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInfo]),
+};
+
+
function nsTelephonyWorker() {
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
this.worker.onerror = this.onerror.bind(this);
this.worker.onmessage = this.onmessage.bind(this);
debug("Starting Worker\n");
this.currentState = {
signalStrength: null,
operator: null,
@@ -173,16 +189,22 @@ nsTelephonyWorker.prototype = {
this.currentState.radioState = message.radioState;
break;
case "cardstatechange":
this.currentState.cardState = message.cardState;
break;
case "sms-received":
this.handleSmsReceived(message);
return;
+ case "datacallstatechange":
+ this.handleDataCallState(message);
+ break;
+ case "datacalllist":
+ this.handleDataCallList(message);
+ break;
default:
throw new Error("Don't know about this message type: " + message.type);
}
},
/**
* Track the active call and update the audio system as its state changes.
*
@@ -273,16 +295,39 @@ nsTelephonyWorker.prototype = {
DOM_SMS_DELIVERY_RECEIVED,
message.sender || null,
message.receiver || null,
message.body || null,
message.timestamp);
Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
},
+ /**
+ * Handle data call state changes.
+ */
+ handleDataCallState: function handleDataCallState(message) {
+ let ifname = message.ifname ? message.ifname : "";
+ this._deliverDataCallCallback("dataCallStateChanged",
+ [message.cid, ifname, message.state]);
+ },
+
+ /**
+ * Handle data call list.
+ */
+ handleDataCallList: function handleDataCallList(message) {
+ let datacalls = [];
+ for each (let datacall in message.datacalls) {
+ datacalls.push(new DataCallInfo(datacall.state,
+ datacall.cid,
+ datacall.apn));
+ }
+ this._deliverDataCallCallback("receiveDataCallList",
+ [datacalls, datacalls.length]);
+ },
+
// nsIRadioWorker
worker: null,
// nsITelephone
currentState: null,
@@ -290,17 +335,17 @@ nsTelephonyWorker.prototype = {
debug("Dialing " + number);
this.worker.postMessage({type: "dial", number: number});
},
hangUp: function hangUp(callIndex) {
debug("Hanging up call no. " + callIndex);
this.worker.postMessage({type: "hangUp", callIndex: callIndex});
},
-
+
startTone: function startTone(dtmfChar) {
debug("Sending Tone for " + dtmfChar);
this.worker.postMessage({type: "startTone", dtmfChar: dtmfChar});
},
stopTone: function stopTone() {
debug("Stopping Tone");
this.worker.postMessage({type: "stopTone"});
@@ -410,16 +455,94 @@ nsTelephonyWorker.prototype = {
}
try {
handler.apply(callback, args);
} catch (e) {
debug("callback handler for " + name + " threw an exception: " + e);
}
}
},
+
+ registerDataCallCallback: function registerDataCallCallback(callback) {
+ if (this._datacall_callbacks) {
+ if (this._datacall_callbacks.indexOf(callback) != -1) {
+ throw new Error("Already registered this callback!");
+ }
+ } else {
+ this._datacall_callbacks = [];
+ }
+ this._datacall_callbacks.push(callback);
+ debug("Registering callback: " + callback);
+ },
+
+ unregisterDataCallCallback: function unregisterDataCallCallback(callback) {
+ if (!this._datacall_callbacks) {
+ return;
+ }
+ let index = this._datacall_callbacks.indexOf(callback);
+ if (index != -1) {
+ this._datacall_callbacks.splice(index, 1);
+ debug("Unregistering callback: " + callback);
+ }
+ },
+
+ _deliverDataCallCallback: function _deliverDataCallCallback(name, args) {
+ // We need to worry about callback registration state mutations during the
+ // callback firing. The behaviour we want is to *not* call any callbacks
+ // that are added during the firing and to *not* call any callbacks that are
+ // removed during the firing. To address this, we make a copy of the
+ // callback list before dispatching and then double-check that each callback
+ // is still registered before calling it.
+ if (!this._datacall_callbacks) {
+ return;
+ }
+ let callbacks = this._datacall_callbacks.slice();
+ for each (let callback in callbacks) {
+ if (this._datacall_callbacks.indexOf(callback) == -1) {
+ continue;
+ }
+ let handler = callback[name];
+ if (typeof handler != "function") {
+ throw new Error("No handler for " + name);
+ }
+ try {
+ handler.apply(callback, args);
+ } catch (e) {
+ debug("callback handler for " + name + " threw an exception: " + e);
+ }
+ }
+ },
+
+ setupDataCall: function(radioTech, apn, user, passwd, chappap, pdptype) {
+ this.worker.postMessage({type: "setupDataCall",
+ radioTech: radioTech,
+ apn: apn,
+ user: user,
+ passwd: passwd,
+ chappap: chappap,
+ pdptype: pdptype});
+ this._deliverDataCallCallback("dataCallStateChanged",
+ [message.cid, "",
+ RIL.GECKO_DATACALL_STATE_CONNECTING]);
+ },
+
+ deactivateDataCall: function(cid, reason) {
+ this.worker.postMessage({type: "deactivateDataCall",
+ cid: cid,
+ reason: reason});
+ this._deliverDataCallCallback("dataCallStateChanged",
+ [message.cid,
+ "",
+ RIL.GECKO_DATACALL_STATE_DISCONNECTING]);
+ },
+
+ getDataCallList: function getDataCallList() {
+ this.worker.postMessage({type: "getDataCallList"});
+ },
+
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTelephonyWorker]);
let debug;
if (DEBUG) {
debug = function (s) {
dump("-*- TelephonyWorker component: " + s + "\n");
--- a/dom/telephony/ril_consts.js
+++ b/dom/telephony/ril_consts.js
@@ -402,11 +402,37 @@ const PDU_ALPHABET_7BIT_DEFAULT = [
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"\xe4", // LATIN SMALL LETTER A WITH DIAERESIS
"\xf6", // LATIN SMALL LETTER O WITH DIAERESIS
"\xf1", // LATIN SMALL LETTER N WITH TILDE
"\xfc", // LATIN SMALL LETTER U WITH DIAERESIS
"\xe0" // LATIN SMALL LETTER A WITH GRAVE
];
+const DATACALL_RADIOTECHONLOGY_CDMA = 0;
+const DATACALL_RADIOTECHONLOGY_GSM = 1;
+
+const DATACALL_AUTH_NONE = 0;
+const DATACALL_AUTH_PAP = 1;
+const DATACALL_AUTH_CHAP = 2;
+const DATACALL_AUTH_PAP_OR_CHAP = 3;
+
+const DATACALL_PROFILE_DEFAULT = 0;
+const DATACALL_PROFILE_TETHERED = 1;
+const DATACALL_PROFILE_OEM_BASE = 1000;
+
+const DATACALL_DEACTIVATE_NO_REASON = 0;
+const DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1;
+
+const DATACALL_INACTIVE = 0;
+const DATACALL_ACTIVE_DOWN = 1;
+const DATACALL_ACTIVE_UP = 2;
+
+// Keep consistent with nsITelephone.DATACALL_STATE_*.
+const GECKO_DATACALL_STATE_UNKNOWN = 0;
+const GECKO_DATACALL_STATE_CONNECTING = 1;
+const GECKO_DATACALL_STATE_CONNECTED = 2;
+const GECKO_DATACALL_STATE_DISCONNECTING = 3;
+const GECKO_DATACALL_STATE_DISCONNECTED = 4;
+
// Allow this file to be imported via Components.utils.import().
const EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/telephony/ril_worker.js
+++ b/dom/telephony/ril_worker.js
@@ -111,16 +111,19 @@ let Buf = {
this.currentParcelSize = 0;
// This gets incremented each time we send out a parcel.
this.token = 1;
// Maps tokens we send out with requests to the request type, so that
// when we get a response parcel back, we know what request it was for.
this.tokenRequestMap = {};
+
+ // This is the token of last solicited response.
+ this.lastSolicitedToken = 0;
},
/**
* Grow the incoming buffer.
*
* @param min_size
* Minimum new size. The actual new size will be the the smallest
* power of 2 that's larger than this number.
@@ -444,16 +447,17 @@ let Buf = {
//TODO
debug("Received error " + error + " for solicited parcel type " +
request_type);
return;
}
debug("Solicited response for request type " + request_type +
", token " + token);
delete this.tokenRequestMap[token];
+ this.lastSolicitedToken = token;
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
request_type = this.readUint32();
length -= UINT32_SIZE;
debug("Unsolicited response for request type " + request_type);
} else {
debug("Unknown response type: " + response_type);
return;
}
@@ -745,17 +749,16 @@ let RIL = {
},
/**
* Start a DTMF Tone.
*
* @param dtmfChar
* DTMF signal to send, 0-9, *, +
*/
-
startTone: function startTone(dtmfChar) {
Buf.newParcel(REQUEST_DTMF_START);
Buf.writeString(dtmfChar);
Buf.sendParcel();
},
stopTone: function stopTone() {
Buf.simpleRequest(REQUEST_DTMF_STOP);
@@ -775,21 +778,88 @@ let RIL = {
},
/**
* Set the Short Message Service Center address.
*
* @param smsc
* Short Message Service Center address in PDU format.
*/
- setSMSCAddress: function setSMSCAddress(smsc) {
- Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
- Buf.writeString(smsc);
- Buf.sendParcel();
- },
+ setSMSCAddress: function setSMSCAddress(smsc) {
+ Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
+ Buf.writeString(smsc);
+ Buf.sendParcel();
+ },
+
+ /**
+ * Setup a data call.
+ *
+ * @param radioTech
+ * Integer to indicate radio technology.
+ * DATACALL_RADIOTECHONLOGY_CDMA => CDMA.
+ * DATACALL_RADIOTECHONLOGY_GSM => GSM.
+ * @param apn
+ * String containing the name of the APN to connect to.
+ * @param user
+ * String containing the username for the APN.
+ * @param passwd
+ * String containing the password for the APN.
+ * @param chappap
+ * Integer containing CHAP/PAP auth type.
+ * DATACALL_AUTH_NONE => PAP and CHAP is never performed.
+ * DATACALL_AUTH_PAP => PAP may be performed.
+ * DATACALL_AUTH_CHAP => CHAP may be performed.
+ * DATACALL_AUTH_PAP_OR_CHAP => PAP / CHAP may be performed.
+ * @param pdptype
+ * String containing PDP type to request. ("IP", "IPV6", ...)
+ */
+ setupDataCall: function (radioTech, apn, user, passwd, chappap, pdptype) {
+ let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL);
+ Buf.writeUint32(7);
+ Buf.writeString(radioTech.toString());
+ Buf.writeString(DATACALL_PROFILE_DEFAULT.toString());
+ Buf.writeString(apn);
+ Buf.writeString(user);
+ Buf.writeString(passwd);
+ Buf.writeString(chappap.toString());
+ Buf.writeString(pdptype);
+ Buf.sendParcel();
+ return token;
+ },
+
+ /**
+ * Deactivate a data call.
+ *
+ * @param cid
+ * String containing CID.
+ * @param reason
+ * One of DATACALL_DEACTIVATE_* constants.
+ */
+ deactivateDataCall: function (cid, reason) {
+ let token = Buf.newParcel(REQUEST_DEACTIVATE_DATA_CALL);
+ Buf.writeUint32(2);
+ Buf.writeString(cid);
+ Buf.writeString(reason);
+ Buf.sendParcel();
+ return token;
+ },
+
+ /**
+ * Get a list of data calls.
+ */
+ getDataCallList: function getDataCallList() {
+ Buf.simpleRequest(REQUEST_DATA_CALL_LIST);
+ },
+
+ /**
+ * Get failure casue code for the most recently failed PDP context.
+ */
+ getFailCauseCode: function getFailCauseCode() {
+ Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE);
+ },
/**
* Handle incoming requests from the RIL. We find the method that
* corresponds to the request type. Incidentally, the request type
* _is_ the method name, so that's easy.
*/
handleParcel: function handleParcel(request_type, length) {
@@ -944,17 +1014,20 @@ RIL[REQUEST_DTMF] = function REQUEST_DTM
};
RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS() {
let messageRef = Buf.readUint32();
let ackPDU = Buf.readString();
let errorCode = Buf.readUint32();
Phone.onSendSMS(messageRef, ackPDU, errorCode);
};
RIL[REQUEST_SEND_SMS_EXPECT_MORE] = null;
-RIL[REQUEST_SETUP_DATA_CALL] = null;
+RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL() {
+ let [cid, ifname, ipaddr, dns, gw] = Buf.readStringList();
+ Phone.onSetupDataCall(Buf.lastSolicitedToken, cid, ifname, ipaddr, dns, gw);
+};
RIL[REQUEST_SIM_IO] = null;
RIL[REQUEST_SEND_USSD] = null;
RIL[REQUEST_CANCEL_USSD] = null;
RIL[REQUEST_GET_CLIR] = null;
RIL[REQUEST_SET_CLIR] = null;
RIL[REQUEST_QUERY_CALL_FORWARD_STATUS] = null;
RIL[REQUEST_SET_CALL_FORWARD] = null;
RIL[REQUEST_QUERY_CALL_WAITING] = null;
@@ -968,17 +1041,19 @@ RIL[REQUEST_GET_IMEI] = function REQUEST
};
RIL[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV() {
let imeiSV = Buf.readString();
Phone.onIMEISV(imeiSV);
};
RIL[REQUEST_ANSWER] = function REQUEST_ANSWER(length) {
Phone.onAnswerCall();
};
-RIL[REQUEST_DEACTIVATE_DATA_CALL] = null;
+RIL[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL() {
+ Phone.onDeactivateDataCall(Buf.lastSolicitedToken);
+};
RIL[REQUEST_QUERY_FACILITY_LOCK] = null;
RIL[REQUEST_SET_FACILITY_LOCK] = null;
RIL[REQUEST_CHANGE_BARRING_PASSWORD] = null;
RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE() {
let response = Buf.readUint32List();
Phone.onNetworkSelectionMode(response);
};
RIL[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = null;
@@ -988,25 +1063,44 @@ RIL[REQUEST_DTMF_START] = function REQUE
Phone.onStartTone();
};
RIL[REQUEST_DTMF_STOP] = function REQUEST_DTMF_STOP() {
Phone.onStopTone();
};
RIL[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION() {
let version = Buf.readString();
Phone.onBasebandVersion(version);
-},
+};
RIL[REQUEST_SEPARATE_CONNECTION] = null;
RIL[REQUEST_SET_MUTE] = function REQUEST_SET_MUTE(length) {
Phone.onSetMute();
};
RIL[REQUEST_GET_MUTE] = null;
RIL[REQUEST_QUERY_CLIP] = null;
RIL[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null;
-RIL[REQUEST_DATA_CALL_LIST] = null;
+RIL[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length) {
+ let datacalls = [];
+
+ if (!length) {
+ return;
+ }
+
+ let num = Buf.readUint32();
+ for (let i = 0; i < num; i++) {
+ datacalls.push({
+ cid: Buf.readUint32().toString(),
+ active: Buf.readUint32(),
+ type: Buf.readString(),
+ apn: Buf.readString(),
+ address: Buf.readString()
+ });
+ }
+
+ Phone.onDataCallList(datacalls);
+};
RIL[REQUEST_RESET_RADIO] = null;
RIL[REQUEST_OEM_HOOK_RAW] = null;
RIL[REQUEST_OEM_HOOK_STRINGS] = null;
RIL[REQUEST_SCREEN_STATE] = null;
RIL[REQUEST_SET_SUPP_SVC_NOTIFICATION] = null;
RIL[REQUEST_WRITE_SMS_TO_SIM] = null;
RIL[REQUEST_DELETE_SMS_ON_SIM] = null;
RIL[REQUEST_SET_BAND_MODE] = null;
@@ -1171,16 +1265,26 @@ let Phone = {
*/
currentCalls: {},
/**
* Mute or unmute the radio.
*/
_muted: true,
+ /**
+ * Existing data calls.
+ */
+ currentDataCalls: {},
+
+ /**
+ * Tracks active requests to the RIL concerning 3G data calls.
+ */
+ activeDataRequests: {},
+
get muted() {
return this._muted;
},
set muted(val) {
val = Boolean(val);
if (this._muted != val) {
RIL.setMute(val);
@@ -1578,16 +1682,98 @@ let Phone = {
onNewSMSOnSIM: function onNewSMSOnSIM(info) {
//TODO
},
onAcknowledgeSMS: function onAcknowledgeSMS() {
},
+ onSetupDataCall: function onSetupDataCall(token, cid, ifname, ipaddr,
+ dns, gw) {
+ let options = this.activeDataRequests[token];
+ delete this.activeDataRequests[token];
+
+ this.currentDataCalls[cid] = {
+ state: GECKO_DATACALL_STATE_CONNECTED,
+ cid: cid,
+ apn: options.apn,
+ ifname: ifname,
+ ipaddr: ipaddr,
+ dns: dns,
+ gw: gw,
+ };
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_CONNECTED,
+ cid: cid,
+ apn: options.apn,
+ ifname: ifname,
+ ipaddr: ipaddr,
+ dns: dns,
+ gateway: gw});
+ },
+
+ onDeactivateDataCall: function onDeactivateDataCall(token) {
+ let options = this.activeDataRequests[token];
+ delete this.activeDataRequests[token];
+
+ let cid = options.cid;
+ if (!(cid in this.currentDataCalls)) {
+ return;
+ }
+
+ let apn = this.currentDataCalls[cid].apn;
+ delete this.currentDataCalls[cid];
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_DISCONNECTED,
+ cid: cid,
+ apn: apn});
+ },
+
+ onDataCallList: function onDataCallList(datacalls) {
+ let currentDataCalls = this.currentDataCalls;
+
+ // Sync content of currentDataCalls and data call list.
+ for each (let datacall in datacalls) {
+ let {cid, apn} = datacall;
+
+ if (datacall.active != DATACALL_INACTIVE) {
+ // XXX: This should be followed up.
+ // datacall.active == DATACALL_ACTIVE_DOWN(1) for my device
+ if (!(cid in currentDataCalls)) {
+ let datacall = {state: GECKO_DATACALL_STATE_CONNECTED,
+ cid: cid,
+ apn: apn,
+ ipaddr: datacall.address};
+ currentDataCalls[cid] = datacall;
+
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_CONNECTED,
+ cid: cid,
+ apn: apn});
+ }
+ } else { // datacall.active == DATACALL_INACTIVE
+ if (cid in currentDataCalls) {
+ delete currentDataCalls[cid];
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_DISCONNECTED,
+ cid: cid,
+ apn: apn});
+ }
+ }
+ }
+
+ let datacall_list = [];
+ for each (let datacall in this.currentDataCalls) {
+ datacall_list.push(datacall);
+ }
+ this.sendDOMMessage({type: "datacalllist",
+ datacalls: datacall_list});
+ },
+
/**
* Outgoing requests to the RIL. These can be triggered from the
* main thread via messages that look like this:
*
* {type: "methodName",
* extra: "parameters",
* go: "here"}
*
@@ -1725,16 +1911,64 @@ let Phone = {
//TODO: the data encoding and length in octets should eventually be
// computed on the mainthread and passed down to us.
RIL.sendSMS(this.SMSC, options.number, options.body,
PDU_DCS_MSG_CODING_7BITS_ALPHABET, //TODO: hard-coded for now,
Math.ceil(options.body.length * 7 / 8)); //TODO: ditto
},
/**
+ * Setup a data call (PDP).
+ */
+ setupDataCall: function setupDataCall(options) {
+ if (DEBUG) debug("setupDataCall: " + JSON.stringify(options));
+
+ let token = RIL.setupDataCall(options.radioTech, options.apn,
+ options.user, options.passwd,
+ options.chappap, options.reason);
+ this.activeDataRequests[token] = options;
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_CONNECTING,
+ apn: options.apn});
+ },
+
+ /**
+ * Deactivate a data call (PDP).
+ */
+ deactivateDataCall: function deactivateDataCall(options) {
+ if (!(options.cid in this.currentDataCalls)) {
+ return;
+ }
+
+ let datacall = this.currentDataCalls[options.cid];
+ datacall.state = GECKO_DATACALL_STATE_DISCONNECTING;
+
+ let token = RIL.deactivateDataCall(options.cid, options.reason);
+ this.activeDataRequests[token] = options;
+ this.sendDOMMessage({type: "datacallstatechange",
+ state: GECKO_DATACALL_STATE_DISCONNECTING,
+ cid: options.cid,
+ apn: datacall.apn});
+ },
+
+ /**
+ * Get the list of data calls.
+ */
+ getDataCallList: function getDataCallList(options) {
+ RIL.getDataCallList();
+ },
+
+ /**
+ * Get failure cause code for the last failed PDP context.
+ */
+ getFailCauseCode: function getFailCauseCode(options) {
+ RIL.getFailCauseCode();
+ },
+
+ /**
* Handle incoming messages from the main UI thread.
*
* @param message
* Object containing the message. Messages are supposed
*/
handleDOMMessage: function handleMessage(message) {
if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
let method = this[message.type];
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -87,31 +87,53 @@ using namespace mozilla::xpconnect::memo
// The stack limit the JS engine will check. Half the size of the
// actual C stack, to be safe.
#define WORKER_CONTEXT_NATIVE_STACK_LIMIT 128 * sizeof(size_t) * 1024
// The maximum number of threads to use for workers, overridable via pref.
#define MAX_WORKERS_PER_DOMAIN 10
+PR_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN >= 1);
+
// The default number of seconds that close handlers will be allowed to run.
#define MAX_SCRIPT_RUN_TIME_SEC 10
// The number of seconds that idle threads can hang around before being killed.
#define IDLE_THREAD_TIMEOUT_SEC 30
// The maximum number of threads that can be idle at one time.
#define MAX_IDLE_THREADS 20
#define PREF_WORKERS_ENABLED "dom.workers.enabled"
#define PREF_WORKERS_MAX_PER_DOMAIN "dom.workers.maxPerDomain"
#define PREF_WORKERS_GCZEAL "dom.workers.gczeal"
#define PREF_MAX_SCRIPT_RUN_TIME "dom.max_script_run_time"
-PR_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN >= 1);
+#define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
+#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
+
+#define BROADCAST_ALL_WORKERS(_func, ...) \
+ PR_BEGIN_MACRO \
+ AssertIsOnMainThread(); \
+ \
+ nsAutoTArray<WorkerPrivate*, 100> workers; \
+ { \
+ MutexAutoLock lock(mMutex); \
+ \
+ mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers); \
+ } \
+ \
+ if (!workers.IsEmpty()) { \
+ AutoSafeJSContext cx; \
+ for (PRUint32 index = 0; index < workers.Length(); index++) { \
+ workers[index]-> _func (cx, ##__VA_ARGS__); \
+ } \
+ } \
+ PR_END_MACRO
namespace {
const PRUint32 kNoIndex = PRUint32(-1);
const PRUint32 kRequiredJSContextOptions =
JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_NO_SCRIPT_RVAL;
@@ -902,16 +924,25 @@ RuntimeService::Init()
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
nsresult rv =
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
NS_ENSURE_SUCCESS(rv, rv);
mObserved = true;
+ if (NS_FAILED(obs->AddObserver(this, GC_REQUEST_OBSERVER_TOPIC, false))) {
+ NS_WARNING("Failed to register for GC request notifications!");
+ }
+
+ if (NS_FAILED(obs->AddObserver(this, MEMORY_PRESSURE_OBSERVER_TOPIC,
+ false))) {
+ NS_WARNING("Failed to register for memory pressure notifications!");
+ }
+
for (PRUint32 index = 0; index < ArrayLength(gPrefsToWatch); index++) {
if (NS_FAILED(Preferences::RegisterCallback(PrefCallback,
gPrefsToWatch[index], this))) {
NS_WARNING("Failed to register pref callback?!");
}
PrefCallback(gPrefsToWatch[index], this);
}
@@ -1014,17 +1045,17 @@ RuntimeService::Cleanup()
}
}
// And make sure all their final messages have run and all their threads
// have joined.
while (mDomainMap.Count()) {
MutexAutoUnlock unlock(mMutex);
- if (NS_FAILED(NS_ProcessNextEvent(currentThread))) {
+ if (!NS_ProcessNextEvent(currentThread)) {
NS_WARNING("Something bad happened!");
break;
}
}
}
}
if (mWindowMap.IsInitialized()) {
@@ -1032,16 +1063,25 @@ RuntimeService::Cleanup()
}
if (mObserved) {
for (PRUint32 index = 0; index < ArrayLength(gPrefsToWatch); index++) {
Preferences::UnregisterCallback(PrefCallback, gPrefsToWatch[index], this);
}
if (obs) {
+ if (NS_FAILED(obs->RemoveObserver(this, GC_REQUEST_OBSERVER_TOPIC))) {
+ NS_WARNING("Failed to unregister for GC request notifications!");
+ }
+
+ if (NS_FAILED(obs->RemoveObserver(this,
+ MEMORY_PRESSURE_OBSERVER_TOPIC))) {
+ NS_WARNING("Failed to unregister for memory pressure notifications!");
+ }
+
nsresult rv =
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID);
mObserved = NS_FAILED(rv);
}
}
}
// static
@@ -1190,90 +1230,61 @@ RuntimeService::NoteIdleThread(nsIThread
nsITimer::TYPE_ONE_SHOT))) {
NS_ERROR("Can't schedule timer!");
}
}
void
RuntimeService::UpdateAllWorkerJSContextOptions()
{
- AssertIsOnMainThread();
-
- nsAutoTArray<WorkerPrivate*, 100> workers;
- {
- MutexAutoLock lock(mMutex);
-
- mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
- }
-
- if (!workers.IsEmpty()) {
- AutoSafeJSContext cx;
- for (PRUint32 index = 0; index < workers.Length(); index++) {
- workers[index]->UpdateJSContextOptions(cx, GetDefaultJSContextOptions());
- }
- }
+ BROADCAST_ALL_WORKERS(UpdateJSContextOptions, GetDefaultJSContextOptions());
}
void
RuntimeService::UpdateAllWorkerJSRuntimeHeapSize()
{
- AssertIsOnMainThread();
-
- nsAutoTArray<WorkerPrivate*, 100> workers;
- {
- MutexAutoLock lock(mMutex);
-
- mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
- }
-
- if (!workers.IsEmpty()) {
- AutoSafeJSContext cx;
- for (PRUint32 index = 0; index < workers.Length(); index++) {
- workers[index]->UpdateJSRuntimeHeapSize(cx,
- GetDefaultJSRuntimeHeapSize());
- }
- }
+ BROADCAST_ALL_WORKERS(UpdateJSRuntimeHeapSize, GetDefaultJSRuntimeHeapSize());
}
#ifdef JS_GC_ZEAL
void
RuntimeService::UpdateAllWorkerGCZeal()
{
- AssertIsOnMainThread();
-
- nsAutoTArray<WorkerPrivate*, 100> workers;
- {
- MutexAutoLock lock(mMutex);
-
- mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
- }
-
- if (!workers.IsEmpty()) {
- AutoSafeJSContext cx;
- for (PRUint32 index = 0; index < workers.Length(); index++) {
- workers[index]->UpdateGCZeal(cx, GetDefaultGCZeal());
- }
- }
+ BROADCAST_ALL_WORKERS(UpdateGCZeal, GetDefaultGCZeal());
}
#endif
+void
+RuntimeService::GarbageCollectAllWorkers(bool aShrinking)
+{
+ BROADCAST_ALL_WORKERS(GarbageCollect, aShrinking);
+}
+
// nsISupports
NS_IMPL_ISUPPORTS1(RuntimeService, nsIObserver)
// nsIObserver
NS_IMETHODIMP
RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
AssertIsOnMainThread();
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) {
Cleanup();
return NS_OK;
}
+ if (!strcmp(aTopic, GC_REQUEST_OBSERVER_TOPIC)) {
+ GarbageCollectAllWorkers(false);
+ return NS_OK;
+ }
+ if (!strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
+ GarbageCollectAllWorkers(true);
+ return NS_OK;
+ }
NS_NOTREACHED("Unknown observer topic!");
return NS_OK;
}
RuntimeService::AutoSafeJSContext::AutoSafeJSContext(JSContext* aCx)
: mContext(aCx ? aCx : GetSafeContext())
{
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -228,16 +228,19 @@ public:
AssertIsOnMainThread();
sDefaultGCZeal = aGCZeal;
}
void
UpdateAllWorkerGCZeal();
#endif
+ void
+ GarbageCollectAllWorkers(bool aShrinking);
+
class AutoSafeJSContext
{
JSContext* mContext;
public:
AutoSafeJSContext(JSContext* aCx = nsnull);
~AutoSafeJSContext();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -53,16 +53,17 @@
#include "nsITextToSubURI.h"
#include "nsITimer.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIXPConnect.h"
#include "jsfriendapi.h"
#include "jsdbgapi.h"
+#include "jsfriendapi.h"
#include "jsprf.h"
#include "js/MemoryMetrics.h"
#include "nsAlgorithm.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsDOMJSUtils.h"
#include "nsGUIEvent.h"
@@ -86,16 +87,22 @@
#endif
#include "WorkerInlines.h"
#if 0 // Define to run GC more often.
#define EXTRA_GC
#endif
+// GC will run once every thirty seconds during normal execution.
+#define NORMAL_GC_TIMER_DELAY_MS 30000
+
+// GC will run five seconds after the last event is processed.
+#define IDLE_GC_TIMER_DELAY_MS 5000
+
using mozilla::MutexAutoLock;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
using mozilla::xpconnect::memory::ReportJSRuntimeStats;
USING_WORKERS_NAMESPACE
@@ -1413,16 +1420,53 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal);
return true;
}
};
#endif
+class GarbageCollectRunnable : public WorkerControlRunnable
+{
+protected:
+ bool mShrinking;
+ bool mCollectChildren;
+
+public:
+ GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
+ bool aCollectChildren)
+ : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
+ mShrinking(aShrinking), mCollectChildren(aCollectChildren)
+ { }
+
+ bool
+ PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ {
+ // Silence bad assertions, this can be dispatched from either the main
+ // thread or the timer thread..
+ return true;
+ }
+
+ void
+ PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult)
+ {
+ // Silence bad assertions, this can be dispatched from either the main
+ // thread or the timer thread..
+ }
+
+ bool
+ WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ {
+ aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren);
+ return true;
+ }
+};
+
class CollectRuntimeStatsRunnable : public WorkerControlRunnable
{
typedef mozilla::Mutex Mutex;
typedef mozilla::CondVar CondVar;
Mutex mMutex;
CondVar mCondVar;
volatile bool mDone;
@@ -2167,16 +2211,28 @@ WorkerPrivateParent<Derived>::UpdateGCZe
NS_WARNING("Failed to update worker gczeal!");
JS_ClearPendingException(aCx);
}
}
#endif
template <class Derived>
void
+WorkerPrivateParent<Derived>::GarbageCollect(JSContext* aCx, bool aShrinking)
+{
+ nsRefPtr<GarbageCollectRunnable> runnable =
+ new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking, true);
+ if (!runnable->Dispatch(aCx)) {
+ NS_WARNING("Failed to update worker heap size!");
+ JS_ClearPendingException(aCx);
+ }
+}
+
+template <class Derived>
+void
WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
{
AssertIsOnMainThread();
mBaseURI = aBaseURI;
if (NS_FAILED(aBaseURI->GetSpec(mLocationInfo.mHref))) {
mLocationInfo.mHref.Truncate();
@@ -2490,46 +2546,132 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
{
MutexAutoLock lock(mMutex);
mJSContext = aCx;
NS_ASSERTION(mStatus == Pending, "Huh?!");
mStatus = Running;
}
+ // We need a timer for GC. The basic plan is to run a normal (non-shrinking)
+ // GC periodically (NORMAL_GC_TIMER_DELAY_MS) while the worker is running.
+ // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_MS) timer to
+ // run a shrinking GC. If the worker receives more messages then the short
+ // timer is canceled and the periodic timer resumes.
+ nsCOMPtr<nsITimer> gcTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+ if (!gcTimer) {
+ JS_ReportError(aCx, "Failed to create GC timer!");
+ return;
+ }
+
+ bool normalGCTimerRunning = false;
+
+ // We need to swap event targets below to get different types of GC behavior.
+ nsCOMPtr<nsIEventTarget> normalGCEventTarget;
+ nsCOMPtr<nsIEventTarget> idleGCEventTarget;
+
+ // We also need to track the idle GC event so that we don't confuse it with a
+ // generic event that should re-trigger the idle GC timer.
+ nsCOMPtr<nsIRunnable> idleGCEvent;
+ {
+ nsRefPtr<GarbageCollectRunnable> runnable =
+ new GarbageCollectRunnable(this, false, false);
+ normalGCEventTarget = new WorkerRunnableEventTarget(runnable);
+
+ runnable = new GarbageCollectRunnable(this, true, false);
+ idleGCEventTarget = new WorkerRunnableEventTarget(runnable);
+
+ idleGCEvent = runnable;
+ }
+
mMemoryReporter = new WorkerMemoryReporter(this);
if (NS_FAILED(NS_RegisterMemoryMultiReporter(mMemoryReporter))) {
NS_WARNING("Failed to register memory reporter!");
mMemoryReporter = nsnull;
}
for (;;) {
Status currentStatus;
+ bool scheduleIdleGC;
+
nsIRunnable* event;
{
MutexAutoLock lock(mMutex);
while (!mControlQueue.Pop(event) && !mQueue.Pop(event)) {
mCondVar.Wait();
}
+ bool eventIsNotIdleGCEvent;
+ currentStatus = mStatus;
+
{
MutexAutoUnlock unlock(mMutex);
+ if (!normalGCTimerRunning &&
+ event != idleGCEvent &&
+ currentStatus <= Terminating) {
+ // Must always cancel before changing the timer's target.
+ if (NS_FAILED(gcTimer->Cancel())) {
+ NS_WARNING("Failed to cancel GC timer!");
+ }
+
+ if (NS_SUCCEEDED(gcTimer->SetTarget(normalGCEventTarget)) &&
+ NS_SUCCEEDED(gcTimer->InitWithFuncCallback(
+ DummyCallback, nsnull,
+ NORMAL_GC_TIMER_DELAY_MS,
+ nsITimer::TYPE_REPEATING_SLACK))) {
+ normalGCTimerRunning = true;
+ }
+ else {
+ JS_ReportError(aCx, "Failed to start normal GC timer!");
+ }
+ }
+
#ifdef EXTRA_GC
// Find GC bugs...
JS_GC(aCx);
#endif
+ // Keep track of whether or not this is the idle GC event.
+ eventIsNotIdleGCEvent = event != idleGCEvent;
+
event->Run();
NS_RELEASE(event);
}
currentStatus = mStatus;
+ scheduleIdleGC = mControlQueue.IsEmpty() &&
+ mQueue.IsEmpty() &&
+ eventIsNotIdleGCEvent;
+ }
+
+ // Take care of the GC timer. If we're starting the close sequence then we
+ // kill the timer once and for all. Otherwise we schedule the idle timeout
+ // if there are no more events.
+ if (currentStatus > Terminating || scheduleIdleGC) {
+ if (NS_SUCCEEDED(gcTimer->Cancel())) {
+ normalGCTimerRunning = false;
+ }
+ else {
+ NS_WARNING("Failed to cancel GC timer!");
+ }
+ }
+
+ if (scheduleIdleGC) {
+ if (NS_SUCCEEDED(gcTimer->SetTarget(idleGCEventTarget)) &&
+ NS_SUCCEEDED(gcTimer->InitWithFuncCallback(
+ DummyCallback, nsnull,
+ IDLE_GC_TIMER_DELAY_MS,
+ nsITimer::TYPE_ONE_SHOT))) {
+ }
+ else {
+ JS_ReportError(aCx, "Failed to start idle GC timer!");
+ }
}
#ifdef EXTRA_GC
// Find GC bugs...
JS_GC(aCx);
#endif
if (currentStatus != Running && !HasActiveFeatures()) {
@@ -2547,16 +2689,21 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
NS_ASSERTION(currentStatus == Killing, "Should have changed status!");
#else
currentStatus = Killing;
#endif
}
// If we're supposed to die then we should exit the loop.
if (currentStatus == Killing) {
+ // Always make sure the timer is canceled.
+ if (NS_FAILED(gcTimer->Cancel())) {
+ NS_WARNING("Failed to cancel the GC timer!");
+ }
+
// Call this before unregistering the reporter as we may be racing with
// the main thread.
DisableMemoryReporter();
if (mMemoryReporter) {
if (NS_FAILED(NS_UnregisterMemoryMultiReporter(mMemoryReporter))) {
NS_WARNING("Failed to unregister memory reporter!");
}
@@ -3635,16 +3782,36 @@ WorkerPrivate::UpdateGCZealInternal(JSCo
JS_SetGCZeal(aCx, aGCZeal, frequency, false);
for (PRUint32 index = 0; index < mChildWorkers.Length(); index++) {
mChildWorkers[index]->UpdateGCZeal(aCx, aGCZeal);
}
}
#endif
+void
+WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
+ bool aCollectChildren)
+{
+ AssertIsOnWorkerThread();
+
+ if (aShrinking) {
+ JS_ShrinkingGC(aCx);
+ }
+ else {
+ JS_GC(aCx);
+ }
+
+ if (aCollectChildren) {
+ for (PRUint32 index = 0; index < mChildWorkers.Length(); index++) {
+ mChildWorkers[index]->GarbageCollect(aCx, aShrinking);
+ }
+ }
+}
+
#ifdef DEBUG
template <class Derived>
void
WorkerPrivateParent<Derived>::AssertIsOnParentThread() const
{
if (GetParent()) {
GetParent()->AssertIsOnWorkerThread();
}
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -313,16 +313,19 @@ public:
void
UpdateJSRuntimeHeapSize(JSContext* aCx, PRUint32 aJSRuntimeHeapSize);
#ifdef JS_GC_ZEAL
void
UpdateGCZeal(JSContext* aCx, PRUint8 aGCZeal);
#endif
+ void
+ GarbageCollect(JSContext* aCx, bool aShrinking);
+
using events::EventTarget::GetEventListenerOnEventTarget;
using events::EventTarget::SetEventListenerOnEventTarget;
void
QueueRunnable(WorkerRunnable* aRunnable)
{
AssertIsOnMainThread();
mQueuedRunnables.AppendElement(aRunnable);
@@ -681,16 +684,20 @@ public:
bool
DisableMemoryReporter();
#ifdef JS_GC_ZEAL
void
UpdateGCZealInternal(JSContext* aCx, PRUint8 aGCZeal);
#endif
+ void
+ GarbageCollectInternal(JSContext* aCx, bool aShrinking,
+ bool aCollectChildren);
+
JSContext*
GetJSContext() const
{
AssertIsOnWorkerThread();
return mJSContext;
}
#ifdef DEBUG
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -312,16 +312,21 @@ private:
return false;
}
jsval adaptor;
if (!scope->GetEventListenerOnEventTarget(aCx, name + 2, &adaptor)) {
return false;
}
+ if (JSVAL_IS_VOID(adaptor)) {
+ *aVp = JSVAL_NULL;
+ return true;
+ }
+
JS_ASSERT(JSVAL_IS_OBJECT(adaptor));
jsval listener = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(adaptor),
SLOT_wrappedFunction);
*aVp = listener;
return true;
}
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -16,19 +16,23 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
+#ifdef MOZ_WEBSMS_BACKEND
<!-- WebSMS -->
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.WRITE_SMS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+#endif
<uses-feature android:name="android.hardware.location" android:required="false"/>
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -83,17 +83,16 @@ abstract public class GeckoApp
public static GeckoApp mAppContext;
public static boolean mFullscreen = false;
public static File sGREDir = null;
static Thread mLibLoadThread = null;
public Handler mMainHandler;
private IntentFilter mConnectivityFilter;
private BroadcastReceiver mConnectivityReceiver;
private BroadcastReceiver mBatteryReceiver;
- private BroadcastReceiver mSmsReceiver;
enum LaunchState {PreLaunch, Launching, WaitForDebugger,
Launched, GeckoRunning, GeckoExiting};
private static LaunchState sLaunchState = LaunchState.PreLaunch;
private static boolean sTryCatchAttached = false;
static boolean checkLaunchState(LaunchState checkState) {
@@ -409,20 +408,21 @@ abstract public class GeckoApp
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mConnectivityReceiver = new GeckoConnectivityReceiver();
IntentFilter batteryFilter = new IntentFilter();
batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
mBatteryReceiver = new GeckoBatteryManager();
registerReceiver(mBatteryReceiver, batteryFilter);
- IntentFilter smsFilter = new IntentFilter();
- smsFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
- mSmsReceiver = new GeckoSmsManager();
- registerReceiver(mSmsReceiver, smsFilter);
+ if (SmsManager.getInstance() != null) {
+ SmsManager.getInstance().init();
+ }
+
+ GeckoNetworkManager.getInstance().init();
if (!checkAndSetLaunchState(LaunchState.PreLaunch,
LaunchState.Launching))
return;
checkAndLaunchUpdate();
mLibLoadThread = new Thread(new Runnable() {
public void run() {
@@ -506,16 +506,17 @@ abstract public class GeckoApp
// Whatever we do here should be fast, because we're blocking
// the next activity from showing up until we finish.
// onPause will be followed by either onResume or onStop.
super.onPause();
unregisterReceiver(mConnectivityReceiver);
+ GeckoNetworkManager.getInstance().stop();
}
@Override
public void onResume()
{
Log.i(LOG_FILE_NAME, "resume");
if (checkLaunchState(LaunchState.GeckoRunning))
GeckoAppShell.onResume();
@@ -524,16 +525,17 @@ abstract public class GeckoApp
super.onResume();
// Just in case. Normally we start in onNewIntent
if (checkLaunchState(LaunchState.PreLaunch) ||
checkLaunchState(LaunchState.Launching))
onNewIntent(getIntent());
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
+ GeckoNetworkManager.getInstance().start();
}
@Override
public void onStop()
{
Log.i(LOG_FILE_NAME, "stop");
// We're about to be stopped, potentially in preparation for
// being destroyed. We're killable after this point -- as I
@@ -572,19 +574,24 @@ abstract public class GeckoApp
{
Log.i(LOG_FILE_NAME, "destroy");
// Tell Gecko to shutting down; we'll end up calling System.exit()
// in onXreExit.
if (isFinishing())
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN));
+ if (SmsManager.getInstance() != null) {
+ SmsManager.getInstance().shutdown();
+ }
+
+ GeckoNetworkManager.getInstance().stop();
+
super.onDestroy();
- unregisterReceiver(mSmsReceiver);
unregisterReceiver(mBatteryReceiver);
}
@Override
public void onConfigurationChanged(android.content.res.Configuration newConfig)
{
Log.i(LOG_FILE_NAME, "configuration changed");
// nothing, just ignore
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -117,16 +117,28 @@ public class GeckoAppShell
public static native void onChangeNetworkLinkStatus(String status);
public static native void reportJavaCrash(String stack);
public static native void processNextNativeEvent();
public static native void notifyBatteryChange(double aLevel, boolean aCharging, double aRemainingTime);
public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp);
+ public static native int saveMessageInSentbox(String aReceiver, String aBody, long aTimestamp);
+ public static native void notifySmsSent(int aId, String aReceiver, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+ public static native void notifySmsDelivered(int aId, String aReceiver, String aBody, long aTimestamp);
+ public static native void notifySmsSendFailed(int aError, int aRequestId, long aProcessId);
+ public static native void notifyGetSms(int aId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+ public static native void notifyGetSmsFailed(int aError, int aRequestId, long aProcessId);
+ public static native void notifySmsDeleted(boolean aDeleted, int aRequestId, long aProcessId);
+ public static native void notifySmsDeleteFailed(int aError, int aRequestId, long aProcessId);
+ public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
+ public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+ public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+ public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
// A looper thread, accessed by GeckoAppShell.getHandler
private static class LooperThread extends Thread {
public SynchronousQueue<Handler> mHandlerQueue =
new SynchronousQueue<Handler>();
public void run() {
Looper.prepare();
@@ -1684,28 +1696,96 @@ public class GeckoAppShell
public static double[] getCurrentBatteryInformation() {
return GeckoBatteryManager.getCurrentInformation();
}
/*
* WebSMS related methods.
*/
public static int getNumberOfMessagesForText(String aText) {
- return GeckoSmsManager.getNumberOfMessagesForText(aText);
+ if (SmsManager.getInstance() == null) {
+ return 0;
+ }
+
+ return SmsManager.getInstance().getNumberOfMessagesForText(aText);
+ }
+
+ public static void sendMessage(String aNumber, String aMessage, int aRequestId, long aProcessId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().send(aNumber, aMessage, aRequestId, aProcessId);
+ }
+
+ public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
+ if (SmsManager.getInstance() == null) {
+ return -1;
+ }
+
+ return SmsManager.getInstance().saveSentMessage(aRecipient, aBody, aDate);
+ }
+
+ public static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().getMessage(aMessageId, aRequestId, aProcessId);
}
- public static void sendMessage(String aNumber, String aMessage) {
- GeckoSmsManager.send(aNumber, aMessage);
+ public static void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().deleteMessage(aMessageId, aRequestId, aProcessId);
+ }
+
+ public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId);
+ }
+
+ public static void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().getNextMessageInList(aListId, aRequestId, aProcessId);
+ }
+
+ public static void clearMessageList(int aListId) {
+ if (SmsManager.getInstance() == null) {
+ return;
+ }
+
+ SmsManager.getInstance().clearMessageList(aListId);
}
public static boolean isTablet() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
Configuration config = GeckoApp.mAppContext.getResources().getConfiguration();
// xlarge is defined by android as screens larger than 960dp x 720dp
// and should include most devices ~7in and up.
// http://developer.android.com/guide/practices/screens_support.html
if ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE) {
return true;
}
}
return false;
}
+
+ public static double[] getCurrentNetworkInformation() {
+ return GeckoNetworkManager.getInstance().getCurrentInformation();
+ }
+
+ public static void enableNetworkNotifications() {
+ GeckoNetworkManager.getInstance().enableNotifications();
+ }
+
+ public static void disableNetworkNotifications() {
+ GeckoNetworkManager.getInstance().disableNotifications();
+ }
}
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -70,16 +70,20 @@ public class GeckoEvent {
public static final int ACTIVITY_SHUTDOWN = 11;
public static final int LOAD_URI = 12;
public static final int SURFACE_CREATED = 13;
public static final int SURFACE_DESTROYED = 14;
public static final int GECKO_EVENT_SYNC = 15;
public static final int ACTIVITY_START = 17;
public static final int SAVE_STATE = 18;
public static final int BROADCAST = 19;
+ public static final int VIEWPORT = 20;
+ public static final int TILE_SIZE = 21;
+ public static final int VISTITED = 22;
+ public static final int NETWORK_CHANGED = 23;
public static final int IME_COMPOSITION_END = 0;
public static final int IME_COMPOSITION_BEGIN = 1;
public static final int IME_SET_TEXT = 2;
public static final int IME_GET_TEXT = 3;
public static final int IME_DELETE_TEXT = 4;
public static final int IME_SET_SELECTION = 5;
public static final int IME_GET_SELECTION = 6;
@@ -107,16 +111,19 @@ public class GeckoEvent {
public int mKeyCode, mUnicodeChar;
public int mOffset, mCount;
public String mCharacters, mCharactersExtra;
public int mRangeType, mRangeStyles;
public int mRangeForeColor, mRangeBackColor;
public Location mLocation;
public Address mAddress;
+ public double mBandwidth;
+ public boolean mCanBeMetered;
+
public int mNativeWindow;
public GeckoEvent() {
mType = NATIVE_POKE;
}
public GeckoEvent(int evType) {
mType = evType;
@@ -230,9 +237,15 @@ public class GeckoEvent {
mCharacters = subject;
mCharactersExtra = data;
}
public GeckoEvent(String uri) {
mType = LOAD_URI;
mCharacters = uri;
}
+
+ public GeckoEvent(double bandwidth, boolean canBeMetered) {
+ mType = NETWORK_CHANGED;
+ mBandwidth = bandwidth;
+ mCanBeMetered = canBeMetered;
+ }
}
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoNetworkManager.java
@@ -0,0 +1,323 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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 ***** */
+
+package org.mozilla.gecko;
+
+import java.lang.Math;
+
+import android.util.Log;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import android.telephony.TelephonyManager;
+
+/*
+ * A part of the work of GeckoNetworkManager is to give an estimation of the
+ * download speed of the current connection. For known to be fast connection, we
+ * simply use a predefined value (we don't care about being precise). For mobile
+ * connections, we sort them in groups (generations) and estimate the average
+ * real life download speed of that specific generation. This value comes from
+ * researches (eg. Wikipedia articles) or is simply an arbitrary estimation.
+ * Precision isn't important, we mostly need an order of magnitude.
+ *
+ * Each group is composed with networks represented by the constant from
+ * Android's ConnectivityManager and the description comming from the same
+ * class.
+ *
+ * 2G (15 bk/s):
+ * int NETWORK_TYPE_IDEN Current network is iDen
+ * int NETWORK_TYPE_CDMA Current network is CDMA: Either IS95A or IS95B
+ *
+ * 2.5G (60 kb/s)
+ * int NETWORK_TYPE_GPRS Current network is GPRS
+ * int NETWORK_TYPE_1xRTT Current network is 1xRTT
+ *
+ * 2.75G (200 kb/s)
+ * int NETWORK_TYPE_EDGE Current network is EDGE
+ *
+ * 3G (300 kb/s)
+ * int NETWORK_TYPE_UMTS Current network is UMTS
+ * int NETWORK_TYPE_EVDO_0 Current network is EVDO revision 0
+ *
+ * 3.5G (7 Mb/s)
+ * int NETWORK_TYPE_HSPA Current network is HSPA
+ * int NETWORK_TYPE_HSDPA Current network is HSDPA
+ * int NETWORK_TYPE_HSUPA Current network is HSUPA
+ * int NETWORK_TYPE_EVDO_A Current network is EVDO revision A
+ * int NETWORK_TYPE_EVDO_B Current network is EVDO revision B
+ * int NETWORK_TYPE_EHRPD Current network is eHRPD
+ *
+ * 3.75G (20 Mb/s)
+ * int NETWORK_TYPE_HSPAP Current network is HSPA+
+ *
+ * 3.9G (50 Mb/s)
+ * int NETWORK_TYPE_LTE Current network is LTE
+ */
+
+public class GeckoNetworkManager
+ extends BroadcastReceiver
+{
+ static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
+
+ static private final double kDefaultBandwidth = -1.0;
+ static private final boolean kDefaultCanBeMetered = false;
+
+ static private final double kMaxBandwidth = 20.0;
+
+ static private final double kNetworkSpeedEthernet = 20.0; // 20 Mb/s
+ static private final double kNetworkSpeedWifi = 20.0; // 20 Mb/s
+ static private final double kNetworkSpeedWiMax = 40.0; // 40 Mb/s
+ static private final double kNetworkSpeed_2_G = 15.0 / 1024.0; // 15 kb/s
+ static private final double kNetworkSpeed_2_5_G = 60.0 / 1024.0; // 60 kb/s
+ static private final double kNetworkSpeed_2_75_G = 200.0 / 1024.0; // 200 kb/s
+ static private final double kNetworkSpeed_3_G = 300.0 / 1024.0; // 300 kb/s
+ static private final double kNetworkSpeed_3_5_G = 7.0; // 7 Mb/s
+ static private final double kNetworkSpeed_3_75_G = 20.0; // 20 Mb/s
+ static private final double kNetworkSpeed_3_9_G = 50.0; // 50 Mb/s
+
+ private enum NetworkType {
+ NETWORK_NONE,
+ NETWORK_ETHERNET,
+ NETWORK_WIFI,
+ NETWORK_WIMAX,
+ NETWORK_2_G, // 2G
+ NETWORK_2_5_G, // 2.5G
+ NETWORK_2_75_G, // 2.75G
+ NETWORK_3_G, // 3G
+ NETWORK_3_5_G, // 3.5G
+ NETWORK_3_75_G, // 3.75G
+ NETWORK_3_9_G, // 3.9G
+ NETWORK_UNKNOWN
+ }
+
+ private NetworkType mNetworkType = NetworkType.NETWORK_NONE;
+ private IntentFilter mNetworkFilter = new IntentFilter();
+ // Whether the manager should be listening to Network Information changes.
+ private boolean mShouldBeListening = false;
+ // Whether the manager should notify Gecko that a change in Network
+ // Information happened.
+ private boolean mShouldNotify = false;
+
+ public static GeckoNetworkManager getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public void onReceive(Context aContext, Intent aIntent) {
+ updateNetworkType();
+ }
+
+ public void init() {
+ mNetworkFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+
+ mNetworkType = getNetworkType();
+ }
+
+ public void start() {
+ mShouldBeListening = true;
+ updateNetworkType();
+
+ if (mShouldNotify) {
+ startListening();
+ }
+ }
+
+ private void startListening() {
+ GeckoApp.mAppContext.registerReceiver(sInstance, mNetworkFilter);
+ }
+
+ public void stop() {
+ mShouldBeListening = false;
+
+ if (mShouldNotify) {
+ stopListening();
+ }
+ }
+
+ private void stopListening() {
+ GeckoApp.mAppContext.unregisterReceiver(sInstance);
+ }
+
+ private void updateNetworkType() {
+ NetworkType previousNetworkType = mNetworkType;
+ mNetworkType = getNetworkType();
+
+ if (mNetworkType == previousNetworkType || !mShouldNotify) {
+ return;
+ }
+
+ GeckoAppShell.sendEventToGecko(new GeckoEvent(getNetworkSpeed(mNetworkType),
+ isNetworkUsuallyMetered(mNetworkType)));
+ }
+
+ public double[] getCurrentInformation() {
+ return new double[] { getNetworkSpeed(mNetworkType),
+ isNetworkUsuallyMetered(mNetworkType) ? 1.0 : 0.0 };
+ }
+
+ public void enableNotifications() {
+ // We set mShouldNotify *after* calling updateNetworkType() to make sure we
+ // don't notify an eventual change in mNetworkType.
+ updateNetworkType();
+ mShouldNotify = true;
+
+ if (mShouldBeListening) {
+ startListening();
+ }
+ }
+
+ public void disableNotifications() {
+ mShouldNotify = false;
+
+ if (mShouldBeListening) {
+ stopListening();
+ }
+ }
+
+ private static NetworkType getNetworkType() {
+ ConnectivityManager cm =
+ (ConnectivityManager)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (cm.getActiveNetworkInfo() == null) {
+ return NetworkType.NETWORK_NONE;
+ }
+
+ switch (cm.getActiveNetworkInfo().getType()) {
+ case ConnectivityManager.TYPE_ETHERNET:
+ return NetworkType.NETWORK_ETHERNET;
+ case ConnectivityManager.TYPE_WIFI:
+ return NetworkType.NETWORK_WIFI;
+ case ConnectivityManager.TYPE_WIMAX:
+ return NetworkType.NETWORK_WIMAX;
+ case ConnectivityManager.TYPE_MOBILE:
+ break; // We will handle sub-types after the switch.
+ default:
+ Log.w("GeckoNetworkManager", "Ignoring the current network type.");
+ return NetworkType.NETWORK_UNKNOWN;
+ }
+
+ TelephonyManager tm =
+ (TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+ switch (tm.getNetworkType()) {
+ case TelephonyManager.NETWORK_TYPE_IDEN:
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ return NetworkType.NETWORK_2_G;
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ return NetworkType.NETWORK_2_5_G;
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ return NetworkType.NETWORK_2_75_G;
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:
+ return NetworkType.NETWORK_3_G;
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ return NetworkType.NETWORK_3_5_G;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ return NetworkType.NETWORK_3_75_G;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ return NetworkType.NETWORK_3_9_G;
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ default:
+ Log.w("GeckoNetworkManager", "Connected to an unknown mobile network!");
+ return NetworkType.NETWORK_UNKNOWN;
+ }
+ }
+
+ private static double getNetworkSpeed(NetworkType aType) {
+ switch (aType) {
+ case NETWORK_NONE:
+ return 0.0;
+ case NETWORK_ETHERNET:
+ return kNetworkSpeedEthernet;
+ case NETWORK_WIFI:
+ return kNetworkSpeedWifi;
+ case NETWORK_WIMAX:
+ return kNetworkSpeedWiMax;
+ case NETWORK_2_G:
+ return kNetworkSpeed_2_G;
+ case NETWORK_2_5_G:
+ return kNetworkSpeed_2_5_G;
+ case NETWORK_2_75_G:
+ return kNetworkSpeed_2_75_G;
+ case NETWORK_3_G:
+ return kNetworkSpeed_3_G;
+ case NETWORK_3_5_G:
+ return kNetworkSpeed_3_5_G;
+ case NETWORK_3_75_G:
+ return kNetworkSpeed_3_75_G;
+ case NETWORK_3_9_G:
+ return kNetworkSpeed_3_9_G;
+ case NETWORK_UNKNOWN:
+ default:
+ return kDefaultBandwidth;
+ }
+ }
+
+ private static boolean isNetworkUsuallyMetered(NetworkType aType) {
+ switch (aType) {
+ case NETWORK_NONE:
+ case NETWORK_UNKNOWN:
+ case NETWORK_ETHERNET:
+ case NETWORK_WIFI:
+ case NETWORK_WIMAX:
+ return false;
+ case NETWORK_2_G:
+ case NETWORK_2_5_G:
+ case NETWORK_2_75_G:
+ case NETWORK_3_G:
+ case NETWORK_3_5_G:
+ case NETWORK_3_75_G:
+ case NETWORK_3_9_G:
+ return true;
+ default:
+ Log.e("GeckoNetworkManager", "Got an unexpected network type!");
+ return false;
+ }
+ }
+}
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -33,36 +33,348 @@
* 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 ***** */
package org.mozilla.gecko;
import java.util.ArrayList;
+import java.util.Iterator;
import android.util.Log;
+import android.app.PendingIntent;
+import android.app.Activity;
+
+import android.database.Cursor;
+
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.ContentUris;
+
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
+/**
+ * This class is returning unique ids for PendingIntent requestCode attribute.
+ * There are only |Integer.MAX_VALUE - Integer.MIN_VALUE| unique IDs available,
+ * and they wrap around.
+ */
+class PendingIntentUID
+{
+ static private int sUID = Integer.MIN_VALUE;
+
+ static public int generate() { return sUID++; }
+}
+
+/**
+ * The envelope class contains all information that are needed to keep track of
+ * a sent SMS.
+ */
+class Envelope
+{
+ enum SubParts {
+ SENT_PART,
+ DELIVERED_PART
+ }
+
+ protected int mId;
+ protected int mMessageId;
+ protected long mMessageTimestamp;
+
+ /**
+ * Number of sent/delivered remaining parts.
+ * @note The array has much slots as SubParts items.
+ */
+ protected int[] mRemainingParts;
+
+ /**
+ * Whether sending/delivering is currently failing.
+ * @note The array has much slots as SubParts items.
+ */
+ protected boolean[] mFailing;
+
+ /**
+ * Error type (only for sent).
+ */
+ protected int mError;
+
+ public Envelope(int aId, int aParts) {
+ mId = aId;
+ mMessageId = -1;
+ mMessageTimestamp = 0;
+ mError = GeckoSmsManager.kNoError;
+
+ int size = Envelope.SubParts.values().length;
+ mRemainingParts = new int[size];
+ mFailing = new boolean[size];
+
+ for (int i=0; i<size; ++i) {
+ mRemainingParts[i] = aParts;
+ mFailing[i] = false;
+ }
+ }
+
+ public void decreaseRemainingParts(Envelope.SubParts aType) {
+ --mRemainingParts[aType.ordinal()];
+
+ if (mRemainingParts[SubParts.SENT_PART.ordinal()] >
+ mRemainingParts[SubParts.DELIVERED_PART.ordinal()]) {
+ Log.e("GeckoSmsManager", "Delivered more parts than we sent!?");
+ }
+ }
+
+ public boolean arePartsRemaining(Envelope.SubParts aType) {
+ return mRemainingParts[aType.ordinal()] != 0;
+ }
+
+ public void markAsFailed(Envelope.SubParts aType) {
+ mFailing[aType.ordinal()] = true;
+ }
+
+ public boolean isFailing(Envelope.SubParts aType) {
+ return mFailing[aType.ordinal()];
+ }
+
+ public int getMessageId() {
+ return mMessageId;
+ }
+
+ public void setMessageId(int aMessageId) {
+ mMessageId = aMessageId;
+ }
+
+ public long getMessageTimestamp() {
+ return mMessageTimestamp;
+ }
+
+ public void setMessageTimestamp(long aMessageTimestamp) {
+ mMessageTimestamp = aMessageTimestamp;
+ }
+
+ public int getError() {
+ return mError;
+ }
+
+ public void setError(int aError) {
+ mError = aError;
+ }
+}
+
+/**
+ * Postman class is a singleton that manages Envelope instances.
+ */
+class Postman
+{
+ public static final int kUnknownEnvelopeId = -1;
+
+ private static final Postman sInstance = new Postman();
+
+ private ArrayList<Envelope> mEnvelopes = new ArrayList<Envelope>(1);
+
+ private Postman() {}
+
+ public static Postman getInstance() {
+ return sInstance;
+ }
+
+ public int createEnvelope(int aParts) {
+ /*
+ * We are going to create the envelope in the first empty slot in the array
+ * list. If there is no empty slot, we create a new one.
+ */
+ int size = mEnvelopes.size();
+
+ for (int i=0; i<size; ++i) {
+ if (mEnvelopes.get(i) == null) {
+ mEnvelopes.set(i, new Envelope(i, aParts));
+ return i;
+ }
+ }
+
+ mEnvelopes.add(new Envelope(size, aParts));
+ return size;
+ }
+
+ public Envelope getEnvelope(int aId) {
+ if (aId < 0 || mEnvelopes.size() <= aId) {
+ Log.e("GeckoSmsManager", "Trying to get an unknown Envelope!");
+ return null;
+ }
+
+ Envelope envelope = mEnvelopes.get(aId);
+ if (envelope == null) {
+ Log.e("GeckoSmsManager", "Trying to get an empty Envelope!");
+ }
+
+ return envelope;
+ }
+
+ public void destroyEnvelope(int aId) {
+ if (aId < 0 || mEnvelopes.size() <= aId) {
+ Log.e("GeckoSmsManager", "Trying to destroy an unknown Envelope!");
+ return;
+ }
+
+ if (mEnvelopes.set(aId, null) == null) {
+ Log.e("GeckoSmsManager", "Trying to destroy an empty Envelope!");
+ }
+ }
+}
+
+class SmsIOThread extends Thread {
+ private final static SmsIOThread sInstance = new SmsIOThread();
+
+ private Handler mHandler;
+
+ public static SmsIOThread getInstance() {
+ return sInstance;
+ }
+
+ public boolean execute(Runnable r) {
+ return mHandler.post(r);
+ }
+
+ public void run() {
+ Looper.prepare();
+
+ mHandler = new Handler();
+
+ Looper.loop();
+ }
+}
+
+class MessagesListManager
+{
+ private static final MessagesListManager sInstance = new MessagesListManager();
+
+ public static MessagesListManager getInstance() {
+ return sInstance;
+ }
+
+ private ArrayList<Cursor> mCursors = new ArrayList<Cursor>(0);
+
+ public int add(Cursor aCursor) {
+ int size = mCursors.size();
+
+ for (int i=0; i<size; ++i) {
+ if (mCursors.get(i) == null) {
+ mCursors.set(i, aCursor);
+ return i;
+ }
+ }
+
+ mCursors.add(aCursor);
+ return size;
+ }
+
+ public Cursor get(int aId) {
+ if (aId < 0 || mCursors.size() <= aId) {
+ Log.e("GeckoSmsManager", "Trying to get an unknown list!");
+ return null;
+ }
+
+ Cursor cursor = mCursors.get(aId);
+ if (cursor == null) {
+ Log.e("GeckoSmsManager", "Trying to get an empty list!");
+ }
+
+ return cursor;
+ }
+
+ public void remove(int aId) {
+ if (aId < 0 || mCursors.size() <= aId) {
+ Log.e("GeckoSmsManager", "Trying to destroy an unknown list!");
+ return;
+ }
+
+ Cursor cursor = mCursors.set(aId, null);
+ if (cursor == null) {
+ Log.e("GeckoSmsManager", "Trying to destroy an empty list!");
+ return;
+ }
+
+ cursor.close();
+ }
+
+ public void clear() {
+ for (int i=0; i<mCursors.size(); ++i) {
+ Cursor c = mCursors.get(i);
+ if (c != null) {
+ c.close();
+ }
+ }
+
+ mCursors.clear();
+ }
+}
+
public class GeckoSmsManager
extends BroadcastReceiver
+ implements ISmsManager
{
- final static int kMaxMessageSize = 160;
+ public final static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
+ public final static String ACTION_SMS_SENT = "org.mozilla.gecko.SMS_SENT";
+ public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
+
+ /*
+ * Make sure that the following error codes are in sync with |ErrorType| in:
+ * dom/sms/src/Types.h
+ * The error code are owned by the DOM.
+ */
+ public final static int kNoError = 0;
+ public final static int kNoSignalError = 1;
+ public final static int kNotFoundError = 2;
+ public final static int kUnknownError = 3;
+ public final static int kInternalError = 4;
+
+ private final static int kMaxMessageSize = 160;
+
+ private final static Uri kSmsContentUri = Uri.parse("content://sms");
+ private final static Uri kSmsSentContentUri = Uri.parse("content://sms/sent");
+
+ private final static int kSmsTypeInbox = 1;
+ private final static int kSmsTypeSentbox = 2;
+
+ /*
+ * Keep the following error codes in syng with |DeliveryState| in:
+ * dom/sms/src/Types.h
+ */
+ private final static int kDeliveryStateSent = 0;
+ private final static int kDeliveryStateReceived = 1;
+ private final static int kDeliveryStateUnknown = 2;
+ private final static int kDeliveryStateEndGuard = 3;
+
+ private final static String[] kRequiredMessageRows = new String[] { "_id", "address", "body", "date", "type" };
+
+ public void init() {
+ IntentFilter smsFilter = new IntentFilter();
+ smsFilter.addAction(GeckoSmsManager.ACTION_SMS_RECEIVED);
+ smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
+ smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
+
+ GeckoApp.mAppContext.registerReceiver(this, smsFilter);
+
+ SmsIOThread.getInstance().start();
+ }
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
+ if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
// TODO: Try to find the receiver number to be able to populate
// SmsMessage.receiver.
// TODO: Get the id and the date from the stock app saved message.
// Using the stock app saved message require us to wait for it to
// be saved which can lead to race conditions.
Bundle bundle = intent.getExtras();
@@ -74,35 +386,549 @@ public class GeckoSmsManager
for (int i=0; i<pdus.length; ++i) {
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdus[i]);
GeckoAppShell.notifySmsReceived(msg.getDisplayOriginatingAddress(),
msg.getDisplayMessageBody(),
System.currentTimeMillis());
}
+
+ return;
+ }
+
+ if (intent.getAction().equals(ACTION_SMS_SENT) ||
+ intent.getAction().equals(ACTION_SMS_DELIVERED)) {
+ Bundle bundle = intent.getExtras();
+
+ if (bundle == null || !bundle.containsKey("envelopeId") ||
+ !bundle.containsKey("number") || !bundle.containsKey("message") ||
+ !bundle.containsKey("requestId") || !bundle.containsKey("processId")) {
+ Log.e("GeckoSmsManager", "Got an invalid ACTION_SMS_SENT/ACTION_SMS_DELIVERED!");
+ return;
+ }
+
+ int envelopeId = bundle.getInt("envelopeId");
+ Postman postman = Postman.getInstance();
+
+ Envelope envelope = postman.getEnvelope(envelopeId);
+ if (envelope == null) {
+ Log.e("GeckoSmsManager", "Got an invalid envelope id (or Envelope has been destroyed)!");
+ return;
+ }
+
+ Envelope.SubParts part = intent.getAction().equals(ACTION_SMS_SENT)
+ ? Envelope.SubParts.SENT_PART
+ : Envelope.SubParts.DELIVERED_PART;
+ envelope.decreaseRemainingParts(part);
+
+
+ if (getResultCode() != Activity.RESULT_OK) {
+ switch (getResultCode()) {
+ case SmsManager.RESULT_ERROR_NULL_PDU:
+ envelope.setError(kInternalError);
+ break;
+ case SmsManager.RESULT_ERROR_NO_SERVICE:
+ case SmsManager.RESULT_ERROR_RADIO_OFF:
+ envelope.setError(kNoSignalError);
+ break;
+ case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+ default:
+ envelope.setError(kUnknownError);
+ break;
+ }
+ envelope.markAsFailed(part);
+ Log.i("GeckoSmsManager", "SMS part sending failed!");
+ }
+
+ if (envelope.arePartsRemaining(part)) {
+ return;
+ }
+
+ if (envelope.isFailing(part)) {
+ if (part == Envelope.SubParts.SENT_PART) {
+ GeckoAppShell.notifySmsSendFailed(envelope.getError(),
+ bundle.getInt("requestId"),
+ bundle.getLong("processId"));
+ Log.i("GeckoSmsManager", "SMS sending failed!");
+ } else {
+ // It seems unlikely to get a result code for a failure to deliver.
+ // Even if, we don't want to do anything with this.
+ Log.e("GeckoSmsManager", "SMS failed to be delivered... is that even possible?");
+ }
+ } else {
+ if (part == Envelope.SubParts.SENT_PART) {
+ String number = bundle.getString("number");
+ String message = bundle.getString("message");
+ long timestamp = System.currentTimeMillis();
+
+ int id = GeckoAppShell.saveMessageInSentbox(number, message, timestamp);
+
+ GeckoAppShell.notifySmsSent(id, number, message, timestamp,
+ bundle.getInt("requestId"),
+ bundle.getLong("processId"));
+
+ envelope.setMessageId(id);
+ envelope.setMessageTimestamp(timestamp);
+
+ Log.i("GeckoSmsManager", "SMS sending was successfull!");
+ } else {
+ GeckoAppShell.notifySmsDelivered(envelope.getMessageId(),
+ bundle.getString("number"),
+ bundle.getString("message"),
+ envelope.getMessageTimestamp());
+ Log.i("GeckoSmsManager", "SMS succesfully delivered!");
+ }
+ }
+
+ // Destroy the envelope object only if the SMS has been sent and delivered.
+ if (!envelope.arePartsRemaining(Envelope.SubParts.SENT_PART) &&
+ !envelope.arePartsRemaining(Envelope.SubParts.DELIVERED_PART)) {
+ postman.destroyEnvelope(envelopeId);
+ }
+
+ return;
}
}
- public static int getNumberOfMessagesForText(String aText) {
+ public int getNumberOfMessagesForText(String aText) {
return SmsManager.getDefault().divideMessage(aText).size();
}
- public static void send(String aNumber, String aMessage) {
- /*
- * TODO:
- * This is a basic send method that doesn't handle errors, doesn't listen to
- * sent and received messages. It's only calling the send method.
- */
+ public void send(String aNumber, String aMessage, int aRequestId, long aProcessId) {
+ int envelopeId = Postman.kUnknownEnvelopeId;
+
try {
SmsManager sm = SmsManager.getDefault();
+ Intent sentIntent = new Intent(ACTION_SMS_SENT);
+ Intent deliveredIntent = new Intent(ACTION_SMS_DELIVERED);
+
+ Bundle bundle = new Bundle();
+ bundle.putString("number", aNumber);
+ bundle.putString("message", aMessage);
+ bundle.putInt("requestId", aRequestId);
+ bundle.putLong("processId", aProcessId);
+
if (aMessage.length() <= kMaxMessageSize) {
- sm.sendTextMessage(aNumber, "", aMessage, null, null);
+ envelopeId = Postman.getInstance().createEnvelope(1);
+ bundle.putInt("envelopeId", envelopeId);
+
+ sentIntent.putExtras(bundle);
+ deliveredIntent.putExtras(bundle);
+
+ /*
+ * There are a few things to know about getBroadcast and pending intents:
+ * - the pending intents are in a shared pool maintained by the system;
+ * - each pending intent is identified by a token;
+ * - when a new pending intent is created, if it has the same token as
+ * another intent in the pool, one of them has to be removed.
+ *
+ * To prevent having a hard time because of this situation, we give a
+ * unique id to all pending intents we are creating. This unique id is
+ * generated by GetPendingIntentUID().
+ */
+ PendingIntent sentPendingIntent =
+ PendingIntent.getBroadcast(GeckoApp.mAppContext,
+ PendingIntentUID.generate(), sentIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+
+ PendingIntent deliveredPendingIntent =
+ PendingIntent.getBroadcast(GeckoApp.mAppContext,
+ PendingIntentUID.generate(), deliveredIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+
+ sm.sendTextMessage(aNumber, "", aMessage,
+ sentPendingIntent, deliveredPendingIntent);
} else {
ArrayList<String> parts = sm.divideMessage(aMessage);
- sm.sendMultipartTextMessage(aNumber, "", parts, null, null);
+ envelopeId = Postman.getInstance().createEnvelope(parts.size());
+ bundle.putInt("envelopeId", envelopeId);
+
+ sentIntent.putExtras(bundle);
+ deliveredIntent.putExtras(bundle);
+
+ ArrayList<PendingIntent> sentPendingIntents =
+ new ArrayList<PendingIntent>(parts.size());
+ ArrayList<PendingIntent> deliveredPendingIntents =
+ new ArrayList<PendingIntent>(parts.size());
+
+ for (int i=0; i<parts.size(); ++i) {
+ sentPendingIntents.add(
+ PendingIntent.getBroadcast(GeckoApp.mAppContext,
+ PendingIntentUID.generate(), sentIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT)
+ );
+
+ deliveredPendingIntents.add(
+ PendingIntent.getBroadcast(GeckoApp.mAppContext,
+ PendingIntentUID.generate(), deliveredIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT)
+ );
+ }
+
+ sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
+ deliveredPendingIntents);
}
} catch (Exception e) {
- Log.i("GeckoSmsManager", "Failed to send an SMS: ", e);
+ Log.e("GeckoSmsManager", "Failed to send an SMS: ", e);
+
+ if (envelopeId != Postman.kUnknownEnvelopeId) {
+ Postman.getInstance().destroyEnvelope(envelopeId);
+ }
+
+ GeckoAppShell.notifySmsSendFailed(kUnknownError, aRequestId, aProcessId);
+ }
+ }
+
+ public int saveSentMessage(String aRecipient, String aBody, long aDate) {
+ class IdTooHighException extends Exception { }
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put("address", aRecipient);
+ values.put("body", aBody);
+ values.put("date", aDate);
+
+ ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+ Uri uri = cr.insert(kSmsSentContentUri, values);
+
+ long id = ContentUris.parseId(uri);
+
+ // The DOM API takes a 32bits unsigned int for the id. It's unlikely that
+ // we happen to need more than that but it doesn't cost to check.
+ if (id > Integer.MAX_VALUE) {
+ throw new IdTooHighException();
+ }
+
+ return (int)id;
+ } catch (IdTooHighException e) {
+ Log.e("GeckoSmsManager", "The id we received is higher than the higher allowed value.");
+ return -1;
+ } catch (Exception e) {
+ Log.e("GeckoSmsManager", "Something went wrong when trying to write a sent message: " + e);
+ return -1;
+ }
+ }
+
+ public void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+ class GetMessageRunnable implements Runnable {
+ private int mMessageId;
+ private int mRequestId;
+ private long mProcessId;
+
+ GetMessageRunnable(int aMessageId, int aRequestId, long aProcessId) {
+ mMessageId = aMessageId;
+ mRequestId = aRequestId;
+ mProcessId = aProcessId;
+ }
+
+ @Override
+ public void run() {
+ class NotFoundException extends Exception { }
+ class UnmatchingIdException extends Exception { }
+ class TooManyResultsException extends Exception { }
+ class InvalidTypeException extends Exception { }
+
+ Cursor cursor = null;
+
+ try {
+ ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+ Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
+
+ cursor = cr.query(message, kRequiredMessageRows, null, null, null);
+ if (cursor == null || cursor.getCount() == 0) {
+ throw new NotFoundException();
+ }
+
+ if (cursor.getCount() != 1) {
+ throw new TooManyResultsException();
+ }
+
+ cursor.moveToFirst();
+
+ if (cursor.getInt(cursor.getColumnIndex("_id")) != mMessageId) {
+ throw new UnmatchingIdException();
+ }
+
+ int type = cursor.getInt(cursor.getColumnIndex("type"));
+ String sender = "";
+ String receiver = "";
+
+ if (type == kSmsTypeInbox) {
+ sender = cursor.getString(cursor.getColumnIndex("address"));
+ } else if (type == kSmsTypeSentbox) {
+ receiver = cursor.getString(cursor.getColumnIndex("address"));
+ } else {
+ throw new InvalidTypeException();
+ }
+
+ GeckoAppShell.notifyGetSms(cursor.getInt(cursor.getColumnIndex("_id")),
+ receiver, sender,
+ cursor.getString(cursor.getColumnIndex("body")),
+ cursor.getLong(cursor.getColumnIndex("date")),
+ mRequestId, mProcessId);
+ } catch (NotFoundException e) {
+ Log.i("GeckoSmsManager", "Message id " + mMessageId + " not found");
+ GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId, mProcessId);
+ } catch (UnmatchingIdException e) {
+ Log.e("GeckoSmsManager", "Requested message id (" + mMessageId +
+ ") is different from the one we got.");
+ GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+ } catch (TooManyResultsException e) {
+ Log.e("GeckoSmsManager", "Get too many results for id " + mMessageId);
+ GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+ } catch (InvalidTypeException e) {
+ Log.i("GeckoSmsManager", "Message has an invalid type, we ignore it.");
+ GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId, mProcessId);
+ } catch (Exception e) {
+ Log.e("GeckoSmsManager", "Error while trying to get message: " + e);
+ GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ if (!SmsIOThread.getInstance().execute(new GetMessageRunnable(aMessageId, aRequestId, aProcessId))) {
+ Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
+ GeckoAppShell.notifyGetSmsFailed(kUnknownError, aRequestId, aProcessId);
+ }
+ }
+
+ public void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
+ class DeleteMessageRunnable implements Runnable {
+ private int mMessageId;
+ private int mRequestId;
+ private long mProcessId;
+
+ DeleteMessageRunnable(int aMessageId, int aRequestId, long aProcessId) {
+ mMessageId = aMessageId;
+ mRequestId = aRequestId;
+ mProcessId = aProcessId;
+ }
+
+ @Override
+ public void run() {
+ class TooManyResultsException extends Exception { }
+
+ try {
+ ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+ Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
+
+ int count = cr.delete(message, null, null);
+
+ if (count > 1) {
+ throw new TooManyResultsException();
+ }
+
+ GeckoAppShell.notifySmsDeleted(count == 1, mRequestId, mProcessId);
+ } catch (TooManyResultsException e) {
+ Log.e("GeckoSmsManager", "Delete more than one message? " + e);
+ GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId, mProcessId);
+ } catch (Exception e) {
+ Log.e("GeckoSmsManager", "Error while trying to delete a message: " + e);
+ GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId, mProcessId);
+ }
+ }
+ }
+
+ if (!SmsIOThread.getInstance().execute(new DeleteMessageRunnable(aMessageId, aRequestId, aProcessId))) {
+ Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
+ GeckoAppShell.notifySmsDeleteFailed(kUnknownError, aRequestId, aProcessId);
}
}
+
+ public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+ class CreateMessageListRunnable implements Runnable {
+ private long mStartDate;
+ private long mEndDate;
+ private String[] mNumbers;
+ private int mNumbersCount;
+ private int mDeliveryState;
+ private boolean mReverse;
+ private int mRequestId;
+ private long mProcessId;
+
+ CreateMessageListRunnable(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+ mStartDate = aStartDate;
+ mEndDate = aEndDate;
+ mNumbers = aNumbers;
+ mNumbersCount = aNumbersCount;
+ mDeliveryState = aDeliveryState;
+ mReverse = aReverse;
+ mRequestId = aRequestId;
+ mProcessId = aProcessId;
+ }
+
+ @Override
+ public void run() {
+ class UnexpectedDeliveryStateException extends Exception { };
+ class InvalidTypeException extends Exception { }
+
+ Cursor cursor = null;
+ boolean closeCursor = true;
+
+ try {
+ // TODO: should use the |selectionArgs| argument in |ContentResolver.query()|.
+ ArrayList<String> restrictions = new ArrayList<String>();
+
+ if (mStartDate != 0) {
+ restrictions.add("date >= " + mStartDate);
+ }
+
+ if (mEndDate != 0) {
+ restrictions.add("date <= " + mEndDate);
+ }
+
+ if (mNumbersCount > 0) {
+ String numberRestriction = "address IN ('" + mNumbers[0] + "'";
+
+ for (int i=1; i<mNumbersCount; ++i) {
+ numberRestriction += ", '" + mNumbers[i] + "'";
+ }
+ numberRestriction += ")";
+
+ restrictions.add(numberRestriction);
+ }
+
+ if (mDeliveryState == kDeliveryStateUnknown) {
+ restrictions.add("type IN ('" + kSmsTypeSentbox + "', '" + kSmsTypeInbox + "')");
+ } else if (mDeliveryState == kDeliveryStateSent) {
+ restrictions.add("type = " + kSmsTypeSentbox);
+ } else if (mDeliveryState == kDeliveryStateReceived) {
+ restrictions.add("type = " + kSmsTypeInbox);
+ } else {
+ throw new UnexpectedDeliveryStateException();
+ }
+
+ String restrictionText = restrictions.size() > 0 ? restrictions.get(0) : "";
+
+ for (int i=1; i<restrictions.size(); ++i) {
+ restrictionText += " AND " + restrictions.get(i);
+ }
+
+ ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+ cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
+ mReverse ? "date DESC" : "date ASC");
+
+ if (cursor.getCount() == 0) {
+ GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+ return;
+ }
+
+ cursor.moveToFirst();
+
+ int type = cursor.getInt(cursor.getColumnIndex("type"));
+ String sender = "";
+ String receiver = "";
+
+ if (type == kSmsTypeInbox) {
+ sender = cursor.getString(cursor.getColumnIndex("address"));
+ } else if (type == kSmsTypeSentbox) {
+ receiver = cursor.getString(cursor.getColumnIndex("address"));
+ } else {
+ throw new UnexpectedDeliveryStateException();
+ }
+
+ int listId = MessagesListManager.getInstance().add(cursor);
+ closeCursor = false;
+ GeckoAppShell.notifyListCreated(listId,
+ cursor.getInt(cursor.getColumnIndex("_id")),
+ receiver, sender,
+ cursor.getString(cursor.getColumnIndex("body")),
+ cursor.getLong(cursor.getColumnIndex("date")),
+ mRequestId, mProcessId);
+ } catch (UnexpectedDeliveryStateException e) {
+ Log.e("GeckoSmsManager", "Unexcepted delivery state type: " + e);
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+ } catch (Exception e) {
+ Log.e("GeckoSmsManager", "Error while trying to create a message list cursor: " + e);
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+ } finally {
+ // Close the cursor if MessagesListManager isn't taking care of it.
+ // We could also just check if it is in the MessagesListManager list but
+ // that would be less efficient.
+ if (cursor != null && closeCursor) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ if (!SmsIOThread.getInstance().execute(new CreateMessageListRunnable(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId))) {
+ Log.e("GeckoSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId, aProcessId);
+ }
+ }
+
+ public void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+ class GetNextMessageInListRunnable implements Runnable {
+ private int mListId;
+ private int mRequestId;
+ private long mProcessId;
+
+ GetNextMessageInListRunnable(int aListId, int aRequestId, long aProcessId) {
+ mListId = aListId;
+ mRequestId = aRequestId;
+ mProcessId = aProcessId;
+ }
+
+ @Override
+ public void run() {
+ class UnexpectedDeliveryStateException extends Exception { };
+
+ try {
+ Cursor cursor = MessagesListManager.getInstance().get(mListId);
+
+ if (!cursor.moveToNext()) {
+ MessagesListManager.getInstance().remove(mListId);
+ GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+ return;
+ }
+
+ int type = cursor.getInt(cursor.getColumnIndex("type"));
+ String sender = "";
+ String receiver = "";
+
+ if (type == kSmsTypeInbox) {
+ sender = cursor.getString(cursor.getColumnIndex("address"));
+ } else if (type == kSmsTypeSentbox) {
+ receiver = cursor.getString(cursor.getColumnIndex("address"));
+ } else {
+ throw new UnexpectedDeliveryStateException();
+ }
+
+ int listId = MessagesListManager.getInstance().add(cursor);
+ GeckoAppShell.notifyGotNextMessage(cursor.getInt(cursor.getColumnIndex("_id")),
+ receiver, sender,
+ cursor.getString(cursor.getColumnIndex("body")),
+ cursor.getLong(cursor.getColumnIndex("date")),
+ mRequestId, mProcessId);
+ } catch (UnexpectedDeliveryStateException e) {
+ Log.e("GeckoSmsManager", "Unexcepted delivery state type: " + e);
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+ } catch (Exception e) {
+ Log.e("GeckoSmsManager", "Error while trying to get the next message of a list: " + e);
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+ }
+ }
+ }
+
+ if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId, aProcessId))) {
+ Log.e("GeckoSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
+ GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId, aProcessId);
+ }
+ }
+
+ public void clearMessageList(int aListId) {
+ MessagesListManager.getInstance().remove(aListId);
+ }
+
+ public void shutdown() {
+ GeckoApp.mAppContext.unregisterReceiver(this);
+
+ SmsIOThread.getInstance().interrupt();
+ MessagesListManager.getInstance().clear();
+ }
}
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -50,25 +50,30 @@ JAVAFILES = \
GeckoAppShell.java \
GeckoConnectivityReceiver.java \
GeckoEvent.java \
GeckoSurfaceView.java \
GeckoInputConnection.java \
AlertNotification.java \
SurfaceInfo.java \
GeckoBatteryManager.java \
- GeckoSmsManager.java \
VideoPlayer.java \
+ GeckoNetworkManager.java \
$(NULL)
+ifdef MOZ_WEBSMS_BACKEND
+JAVAFILES += GeckoSmsManager.java
+endif
+
PROCESSEDJAVAFILES = \
App.java \
Restarter.java \
NotificationHandler.java \
LauncherShortcuts.java \
+ SmsManager.java \
$(NULL)
ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
MIN_CPU_VERSION=7
else
MIN_CPU_VERSION=5
endif
new file mode 100644
--- /dev/null
+++ b/embedding/android/SmsManager.java.in
@@ -0,0 +1,71 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * 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 ***** */
+
+package org.mozilla.gecko;
+
+#ifdef MOZ_WEBSMS_BACKEND
+import org.mozilla.gecko.GeckoSmsManager;
+#endif
+
+class SmsManager
+{
+ static private ISmsManager sInstance = null;
+
+ static public ISmsManager getInstance() {
+#ifdef MOZ_WEBSMS_BACKEND
+ if (sInstance == null) {
+ sInstance = new GeckoSmsManager();
+ }
+#endif
+ return sInstance;
+ }
+}
+
+interface ISmsManager
+{
+ public void init();
+ public void shutdown();
+
+ public int getNumberOfMessagesForText(String aText);
+ public void send(String aNumber, String aMessage, int aRequestId, long aProcessId);
+ public int saveSentMessage(String aRecipient, String aBody, long aDate);
+ public void getMessage(int aMessageId, int aRequestId, long aProcessId);
+ public void deleteMessage(int aMessageId, int aRequestId, long aProcessId);
+ public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId);
+ public void getNextMessageInList(int aListId, int aRequestId, long aProcessId);
+ public void clearMessageList(int aListId);
+}
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -268,16 +268,34 @@ protected:
void GetCurrentInformationInternal(BatteryInformation* aInfo) {
PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
}
};
static BatteryObserversManager sBatteryObservers;
+class NetworkObserversManager : public ObserversManager<NetworkInformation>
+{
+protected:
+ void EnableNotifications() {
+ PROXY_IF_SANDBOXED(EnableNetworkNotifications());
+ }
+
+ void DisableNotifications() {
+ PROXY_IF_SANDBOXED(DisableNetworkNotifications());
+ }
+
+ void GetCurrentInformationInternal(NetworkInformation* aInfo) {
+ PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
+ }
+};
+
+static NetworkObserversManager sNetworkObservers;
+
void
RegisterBatteryObserver(BatteryObserver* aObserver)
{
AssertMainThread();
sBatteryObservers.AddObserver(aObserver);
}
void
@@ -321,10 +339,38 @@ double GetScreenBrightness()
}
void SetScreenBrightness(double brightness)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
}
+void
+RegisterNetworkObserver(NetworkObserver* aObserver)
+{
+ AssertMainThread();
+ sNetworkObservers.AddObserver(aObserver);
+}
+
+void
+UnregisterNetworkObserver(NetworkObserver* aObserver)
+{
+ AssertMainThread();
+ sNetworkObservers.RemoveObserver(aObserver);
+}
+
+void
+GetCurrentNetworkInformation(NetworkInformation* aInfo)
+{
+ AssertMainThread();
+ *aInfo = sNetworkObservers.GetCurrentInformation();
+}
+
+void
+NotifyNetworkChange(const NetworkInformation& aInfo)
+{
+ sNetworkObservers.CacheInformation(aInfo);
+ sNetworkObservers.BroadcastCachedInformation();
+}
+
} // namespace hal
} // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -41,16 +41,17 @@
#define mozilla_Hal_h 1
#include "mozilla/hal_sandbox/PHal.h"
#include "base/basictypes.h"
#include "mozilla/Types.h"
#include "nsTArray.h"
#include "prlog.h"
#include "mozilla/dom/battery/Types.h"
+#include "mozilla/dom/network/Types.h"
/*
* Hal.h contains the public Hal API.
*
* By default, this file defines its functions in the hal namespace, but if
* MOZ_HAL_NAMESPACE is defined, we'll define our functions in that namespace.
*
* This is used by HalImpl.h and HalSandbox.h, which define copies of all the
@@ -163,16 +164,39 @@ double GetScreenBrightness();
*
* Note that we may reduce the resolution of the given brightness value before
* sending it to the screen. Therefore if you call SetScreenBrightness(x)
* followed by GetScreenBrightness(), the value returned by
* GetScreenBrightness() may not be exactly x.
*/
void SetScreenBrightness(double brightness);
+/**
+ * Inform the network backend there is a new network observer.
+ * @param aNetworkObserver The observer that should be added.
+ */
+void RegisterNetworkObserver(NetworkObserver* aNetworkObserver);
+
+/**
+ * Inform the network backend a network observer unregistered.
+ * @param aNetworkObserver The observer that should be removed.
+ */
+void UnregisterNetworkObserver(NetworkObserver* aNetworkObserver);
+
+/**
+ * Returns the current network information.
+ */
+void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
+
+/**
+ * Notify of a change in the network state.
+ * @param aNetworkInfo The new network information.
+ */
+void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
+
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla
#ifdef MOZ_DEFINED_HAL_NAMESPACE
# undef MOZ_DEFINED_HAL_NAMESPACE
# undef MOZ_HAL_NAMESPACE
#endif
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -62,12 +62,22 @@ namespace MOZ_HAL_NAMESPACE {
*/
void EnableBatteryNotifications();
/**
* Disables battery notifications from the backend.
*/
void DisableBatteryNotifications();
+/**
+ * Enables network notifications from the backend.
+ */
+void EnableNetworkNotifications();
+
+/**
+ * Disables network notifications from the backend.
+ */
+void DisableNetworkNotifications();
+
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla
#endif // mozilla_HalInternal_h
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -34,16 +34,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Hal.h"
#include "HalImpl.h"
#include "WindowIdentifier.h"
#include "AndroidBridge.h"
+#include "mozilla/dom/network/Constants.h"
using mozilla::hal::WindowIdentifier;
namespace mozilla {
namespace hal_impl {
void
Vibrate(const nsTArray<uint32> &pattern, const WindowIdentifier &)
@@ -134,11 +135,44 @@ GetScreenBrightness()
{
return 1;
}
void
SetScreenBrightness(double brightness)
{}
+void
+EnableNetworkNotifications()
+{
+ AndroidBridge* bridge = AndroidBridge::Bridge();
+ if (!bridge) {
+ return;
+ }
+
+ bridge->EnableNetworkNotifications();
+}
+
+void
+DisableNetworkNotifications()
+{
+ AndroidBridge* bridge = AndroidBridge::Bridge();
+ if (!bridge) {
+ return;
+ }
+
+ bridge->DisableNetworkNotifications();
+}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+ AndroidBridge* bridge = AndroidBridge::Bridge();
+ if (!bridge) {
+ return;
+ }
+
+ bridge->GetCurrentNetworkInformation(aNetworkInfo);
+}
+
} // hal_impl
} // mozilla
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -34,16 +34,17 @@
* 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 "Hal.h"
#include "mozilla/dom/battery/Constants.h"
+#include "mozilla/dom/network/Constants.h"
using mozilla::hal::WindowIdentifier;
namespace mozilla {
namespace hal_impl {
void
Vibrate(const nsTArray<uint32>& pattern, const hal::WindowIdentifier &)
@@ -84,10 +85,25 @@ GetScreenBrightness()
{
return 1;
}
void
SetScreenBrightness(double brightness)
{}
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+ aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+ aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
} // hal_impl
} // namespace mozilla
--- a/hal/linux/LinuxHal.cpp
+++ b/hal/linux/LinuxHal.cpp
@@ -31,16 +31,17 @@
* 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 "Hal.h"
+#include "mozilla/dom/network/Constants.h"
#ifndef MOZ_ENABLE_DBUS
#include <mozilla/dom/battery/Constants.h>
#endif // !MOZ_ENABLE_DBUS
namespace mozilla {
namespace hal_impl {
@@ -85,11 +86,26 @@ GetScreenBrightness()
{
return 1;
}
void
SetScreenBrightness(double brightness)
{}
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+ aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+ aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
} // hal_impl
} // mozilla
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -45,33 +45,46 @@ namespace mozilla {
namespace hal {
struct BatteryInformation {
double level;
bool charging;
double remainingTime;
};
}
+namespace hal {
+ struct NetworkInformation {
+ double bandwidth;
+ bool canBeMetered;
+ };
+}
+
namespace hal_sandbox {
sync protocol PHal {
manager PContent;
child:
NotifyBatteryChange(BatteryInformation aBatteryInfo);
+ NotifyNetworkChange(NetworkInformation aNetworkInfo);
parent:
Vibrate(uint32[] pattern, uint64[] id, PBrowser browser);
CancelVibrate(uint64[] id, PBrowser browser);
EnableBatteryNotifications();
DisableBatteryNotifications();
sync GetCurrentBatteryInformation()
returns (BatteryInformation aBatteryInfo);
+ EnableNetworkNotifications();
+ DisableNetworkNotifications();
+ sync GetCurrentNetworkInformation()
+ returns (NetworkInformation aNetworkInfo);
+
sync GetScreenEnabled() returns (bool enabled);
SetScreenEnabled(bool enabled);
sync GetScreenBrightness() returns (double brightness);
SetScreenBrightness(double brightness);
__delete__();
};
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -39,16 +39,17 @@
#include "Hal.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/hal_sandbox/PHalChild.h"
#include "mozilla/hal_sandbox/PHalParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/battery/Types.h"
+#include "mozilla/dom/network/Types.h"
#include "mozilla/Observer.h"
#include "mozilla/unused.h"
#include "WindowIdentifier.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::hal;
@@ -100,16 +101,34 @@ DisableBatteryNotifications()
}
void
GetCurrentBatteryInformation(BatteryInformation* aBatteryInfo)
{
Hal()->SendGetCurrentBatteryInformation(aBatteryInfo);
}
+void
+EnableNetworkNotifications()
+{
+ Hal()->SendEnableNetworkNotifications();
+}
+
+void
+DisableNetworkNotifications()
+{
+ Hal()->SendDisableNetworkNotifications();
+}
+
+void
+GetCurrentNetworkInformation(NetworkInformation* aNetworkInfo)
+{
+ Hal()->SendGetCurrentNetworkInformation(aNetworkInfo);
+}
+
bool
GetScreenEnabled()
{
bool enabled = false;
Hal()->SendGetScreenEnabled(&enabled);
return enabled;
}
@@ -129,17 +148,19 @@ GetScreenBrightness()
void
SetScreenBrightness(double brightness)
{
Hal()->SendSetScreenBrightness(brightness);
}
class HalParent : public PHalParent
- , public BatteryObserver {
+ , public BatteryObserver
+ , public NetworkObserver
+{
public:
NS_OVERRIDE virtual bool
RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
const InfallibleTArray<uint64> &id,
PBrowserParent *browserParent)
{
// Check whether browserParent is active. We should have already
// checked that the corresponding window is active, but this check
@@ -193,16 +214,38 @@ public:
return true;
}
void Notify(const BatteryInformation& aBatteryInfo) {
unused << SendNotifyBatteryChange(aBatteryInfo);
}
NS_OVERRIDE virtual bool
+ RecvEnableNetworkNotifications() {
+ hal::RegisterNetworkObserver(this);
+ return true;
+ }
+
+ NS_OVERRIDE virtual bool
+ RecvDisableNetworkNotifications() {
+ hal::UnregisterNetworkObserver(this);
+ return true;
+ }
+
+ NS_OVERRIDE virtual bool
+ RecvGetCurrentNetworkInformation(NetworkInformation* aNetworkInfo) {
+ hal::GetCurrentNetworkInformation(aNetworkInfo);
+ return true;
+ }
+
+ void Notify(const NetworkInformation& aNetworkInfo) {
+ unused << SendNotifyNetworkChange(aNetworkInfo);
+ }
+
+ NS_OVERRIDE virtual bool
RecvGetScreenEnabled(bool *enabled)
{
*enabled = hal::GetScreenEnabled();
return true;
}
NS_OVERRIDE virtual bool
RecvSetScreenEnabled(const bool &enabled)
@@ -228,16 +271,22 @@ public:
class HalChild : public PHalChild {
public:
NS_OVERRIDE virtual bool
RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) {
hal::NotifyBatteryChange(aBatteryInfo);
return true;
}
+
+ NS_OVERRIDE virtual bool
+ RecvNotifyNetworkChange(const NetworkInformation& aNetworkInfo) {
+ hal::NotifyNetworkChange(aNetworkInfo);
+ return true;
+ }
};
PHalChild* CreateHalChild() {
return new HalChild();
}
PHalParent* CreateHalParent() {
return new HalParent();
--- a/hal/windows/WindowsHal.cpp
+++ b/hal/windows/WindowsHal.cpp
@@ -31,16 +31,17 @@
* 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 "Hal.h"
+#include "mozilla/dom/network/Constants.h"
namespace mozilla {
namespace hal_impl {
void
Vibrate(const nsTArray<uint32>& pattern, const hal::WindowIdentifier &)
{}
@@ -63,10 +64,25 @@ GetScreenBrightness()
{
return 1;
}
void
SetScreenBrightness(double brightness)
{}
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+ aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+ aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
} // hal_impl
} // mozilla
--- a/intl/uconv/src/nsCharsetConverterManager.cpp
+++ b/intl/uconv/src/nsCharsetConverterManager.cpp
@@ -233,17 +233,16 @@ nsCharsetConverterManager::GetList(const
const nsACString& aPrefix,
nsIUTF8StringEnumerator** aResult)
{
if (aResult == NULL)
return NS_ERROR_NULL_POINTER;
*aResult = NULL;
nsresult rv;
- nsCAutoString alias;
nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
nsTArray<nsCString>* array = new nsTArray<nsCString>;
if (!array)
return NS_ERROR_OUT_OF_MEMORY;
@@ -257,28 +256,23 @@ nsCharsetConverterManager::GetList(const
nsCOMPtr<nsISupports> supports;
if (NS_FAILED(enumerator->GetNext(getter_AddRefs(supports))))
continue;
nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
if (!supStr)
continue;
- nsCAutoString fullName(aPrefix);
-
nsCAutoString name;
if (NS_FAILED(supStr->GetData(name)))
continue;
- fullName += name;
- rv = GetCharsetAlias(fullName.get(), alias);
- if (NS_FAILED(rv))
- continue;
-
- rv = array->AppendElement(alias) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+ nsCAutoString fullName(aPrefix);
+ fullName.Append(name);
+ NS_ENSURE_TRUE(array->AppendElement(fullName), NS_ERROR_OUT_OF_MEMORY);
}
return NS_NewAdoptingUTF8StringEnumerator(aResult, array);
}
// we should change the interface so that we can just pass back a enumerator!
NS_IMETHODIMP
nsCharsetConverterManager::GetDecoderList(nsIUTF8StringEnumerator ** aResult)
@@ -312,17 +306,16 @@ nsCharsetConverterManager::GetCharsetAli
NS_ENSURE_ARG_POINTER(aCharset);
// We try to obtain the preferred name for this charset from the charset
// aliases.
nsresult rv;
nsCOMPtr<nsICharsetAlias> csAlias(do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
- nsAutoString pref;
rv = csAlias->GetPreferred(nsDependentCString(aCharset), aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/intl/uconv/tests/unit/test_bug718500.js
@@ -0,0 +1,219 @@
+var detectList = [
+ "chardet.universal_charset_detector",
+ "chardet.ja_parallel_state_machine",
+ "chardet.ko_parallel_state_machine",
+ "chardet.zhtw_parallel_state_machine",
+ "chardet.zhcn_parallel_state_machine",
+ "chardet.zh_parallel_state_machine",
+ "chardet.cjk_parallel_state_machine",
+ "chardet.off",
+ "chardet.ruprob",
+ "chardet.ukprob",
+];
+
+var encoderList = [
+ "ISO-8859-1",
+ "windows-1252",
+ "x-mac-roman",
+ "UTF-8",
+ "us-ascii",
+ "ISO-8859-2",
+ "ISO-8859-3",
+ "ISO-8859-4",
+ "ISO-8859-5",
+ "ISO-8859-6",
+ "ISO-8859-6-I",
+ "ISO-8859-6-E",
+ "ISO-8859-7",
+ "ISO-8859-8",
+ "ISO-8859-8-I",
+ "ISO-8859-8-E",
+ "ISO-8859-9",
+ "ISO-8859-10",
+ "ISO-8859-13",
+ "ISO-8859-14",
+ "ISO-8859-15",
+ "ISO-8859-16",
+ "ISO-IR-111",
+ "windows-1250",
+ "windows-1251",
+ "windows-1253",
+ "windows-1254",
+ "windows-1255",
+ "windows-1256",
+ "windows-1257",
+ "windows-1258",
+ "TIS-620",
+ "windows-874",
+ "ISO-8859-11",
+ "KOI8-R",
+ "KOI8-U",
+ "x-mac-ce",
+ "x-mac-greek",
+ "x-mac-turkish",
+ "x-mac-croatian",
+ "x-mac-romanian",
+ "x-mac-cyrillic",
+ "x-mac-icelandic",
+ "armscii-8",
+ "x-viet-tcvn5712",
+ "VISCII",
+ "x-viet-vps",
+ "UTF-7",
+ "x-imap4-modified-utf7",
+ "UTF-16",
+ "UTF-16BE",
+ "UTF-16LE",
+ "T.61-8bit",
+ "x-user-defined",
+ "x-mac-arabic",
+ "x-mac-devanagari",
+ "x-mac-farsi",
+ "x-mac-gurmukhi",
+ "x-mac-gujarati",
+ "x-mac-hebrew",
+
+ "Adobe-Symbol-Encoding",
+ "x-zapf-dingbats",
+ "x-tscii",
+ "x-tamilttf-0",
+
+ "IBM850",
+ "IBM852",
+ "IBM855",
+ "IBM857",
+ "IBM862",
+ "IBM864",
+ "IBM864i",
+ "IBM866",
+ "Shift_JIS",
+ "ISO-2022-JP",
+ "EUC-JP",
+ "jis_0201",
+ "x-euc-tw",
+ "Big5",
+ "Big5-HKSCS",
+ "hkscs-1",
+ "EUC-KR",
+ "x-johab",
+ "x-windows-949",
+ "GB2312",
+ "gbk",
+ "HZ-GB-2312",
+ "gb18030",
+];
+
+var decoderList = [
+ "ISO-8859-1",
+ "windows-1252",
+ "x-mac-roman",
+ "UTF-8",
+ "us-ascii",
+ "ISO-8859-2",
+ "ISO-8859-3",
+ "ISO-8859-4",
+ "ISO-8859-5",
+ "ISO-8859-6",
+ "ISO-8859-6-I",
+ "ISO-8859-6-E",
+ "ISO-8859-7",
+ "ISO-8859-8",
+ "ISO-8859-8-I",
+ "ISO-8859-8-E",
+ "ISO-8859-9",
+ "ISO-8859-10",
+ "ISO-8859-13",
+ "ISO-8859-14",
+ "ISO-8859-15",
+ "ISO-8859-16",
+ "ISO-IR-111",
+ "windows-1250",
+ "windows-1251",
+ "windows-1253",
+ "windows-1254",
+ "windows-1255",
+ "windows-1256",
+ "windows-1257",
+ "windows-1258",
+ "TIS-620",
+ "windows-874",
+ "ISO-8859-11",
+ "KOI8-R",
+ "KOI8-U",
+ "x-mac-ce",
+ "x-mac-greek",
+ "x-mac-turkish",
+ "x-mac-croatian",
+ "x-mac-romanian",
+ "x-mac-cyrillic",
+ "x-mac-icelandic",
+ "armscii-8",
+ "x-viet-tcvn5712",
+ "VISCII",
+ "x-viet-vps",
+ "UTF-7",
+ "x-imap4-modified-utf7",
+ "UTF-16",
+ "UTF-16BE",
+ "UTF-16LE",
+ "T.61-8bit",
+ "x-user-defined",
+ "x-mac-arabic",
+ "x-mac-devanagari",
+ "x-mac-farsi",
+ "x-mac-gurmukhi",
+ "x-mac-gujarati",
+ "x-mac-hebrew",
+ "IBM850",
+ "IBM852",
+ "IBM855",
+ "IBM857",
+ "IBM862",
+ "IBM864",
+ "IBM864i",
+ "IBM866",
+ "Shift_JIS",
+ "ISO-2022-JP",
+ "EUC-JP",
+ "x-euc-tw",
+ "Big5",
+ "Big5-HKSCS",
+ "EUC-KR",
+ "x-johab",
+ "x-windows-949",
+ "GB2312",
+ "gbk",
+ "HZ-GB-2312",
+ "gb18030",
+ "ISO-2022-KR",
+ "ISO-2022-CN",
+];
+
+function verifyList(aEnumerator, aList)
+{
+ var count = 0;
+
+ while (aEnumerator.hasMore()) {
+ var result = aEnumerator.getNext();
+ for (var i = 0; i < aList.length; i++) {
+ if (result == aList[i]) {
+ count++;
+ break;
+ }
+ }
+ if (i == aList.length) {
+ do_throw("Unknown chardet: " + result);
+ }
+ }
+ do_check_eq(count, aList.length);
+}
+
+function run_test()
+{
+ var cm = Components.classes["@mozilla.org/charset-converter-manager;1"]
+ .getService(Components.interfaces.nsICharsetConverterManager);
+
+ verifyList(cm.GetCharsetDetectorList(), detectList);
+ verifyList(cm.getEncoderList(), encoderList);
+ verifyList(cm.getDecoderList(), decoderList);
+}
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -24,16 +24,17 @@ tail =
[test_bug457886.js]
[test_bug522931.js]
[test_bug563283.js]
[test_bug563618.js]
[test_bug601429.js]
[test_bug699673.js]
[test_bug90411.js]
[test_bug713519.js]
+[test_bug718500.js]
[test_charset_conversion.js]
[test_decode_8859-1.js]
[test_decode_8859-10.js]
[test_decode_8859-11.js]
[test_decode_8859-13.js]
[test_decode_8859-14.js]
[test_decode_8859-15.js]
[test_decode_8859-2.js]
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -62,17 +62,17 @@
#endif
#if !defined(OS_POSIX)
// This condition must be kept in sync with the one in
// ipc_message_utils.h, but this dummy definition of
// base::FileDescriptor acts as a static assert that we only get one
// def or the other (or neither, in which case code using
// FileDescriptor fails to build)
-namespace base { class FileDescriptor { }; }
+namespace base { struct FileDescriptor { }; }
#endif
using mozilla::layers::LayerManager;
namespace mozilla {
typedef gfxPattern::GraphicsFilter GraphicsFilterType;
typedef gfxASurface::gfxSurfaceType gfxSurfaceType;
--- a/js/src/jit-test/tests/basic/bug592927.js
+++ b/js/src/jit-test/tests/basic/bug592927.js
@@ -8,20 +8,20 @@ function g(x) {
assertEq(x.arguments[1], "hello");
x.arguments[1] = "bye";
assertEq(x.arguments[1], "hello");
}
function f2(x, y) {
arguments;
x(f2);
- assertEq(y, "bye");
+ assertEq(y, "hello");
}
function g2(x) {
assertEq(x.arguments[1], "hello");
x.arguments[1] = "bye";
- assertEq(x.arguments[1], "bye");
+ assertEq(x.arguments[1], "hello");
}
f(g, "hello");
f2(g2, "hello");
--- a/js/src/jit-test/tests/jaeger/argumentsOptimize-1.js
+++ b/js/src/jit-test/tests/jaeger/argumentsOptimize-1.js
@@ -3,12 +3,12 @@ function bar() {
foo.arguments.length = 10;
}
function foo(x) {
var a = arguments;
var n = 0;
bar();
assertEq(x, 5);
- assertEq(a.length, 10);
+ assertEq(a.length, 1);
}
foo(5);
--- a/js/src/jit-test/tests/jaeger/loops/hoist-05.js
+++ b/js/src/jit-test/tests/jaeger/loops/hoist-05.js
@@ -11,9 +11,9 @@ function foo(x, j, n) {
bar(x, i);
if (typeof q == 'undefined')
a++;
}
return a;
}
var a = foo([1,2,3,4], 3, 100);
-assertEq(a, 49);
+assertEq(a, 0);
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -1528,17 +1528,17 @@ ScriptAnalysis::insertPhi(JSContext *cx,
/*
* Filter dupes inserted into small nodes to keep things clean and avoid
* extra type constraints, but don't bother on large phi nodes to avoid
* quadratic behavior.
*/
if (node->length <= 8) {
for (unsigned i = 0; i < node->length; i++) {
- if (v.equals(node->options[i]))
+ if (v == node->options[i])
return;
}
}
if (trackUseChain(v)) {
SSAUseChain *&uses = useChain(v);
SSAUseChain *use = cx->typeLifoAlloc().new_<SSAUseChain>();
@@ -1572,17 +1572,17 @@ ScriptAnalysis::insertPhi(JSContext *cx,
}
inline void
ScriptAnalysis::mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv)
{
/* Make sure that v is accounted for in the pending value or phi value at pv. */
JS_ASSERT(v.kind() != SSAValue::EMPTY && pv->value.kind() != SSAValue::EMPTY);
- if (v.equals(pv->value))
+ if (v == pv->value)
return;
if (pv->value.kind() != SSAValue::PHI || pv->value.phiOffset() < offset) {
SSAValue ov = pv->value;
if (makePhi(cx, pv->slot, offset, &pv->value)) {
insertPhi(cx, pv->value, v);
insertPhi(cx, pv->value, ov);
}
@@ -1702,17 +1702,17 @@ ScriptAnalysis::mergeExceptionTarget(JSC
* try block starts and overwritten before it is finished can still be
* seen at exception handlers via exception paths.
*/
for (unsigned i = 0; i < exceptionTargets.length(); i++) {
Vector<SlotValue> *pending = getCode(exceptionTargets[i]).pendingValues;
bool duplicate = false;
for (unsigned i = 0; i < pending->length(); i++) {
- if ((*pending)[i].slot == slot && (*pending)[i].value.equals(value))
+ if ((*pending)[i].slot == slot && (*pending)[i].value == value)
duplicate = true;
}
if (!duplicate && !pending->append(SlotValue(slot, value)))
setOOM(cx);
}
}
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -585,17 +585,17 @@ class SSAValue
Kind kind() const {
JS_ASSERT(u.pushed.kind == u.var.kind && u.pushed.kind == u.phi.kind);
/* Use a bitmask because MSVC wants to use -1 for PHI nodes. */
return (Kind) (u.pushed.kind & 0x3);
}
- bool equals(const SSAValue &o) const {
+ bool operator==(const SSAValue &o) const {
return !memcmp(this, &o, sizeof(SSAValue));
}
/* Accessors for values pushed by a bytecode within this script. */
uint32_t pushedOffset() const {
JS_ASSERT(kind() == PUSHED);
return u.pushed.offset;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1673,23 +1673,17 @@ IsJITBrokenHere()
return isBroken;
}
#endif
void
JSContext::updateJITEnabled()
{
#ifdef JS_METHODJIT
- methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
- !IsJITBrokenHere()
-# if defined JS_CPU_X86 || defined JS_CPU_X64
- && JSC::MacroAssemblerX86Common::getSSEState() >=
- JSC::MacroAssemblerX86Common::HasSSE2
-# endif
- ;
+ methodJitEnabled = (runOptions & JSOPTION_METHODJIT) && !IsJITBrokenHere();
#endif
}
size_t
JSContext::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
{
/*
* There are other JSContext members that could be measured; the following
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -118,17 +118,17 @@ js_GetArgsValue(JSContext *cx, StackFram
argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return JS_FALSE;
vp->setObject(*argsobj);
return JS_TRUE;
}
js::ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp)
+ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
{
JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
if (!proto)
return NULL;
RootedVarTypeObject type(cx);
@@ -161,17 +161,17 @@ ArgumentsObject::create(JSContext *cx, u
if (!obj)
return NULL;
ArgumentsObject &argsobj = obj->asArguments();
JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT));
argsobj.initInitialLength(argc);
argsobj.initData(data);
- argsobj.setStackFrame(strict ? NULL : fp);
+ argsobj.setStackFrame(NULL);
JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
return &argsobj;
}
struct STATIC_SKIP_INFERENCE PutArg
@@ -206,18 +206,17 @@ js_GetArgsObject(JSContext *cx, StackFra
if (!fp->script()->createdArgs)
types::MarkArgumentsCreated(cx, fp->script());
/* Create an arguments object for fp only if it lacks one. */
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
if (fp->hasArgsObj())
return &fp->argsObj();
- ArgumentsObject *argsobj =
- ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee(), fp);
+ ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
if (!argsobj)
return argsobj;
/*
* Strict mode functions have arguments objects that copy the initial
* actual parameter values. It is the caller's responsibility to get the
* arguments object before any parameters are modified! (The emitter
* ensures this by synthesizing an arguments access at the start of any
@@ -1107,17 +1106,29 @@ fun_getProperty(JSContext *cx, JSObject
if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) {
/* Warn if strict about f.arguments or equivalent unqualified uses. */
if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage,
NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) {
return false;
}
- return js_GetArgsValue(cx, fp, vp);
+ /*
+ * Purposefully disconnect the returned arguments object from the frame
+ * by always creating a new copy that does not alias formal parameters.
+ * This allows function-local analysis to determine that formals are
+ * not aliased and generally simplifies arguments objects.
+ */
+ ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
+ if (!argsobj)
+ return false;
+
+ fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
+ *vp = ObjectValue(*argsobj);
+ return true;
}
if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
if (!fp->prev())
return true;
StackFrame *frame = js_GetScriptedCaller(cx, fp->prev());
if (frame && !frame->getValidCalleeObject(cx, vp))
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -54,16 +54,19 @@
#include "jsscope.h"
#include "jsstr.h"
#include "jsiter.h"
#include "frontend/TokenStream.h"
#include "js/MemoryMetrics.h"
#include "methodjit/MethodJIT.h"
#include "methodjit/Retcon.h"
+#ifdef JS_METHODJIT
+# include "assembler/assembler/MacroAssembler.h"
+#endif
#include "jsatominlines.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "vm/Stack-inl.h"
@@ -1956,18 +1959,23 @@ TypeSet::needsBarrier(JSContext *cx)
// TypeCompartment
/////////////////////////////////////////////////////////////////////
void
TypeCompartment::init(JSContext *cx)
{
PodZero(this);
- if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE)
- inferenceEnabled = true;
+ if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE) {
+#ifdef JS_METHODJIT
+ JSC::MacroAssembler masm;
+ if (masm.supportsFloatingPoint())
+#endif
+ inferenceEnabled = true;
+ }
}
TypeObject *
TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
JSProtoKey key, JSObject *proto, bool unknown)
{
RootObject root(cx, &proto);
@@ -4296,17 +4304,17 @@ ScriptAnalysis::followEscapingArguments(
/*
* trackUseChain is false for initial values of variables, which
* cannot hold the script's arguments object.
*/
if (!trackUseChain(v))
return true;
for (unsigned i = 0; i < seen->length(); i++) {
- if (v.equals((*seen)[i]))
+ if (v == (*seen)[i])
return true;
}
if (!seen->append(v)) {
cx->compartment->types.setPendingNukeTypes(cx);
return false;
}
SSAUseChain *use = useChain(v);
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -826,17 +826,17 @@ static const JSC::MacroAssembler::Regist
if (key.isConstant())
key.index_ += delta;
else
add32(Imm32(delta), key.reg());
}
void loadFrameActuals(JSFunction *fun, RegisterID reg) {
/* Bias for the case where there was an arguments overflow. */
- load32(Address(JSFrameReg, StackFrame::offsetOfArgs()), reg);
+ load32(Address(JSFrameReg, StackFrame::offsetOfNumActual()), reg);
add32(Imm32(fun->nargs + 2), reg);
Jump overflowArgs = branchTest32(Assembler::NonZero,
Address(JSFrameReg, StackFrame::offsetOfFlags()),
Imm32(StackFrame::OVERFLOW_ARGS));
move(Imm32(fun->nargs), reg);
overflowArgs.linkTo(label(), this);
lshiftPtr(Imm32(3), reg);
negPtr(reg);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -809,27 +809,27 @@ mjit::Compiler::generatePrologue()
stubcc.linkExitDirect(mismatch, stubcc.masm.label());
OOL_STUBCALL(stubs::FunctionFramePrologue, REJOIN_FUNCTION_PROLOGUE);
stubcc.crossJump(stubcc.masm.jump(), masm.label());
}
}
if (outerScript->usesArguments && !script->function()->isHeavyweight()) {
/*
- * Make sure that fp->args.nactual is always coherent. This may be
+ * Make sure that fp->u.nactual is always coherent. This may be
* inspected directly by JIT code, and is not guaranteed to be
* correct if the UNDERFLOW and OVERFLOW flags are not set.
*/
Jump hasArgs = masm.branchTest32(Assembler::NonZero, FrameFlagsAddress(),
Imm32(StackFrame::OVERRIDE_ARGS |
StackFrame::UNDERFLOW_ARGS |
StackFrame::OVERFLOW_ARGS |
StackFrame::HAS_ARGS_OBJ));
masm.storePtr(ImmPtr((void *)(size_t) script->function()->nargs),
- Address(JSFrameReg, StackFrame::offsetOfArgs()));
+ Address(JSFrameReg, StackFrame::offsetOfNumActual()));
hasArgs.linkTo(masm.label(), &masm);
}
j.linkTo(masm.label(), &masm);
}
if (cx->typeInferenceEnabled()) {
#ifdef DEBUG
@@ -4522,22 +4522,21 @@ mjit::Compiler::jsop_getprop(PropertyNam
bumpPropCounter(PC, OpcodeCounts::PROP_DEFINITE);
if (!isObject)
stubcc.rejoin(Changes(1));
return true;
}
/*
* Check if we are accessing the 'length' of the lazy arguments for the
- * current frame. No actual arguments object has ever been constructed
- * for the script, so we can go straight to nactual.
+ * current frame.
*/
if (types->isLazyArguments(cx)) {
frame.pop();
- frame.pushWord(Address(JSFrameReg, StackFrame::offsetOfArgs()), JSVAL_TYPE_INT32);
+ frame.pushWord(Address(JSFrameReg, StackFrame::offsetOfNumActual()), JSVAL_TYPE_INT32);
if (script->pcCounters)
bumpPropCounter(PC, OpcodeCounts::PROP_DEFINITE);
return true;
}
}
/* If the access will definitely be fetching a particular value, nop it. */
bool testObject;
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -633,16 +633,17 @@ private:
bool jsop_xname(PropertyName *name);
void enterBlock(JSObject *obj);
void leaveBlock();
void emitEval(uint32_t argc);
void jsop_arguments(RejoinState rejoin);
bool jsop_tableswitch(jsbytecode *pc);
/* Fast arithmetic. */
+ bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
JSValueType type, bool cannotOverflow, bool ignoreOverflow);
void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
JSValueType type);
void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
JSValueType type);
void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -171,16 +171,31 @@ mjit::Compiler::maybeJumpIfNotDouble(Ass
else
mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe)));
} else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
mj.setJump(masm.jump());
}
}
bool
+mjit::Compiler::jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type,
+ FrameEntry *lhs, FrameEntry *rhs)
+{
+ bool isStringResult = (op == JSOP_ADD) &&
+ (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING));
+ JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
+
+ prepareStubCall(Uses(2));
+ INLINE_STUBCALL(stub, REJOIN_BINARY);
+ frame.popn(2);
+ frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
+ return true;
+}
+
+bool
mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
{
FrameEntry *rhs = frame.peek(-1);
FrameEntry *lhs = frame.peek(-2);
Value v;
if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
if (!v.isInt32() && typeSet && !typeSet->hasType(types::Type::DoubleType())) {
@@ -200,26 +215,17 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
/*
* Bail out if there are unhandled types or ops.
* This is temporary while ops are still being implemented.
*/
if ((lhs->isConstant() && rhs->isConstant()) ||
(lhs->isTypeKnown() && (lhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) ||
(rhs->isTypeKnown() && (rhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)))
{
- bool isStringResult = (op == JSOP_ADD) &&
- (lhs->isType(JSVAL_TYPE_STRING) ||
- rhs->isType(JSVAL_TYPE_STRING));
- JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
-
- prepareStubCall(Uses(2));
- INLINE_STUBCALL(stub, REJOIN_BINARY);
- frame.popn(2);
- frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
- return true;
+ return jsop_binary_slow(op, stub, type, lhs, rhs);
}
/*
* If this is an operation on which integer overflows can be ignored, treat
* the result as an integer even if it has been marked as overflowing by
* the interpreter. Doing this changes the values we maintain on the stack
* from those the interpreter would maintain; this is OK as values derived
* from ignored overflows are not live across points where the interpreter
@@ -233,16 +239,19 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
op == JSOP_ADD && ignoreOverflow) {
type = JSVAL_TYPE_INT32;
}
/* Can do int math iff there is no double constant and the op is not division. */
bool canDoIntMath = op != JSOP_DIV && type != JSVAL_TYPE_DOUBLE &&
!(rhs->isType(JSVAL_TYPE_DOUBLE) || lhs->isType(JSVAL_TYPE_DOUBLE));
+ if (!masm.supportsFloatingPoint() && (!canDoIntMath || frame.haveSameBacking(lhs, rhs)))
+ return jsop_binary_slow(op, stub, type, lhs, rhs);
+
if (canDoIntMath)
jsop_binary_full(lhs, rhs, op, stub, type, cannotOverflow, ignoreOverflow);
else
jsop_binary_double(lhs, rhs, op, stub, type);
return true;
}
@@ -567,17 +576,17 @@ mjit::Compiler::jsop_binary_full(FrameEn
emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
MaybeJump rhsNotNumber2;
if (!rhs->isTypeKnown())
emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
/* Perform the double addition. */
MaybeJump doublePathDone;
- if (!rhs->isTypeKnown() || lhsUnknownDone.isSet()) {
+ if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown())) {
/* If the LHS type was not known, link its path here. */
if (lhsUnknownDone.isSet())
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
/* Perform the double operation. */
EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
/* Force the double back to memory. */
@@ -785,29 +794,32 @@ mjit::Compiler::jsop_binary_full(FrameEn
}
void
mjit::Compiler::jsop_neg()
{
FrameEntry *fe = frame.peek(-1);
JSValueType type = knownPushedType(0);
- if (fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) {
+ if ((fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) ||
+ !masm.supportsFloatingPoint())
+ {
prepareStubCall(Uses(1));
INLINE_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
frame.pop();
frame.pushSynced(type);
return;
}
JS_ASSERT(!fe->isConstant());
/* Handle negation of a known double, or of a known integer which has previously overflowed. */
if (fe->isType(JSVAL_TYPE_DOUBLE) ||
- (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE)) {
+ (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE))
+ {
FPRegisterID fpreg;
if (fe->isType(JSVAL_TYPE_DOUBLE)) {
fpreg = frame.tempFPRegForData(fe);
} else {
fpreg = frame.allocFPReg();
frame.convertInt32ToDouble(masm, fe, fpreg);
}
@@ -1304,16 +1316,21 @@ void
mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s,
MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
MaybeJump &lhsUnknownDone)
{
/* If the LHS is not a 32-bit integer, take OOL path. */
Jump lhsNotInt32 = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg());
stubcc.linkExitDirect(lhsNotInt32, stubcc.masm.label());
+ if (!masm.supportsFloatingPoint()) {
+ lhsNotDouble = stubcc.masm.jump();
+ return;
+ }
+
/* OOL path for LHS as a double - first test LHS is double. */
lhsNotDouble = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
/* Ensure the RHS is a number. */
MaybeJump rhsIsDouble;
if (!rhs->isTypeKnown()) {
rhsIsDouble = stubcc.masm.testDouble(Assembler::Equal, regs.rhsType.reg());
rhsNotNumber = stubcc.masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
@@ -1349,16 +1366,21 @@ mjit::Compiler::emitLeftDoublePath(Frame
void
mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s,
MaybeJump &rhsNotNumber2)
{
/* If the RHS is not a double, take OOL path. */
Jump notInt32 = masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
stubcc.linkExitDirect(notInt32, stubcc.masm.label());
+ if (!masm.supportsFloatingPoint()) {
+ rhsNotNumber2 = stubcc.masm.jump();
+ return;
+ }
+
/* Now test if RHS is a double. */
rhsNotNumber2 = stubcc.masm.testDouble(Assembler::NotEqual, regs.rhsType.reg());
/* We know LHS is an integer. */
if (lhs->isConstant())
slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
else
stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
@@ -1566,17 +1588,17 @@ mjit::Compiler::jsop_relational_full(JSO
emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
MaybeJump rhsNotNumber2;
if (!rhs->isTypeKnown())
emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
/* Both double paths will join here. */
bool hasDoublePath = false;
- if (!rhs->isTypeKnown() || lhsUnknownDone.isSet())
+ if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown()))
hasDoublePath = true;
/* Integer path - figure out the immutable side. */
JSOp cmpOp = op;
int32_t value = 0;
RegisterID cmpReg;
MaybeRegisterID reg;
if (regs.lhsData.isSet()) {
@@ -1607,35 +1629,35 @@ mjit::Compiler::jsop_relational_full(JSO
MaybeJump doubleTest, doubleFall;
Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
if (hasDoublePath) {
if (lhsUnknownDone.isSet())
lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
frame.sync(stubcc.masm, Uses(frame.frameSlots()));
doubleTest = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
doubleFall = stubcc.masm.jump();
-
- /* Link all incoming slow paths to here. */
- if (lhsNotDouble.isSet()) {
- lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
- if (rhsNotNumber.isSet())
- rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
- }
- if (rhsNotNumber2.isSet())
- rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+ }
- /*
- * For fusions, spill the tracker state. xmm* remain intact. Note
- * that frame.sync() must be used directly, to avoid syncExit()'s
- * jumping logic.
- */
- frame.sync(stubcc.masm, Uses(frame.frameSlots()));
- stubcc.leave();
- OOL_STUBCALL(stub, REJOIN_BRANCH);
+ /* Link all incoming slow paths to here. */
+ if (lhsNotDouble.isSet()) {
+ lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+ if (rhsNotNumber.isSet())
+ rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
}
+ if (rhsNotNumber2.isSet())
+ rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+
+ /*
+ * For fusions, spill the tracker state. xmm* remain intact. Note
+ * that frame.sync() must be used directly, to avoid syncExit()'s
+ * jumping logic.
+ */
+ frame.sync(stubcc.masm, Uses(frame.frameSlots()));
+ stubcc.leave();
+ OOL_STUBCALL(stub, REJOIN_BRANCH);
/* Forget the world, preserving data. */
frame.pinReg(cmpReg);
if (reg.isSet())
frame.pinReg(reg.reg());
frame.popn(2);
@@ -1696,31 +1718,31 @@ mjit::Compiler::jsop_relational_full(JSO
/* :FIXME: Use SET if we can? */
Jump test = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
stubcc.masm.move(Imm32(0), regs.result);
Jump skip = stubcc.masm.jump();
test.linkTo(stubcc.masm.label(), &stubcc.masm);
stubcc.masm.move(Imm32(1), regs.result);
skip.linkTo(stubcc.masm.label(), &stubcc.masm);
doubleDone = stubcc.masm.jump();
+ }
- /* Link all incoming slow paths to here. */
- if (lhsNotDouble.isSet()) {
- lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
- if (rhsNotNumber.isSet())
- rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
- }
- if (rhsNotNumber2.isSet())
- rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+ /* Link all incoming slow paths to here. */
+ if (lhsNotDouble.isSet()) {
+ lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+ if (rhsNotNumber.isSet())
+ rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+ }
+ if (rhsNotNumber2.isSet())
+ rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
- /* Emit the slow path - note full frame syncage. */
- frame.sync(stubcc.masm, Uses(2));
- stubcc.leave();
- OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
- }
+ /* Emit the slow path - note full frame syncage. */
+ frame.sync(stubcc.masm, Uses(2));
+ stubcc.leave();
+ OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
/* Get an integer comparison condition. */
Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
/* Emit the compare & set. */
if (reg.isSet())
masm.branchValue(i32Cond, cmpReg, reg.reg(), regs.result);
else
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -96,38 +96,52 @@ mjit::Compiler::ensureInteger(FrameEntry
stubcc.masm.addDouble(fpreg, fptemp);
stubcc.masm.branchConvertDoubleToInt32(fptemp, data, isDouble, Registers::FPConversionTemp);
stubcc.crossJump(stubcc.masm.jump(), masm.label());
isDouble.linkTo(syncPath, &stubcc.masm);
frame.freeReg(fptemp);
frame.learnType(fe, JSVAL_TYPE_INT32, data);
} else if (!fe->isType(JSVAL_TYPE_INT32)) {
- FPRegisterID fptemp = frame.allocFPReg();
- RegisterID typeReg = frame.tempRegForType(fe);
- frame.pinReg(typeReg);
- RegisterID dataReg = frame.copyDataIntoReg(fe);
- frame.unpinReg(typeReg);
-
- Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
-
- Label syncPath = stubcc.syncExitAndJump(uses);
- stubcc.linkExitDirect(intGuard, stubcc.masm.label());
-
- /* Try an OOL path to truncate doubles representing int32s. */
- Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
- doubleGuard.linkTo(syncPath, &stubcc.masm);
-
- frame.loadDouble(fe, fptemp, stubcc.masm);
- Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
- truncateGuard.linkTo(syncPath, &stubcc.masm);
- stubcc.crossJump(stubcc.masm.jump(), masm.label());
-
- frame.freeReg(fptemp);
- frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+ if (masm.supportsFloatingPoint()) {
+ FPRegisterID fptemp = frame.allocFPReg();
+ RegisterID typeReg = frame.tempRegForType(fe);
+ frame.pinReg(typeReg);
+ RegisterID dataReg = frame.copyDataIntoReg(fe);
+ frame.unpinReg(typeReg);
+
+ Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+ Label syncPath = stubcc.syncExitAndJump(uses);
+ stubcc.linkExitDirect(intGuard, stubcc.masm.label());
+
+ /* Try an OOL path to truncate doubles representing int32s. */
+ Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
+ doubleGuard.linkTo(syncPath, &stubcc.masm);
+
+ frame.loadDouble(fe, fptemp, stubcc.masm);
+ Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
+ truncateGuard.linkTo(syncPath, &stubcc.masm);
+ stubcc.crossJump(stubcc.masm.jump(), masm.label());
+
+ frame.freeReg(fptemp);
+ frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+ } else {
+ RegisterID typeReg = frame.tempRegForType(fe);
+ frame.pinReg(typeReg);
+ RegisterID dataReg = frame.copyDataIntoReg(fe);
+ frame.unpinReg(typeReg);
+
+ Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+ Label syncPath = stubcc.syncExitAndJump(uses);
+ stubcc.linkExitDirect(intGuard, syncPath);
+
+ frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+ }
}
}
void
mjit::Compiler::jsop_bitnot()
{
FrameEntry *top = frame.peek(-1);
@@ -557,16 +571,18 @@ mjit::Compiler::jsop_relational(JSOp op,
}
}
if (frame.haveSameBacking(lhs, rhs)) {
return emitStubCmpOp(stub, target, fused);
} else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
return emitStubCmpOp(stub, target, fused);
} else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
+ if (!masm.supportsFloatingPoint())
+ return emitStubCmpOp(stub, target, fused);
return jsop_relational_double(op, stub, target, fused);
} else if (cx->typeInferenceEnabled() &&
lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
return jsop_relational_int(op, target, fused);
} else {
return jsop_relational_full(op, stub, target, fused);
}
}
@@ -1900,17 +1916,17 @@ mjit::Compiler::jsop_getelem_args()
if (!key.isConstant())
frame.pinReg(key.reg());
RegisterID dataReg = frame.allocReg();
RegisterID typeReg = frame.allocReg();
// Guard on nactual.
if (!hoistedLength) {
- Address nactualAddr(JSFrameReg, StackFrame::offsetOfArgs());
+ Address nactualAddr(JSFrameReg, StackFrame::offsetOfNumActual());
MaybeJump rangeGuard;
if (key.isConstant()) {
JS_ASSERT(key.index() >= 0);
rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, Imm32(key.index()));
} else {
rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, key.reg());
}
stubcc.linkExit(rangeGuard.get(), Uses(2));
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -1525,20 +1525,22 @@ FrameState::merge(Assembler &masm, Chang
*/
/*
* For any changed values we are merging back which we consider to be doubles,
* ensure they actually are doubles. They must be doubles or ints, but we
* do not require stub paths to always generate a double when needed.
* :FIXME: we check this on OOL stub calls, but not inline stub calls.
*/
- for (unsigned i = 0; i < changes.nchanges; i++) {
- FrameEntry *fe = a->sp - 1 - i;
- if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
- masm.ensureInMemoryDouble(addressOf(fe));
+ if (cx->typeInferenceEnabled()) {
+ for (unsigned i = 0; i < changes.nchanges; i++) {
+ FrameEntry *fe = a->sp - 1 - i;
+ if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
+ masm.ensureInMemoryDouble(addressOf(fe));
+ }
}
uint32_t mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
Registers search(mask);
while (!search.empty(mask)) {
AnyRegisterID reg = search.peekReg(mask);
FrameEntry *fe = regstate(reg).usedBy();
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -1431,17 +1431,17 @@ LoopState::restoreInvariants(jsbytecode
Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
masm.loadFrameActuals(outerScript->function(), T0);
masm.storePayload(T0, address);
break;
}
case InvariantEntry::INVARIANT_ARGS_LENGTH: {
Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
- masm.load32(Address(JSFrameReg, StackFrame::offsetOfArgs()), T0);
+ masm.load32(Address(JSFrameReg, StackFrame::offsetOfNumActual()), T0);
masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), T0, address);
break;
}
case InvariantEntry::INVARIANT_PROPERTY: {
uint32_t object = entry.u.property.objectSlot;
Jump notObject = masm.testObject(Assembler::NotEqual, frame.addressOf(object));
jumps->append(notObject);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2434,17 +2434,17 @@ GetElementIC::attachArguments(VMFrame &f
masm.loadValueAsComponents(frameEntry, typeReg, objReg);
}
Jump done2 = masm.jump();
notFormalArg.linkTo(masm.label(), &masm);
masm.push(typeReg);
- Address argsObject(typeReg, StackFrame::offsetOfArgs());
+ Address argsObject(typeReg, StackFrame::offsetOfArgsObj());
masm.loadPtr(argsObject, typeReg);
masm.load32(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)),
typeReg);
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), typeReg);
/* This basically does fp - (numFormalArgs + numActualArgs + 2) */
@@ -2532,16 +2532,24 @@ GetElementIC::attachTypedArray(VMFrame &
// Load the array's packed data vector.
masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
Int32Key key = idRemat.isConstant()
? Int32Key::FromConstant(v.toInt32())
: Int32Key::FromRegister(idRemat.dataReg());
JSObject *tarray = js::TypedArray::getTypedArray(obj);
+ if (!masm.supportsFloatingPoint() &&
+ (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+ TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64 ||
+ TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT32))
+ {
+ return disable(cx, "fpu not supported");
+ }
+
MaybeRegisterID tempReg;
masm.loadFromTypedArray(TypedArray::getType(tarray), objReg, key, typeReg, objReg, tempReg);
Jump done = masm.jump();
updatePCCounters(cx, masm);
PICLinker buffer(masm, *this);
@@ -2824,16 +2832,23 @@ SetElementIC::attachTypedArray(VMFrame &
outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
else
outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
// Load the array's packed data vector.
masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
JSObject *tarray = js::TypedArray::getTypedArray(obj);
+ if (!masm.supportsFloatingPoint() &&
+ (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+ TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64))
+ {
+ return disable(cx, "fpu not supported");
+ }
+
int shift = js::TypedArray::slotWidth(obj);
if (hasConstantKey) {
Address addr(objReg, keyValue * shift);
if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
return error(cx);
} else {
Assembler::Scale scale = Assembler::TimesOne;
switch (shift) {
--- a/js/src/tests/js1_4/Functions/function-001.js
+++ b/js/src/tests/js1_4/Functions/function-001.js
@@ -92,17 +92,17 @@ new TestCase(
SECTION,
"return arguments when function contains an arguments property",
"PASS",
TestFunction_3( "P", "A", "S", "S" ) +"");
new TestCase(
SECTION,
"return function.arguments when function contains an arguments property",
- "PASS",
+ "[object Arguments]",
TestFunction_4( "F", "A", "I", "L" ) +"");
test();
function TestFunction_1( a, b, c, d, e ) {
return arguments;
}
@@ -111,12 +111,12 @@ function TestFunction_2( a, b, c, d, e )
}
function TestFunction_3( a, b, c, d, e ) {
var arguments = "PASS";
return arguments;
}
function TestFunction_4( a, b, c, d, e ) {
- var arguments = "PASS";
+ var arguments = "FAIL";
return TestFunction_4.arguments;
}
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -166,18 +166,17 @@ class ArgumentsObject : public JSObject
#endif
void initInitialLength(uint32_t length);
void initData(ArgumentsData *data);
public:
/* Create an arguments object for the given callee function and frame. */
- static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee,
- StackFrame *fp);
+ static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee);
/*
* Return the initial length of the arguments. This may differ from the
* current value of arguments.length!
*/
inline uint32_t initialLength() const;
/* True iff arguments.length has been assigned or its attributes changed. */
@@ -216,34 +215,34 @@ class ArgumentsObject : public JSObject
inline void setStackFrame(js::StackFrame *frame);
};
class NormalArgumentsObject : public ArgumentsObject
{
friend bool JSObject::isNormalArguments() const;
friend struct EmptyShape; // for EmptyShape::getEmptyArgumentsShape
friend ArgumentsObject *
- ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp);
+ ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee);
public:
/*
* Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
* been cleared.
*/
inline const js::Value &callee() const;
/* Clear the location storing arguments.callee's initial value. */
inline void clearCallee();
};
class StrictArgumentsObject : public ArgumentsObject
{
friend bool JSObject::isStrictArguments() const;
friend ArgumentsObject *
- ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp);
+ ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee);
};
} // namespace js
js::NormalArgumentsObject &
JSObject::asNormalArguments()
{
JS_ASSERT(isNormalArguments());
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -152,17 +152,17 @@ StackFrame::initCallFrame(JSContext *cx,
LOWERED_CALL_APPLY |
OVERFLOW_ARGS |
UNDERFLOW_ARGS)) == 0);
JS_ASSERT(script == callee.script());
/* Initialize stack frame members. */
flags_ = FUNCTION | HAS_PREVPC | HAS_SCOPECHAIN | HAS_BLOCKCHAIN | flagsArg;
exec.fun = &callee;
- args.nactual = nactual;
+ u.nactual = nactual;
scopeChain_ = callee.environment();
ncode_ = NULL;
initPrev(cx);
blockChain_= NULL;
JS_ASSERT(!hasBlockChain());
JS_ASSERT(!hasHookData());
JS_ASSERT(annotation() == NULL);
JS_ASSERT(!hasCallObj());
@@ -218,17 +218,17 @@ StackFrame::initJitFrameCallerHalf(Stack
/*
* The "early prologue" refers to either the fast path or arity check path up
* to the "late prologue".
*/
inline void
StackFrame::initJitFrameEarlyPrologue(JSFunction *fun, uint32_t nactual)
{
exec.fun = fun;
- args.nactual = nactual;
+ u.nactual = nactual;
}
/*
* The "late prologue" (in generatePrologue) extends from the join point of the
* fast path and arity check to where the call object is (possibly) created.
*/
inline bool
StackFrame::initJitFrameLatePrologue(JSContext *cx, Value **limit)
@@ -321,56 +321,54 @@ struct CopyTo
return true;
}
};
inline uintN
StackFrame::numActualArgs() const
{
/*
- * args.nactual is always coherent, except for method JIT frames where the
+ * u.nactual is always coherent, except for method JIT frames where the
* callee does not access its arguments and the number of actual arguments
* matches the number of formal arguments. The JIT requires that all frames
* which do not have an arguments object and use their arguments have a
- * coherent args.nactual (even though the below code may not use it), as
+ * coherent u.nactual (even though the below code may not use it), as
* JIT code may access the field directly.
*/
JS_ASSERT(hasArgs());
if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
- return hasArgsObj() ? argsObj().initialLength() : args.nactual;
+ return u.nactual;
return numFormalArgs();
}
inline Value *
StackFrame::actualArgs() const
{
JS_ASSERT(hasArgs());
Value *argv = formalArgs();
- if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS)) {
- uintN nactual = hasArgsObj() ? argsObj().initialLength() : args.nactual;
- return argv - (2 + nactual);
- }
+ if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
+ return argv - (2 + u.nactual);
return argv;
}
inline Value *
StackFrame::actualArgsEnd() const
{
JS_ASSERT(hasArgs());
if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
return formalArgs() - 2;
return formalArgs() + numActualArgs();
}
inline void
StackFrame::setArgsObj(ArgumentsObject &obj)
{
- JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
+ JS_ASSERT_IF(hasArgsObj(), &obj == argsObj_);
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.initialLength());
- args.obj = &obj;
+ argsObj_ = &obj;
flags_ |= HAS_ARGS_OBJ;
}
inline void
StackFrame::setScopeChainNoCallObj(JSObject &obj)
{
#ifdef DEBUG
JS_ASSERT(&obj != NULL);
@@ -459,20 +457,18 @@ StackFrame::functionEpilogue()
if (maintainNestingState())
types::NestingEpilogue(this);
}
inline void
StackFrame::updateEpilogueFlags()
{
if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
- if (hasArgsObj() && !argsObj().maybeStackFrame()) {
- args.nactual = args.obj->initialLength();
+ if (hasArgsObj() && !argsObj().maybeStackFrame())
flags_ &= ~HAS_ARGS_OBJ;
- }
if (hasCallObj() && !callObj().maybeStackFrame()) {
/*
* For function frames, the call object may or may not have have an
* enclosing DeclEnv object, so we use the callee's parent, since
* it was the initial scope chain. For global (strict) eval frames,
* there is no callee, but the call object's parent is the initial
* scope chain.
*/
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -83,23 +83,23 @@ StackFrame::initExecuteFrame(JSScript *s
flags_ |= (prev->flags_ & (FUNCTION | GLOBAL));
Value *dstvp = (Value *)this - 2;
dstvp[1] = thisv;
if (isFunctionFrame()) {
dstvp[0] = prev->calleev();
exec = prev->exec;
- args.script = script;
+ u.evalScript = script;
} else {
JS_ASSERT(isGlobalFrame());
dstvp[0] = NullValue();
exec.script = script;
#ifdef DEBUG
- args.script = (JSScript *)0xbad;
+ u.evalScript = (JSScript *)0xbad;
#endif
}
scopeChain_ = &scopeChain;
prev_ = prev;
prevpc_ = regs ? regs->pc : (jsbytecode *)0xbad;
prevInline_ = regs ? regs->inlined() : NULL;
blockChain_ = NULL;
@@ -229,36 +229,17 @@ StackSegment::contains(const FrameRegs *
bool
StackSegment::contains(const CallArgsList *call) const
{
if (!call || !calls_)
return false;
/* NB: this depends on the continuity of segments in memory. */
Value *vp = call->array();
- bool ret = vp > slotsBegin() && vp <= calls_->array();
-
- /*
- * :XXX: Disabled. Including this check changes the asymptotic complexity
- * of code which calls this function.
- */
-#if 0
-#ifdef DEBUG
- bool found = false;
- for (CallArgsList *c = maybeCalls(); c->argv() > slotsBegin(); c = c->prev()) {
- if (c == call) {
- found = true;
- break;
- }
- }
- JS_ASSERT(found == ret);
-#endif
-#endif
-
- return ret;
+ return vp > slotsBegin() && vp <= calls_->array();
}
StackFrame *
StackSegment::computeNextFrame(const StackFrame *f) const
{
JS_ASSERT(contains(f) && f != fp());
StackFrame *next = fp();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -355,27 +355,27 @@ class StackFrame
private:
mutable uint32_t flags_; /* bits described by Flags */
union { /* describes what code is executing in a */
JSScript *script; /* global frame */
JSFunction *fun; /* function frame, pre GetScopeChain */
} exec;
union { /* describes the arguments of a function */
- uintN nactual; /* before js_GetArgsObject */
- ArgumentsObject *obj; /* after js_GetArgsObject */
- JSScript *script; /* eval has no args, but needs a script */
- } args;
+ uintN nactual; /* for non-eval frames */
+ JSScript *evalScript; /* the script of an eval-in-function */
+ } u;
mutable JSObject *scopeChain_; /* current scope chain */
StackFrame *prev_; /* previous cx->regs->fp */
void *ncode_; /* return address for method JIT */
/* Lazily initialized */
Value rval_; /* return value of the frame */
StaticBlockObject *blockChain_; /* innermost let block */
+ ArgumentsObject *argsObj_; /* if has HAS_ARGS_OBJ */
jsbytecode *prevpc_; /* pc of previous frame*/
JSInlinedSite *prevInline_; /* inlined site in previous frame */
void *hookData_; /* closure returned by call hook */
void *annotation_; /* perhaps remove with bug 546848 */
JSRejoinState rejoin_; /* If rejoining into the interpreter
* from JIT code, state at rejoin. */
static void staticAsserts() {
@@ -573,23 +573,23 @@ class StackFrame
JSInlinedSite *prevInline() {
JS_ASSERT(flags_ & HAS_PREVPC);
return prevInline_;
}
JSScript *script() const {
JS_ASSERT(isScriptFrame());
return isFunctionFrame()
- ? isEvalFrame() ? args.script : fun()->script()
+ ? isEvalFrame() ? u.evalScript : fun()->script()