Bug 713377 - Part 2 - Don't build GeckoSmsManager.java when WebSMS backend is disabled. r=dougt,cjones
authorMounir Lamouri <mounir.lamouri@gmail.com>
Tue, 17 Jan 2012 19:38:04 +0100
changeset 84735 4deac0f12db9325e8f9c94dc6983fd7df1cb260b
parent 84734 544fd25dfc6121e70ecfbca52a87a6a9b34d1b41
child 84736 c199854a52b76bfc0036fe694f7b46d04414bc21
push id21873
push usermlamouri@mozilla.com
push dateWed, 18 Jan 2012 10:29:07 +0000
treeherdermozilla-central@7538f4d4697c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt, cjones
bugs713377
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 713377 - Part 2 - Don't build GeckoSmsManager.java when WebSMS backend is disabled. r=dougt,cjones
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/GeckoSmsManager.java
embedding/android/Makefile.in
embedding/android/SmsManager.java.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoSmsManager.java
mobile/android/base/Makefile.in
mobile/android/base/SmsManager.java.in
--- 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,24 +408,19 @@ 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(GeckoSmsManager.ACTION_SMS_RECEIVED);
-        smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
-        smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
-        mSmsReceiver = new GeckoSmsManager();
-        registerReceiver(mSmsReceiver, smsFilter);
-
-        GeckoSmsManager.init();
+        if (SmsManager.getInstance() != null) {
+            SmsManager.getInstance().init();
+        }
 
         if (!checkAndSetLaunchState(LaunchState.PreLaunch,
                                     LaunchState.Launching))
             return;
 
         checkAndLaunchUpdate();
         mLibLoadThread = new Thread(new Runnable() {
             public void run() {
@@ -571,26 +565,27 @@ abstract public class GeckoApp
         super.onStart();
     }
 
     @Override
     public void onDestroy()
     {
         Log.i(LOG_FILE_NAME, "destroy");
 
-        GeckoSmsManager.shutdown();
-
         // 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();
+        }
+
         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
@@ -1696,45 +1696,77 @@ 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) {
-        GeckoSmsManager.send(aNumber, aMessage, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().send(aNumber, aMessage, aRequestId, aProcessId);
     }
 
     public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
-        return GeckoSmsManager.saveSentMessage(aRecipient, aBody, aDate);
+        if (SmsManager.getInstance() == null) {
+            return -1;
+        }
+
+        return SmsManager.getInstance().saveSentMessage(aRecipient, aBody, aDate);
     }
 
     public static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
-        GeckoSmsManager.getMessage(aMessageId, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getMessage(aMessageId, aRequestId, aProcessId);
     }
 
     public static void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
-        GeckoSmsManager.deleteMessage(aMessageId, aRequestId, 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) {
-        GeckoSmsManager.createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, 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) {
-        GeckoSmsManager.getNextMessageInList(aListId, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getNextMessageInList(aListId, aRequestId, aProcessId);
     }
 
     public static void clearMessageList(int aListId) {
-        GeckoSmsManager.clearMessageList(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
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -43,16 +43,17 @@ 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;
 
@@ -314,16 +315,17 @@ class MessagesListManager
     }
 
     mCursors.clear();
   }
 }
 
 public class GeckoSmsManager
   extends BroadcastReceiver
+  implements ISmsManager
 {
   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
@@ -349,17 +351,24 @@ public class GeckoSmsManager
    */
   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 static void init() {
+  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(ACTION_SMS_RECEIVED)) {
       // TODO: Try to find the receiver number to be able to populate
       //       SmsMessage.receiver.
@@ -475,21 +484,21 @@ public class GeckoSmsManager
           !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, int aRequestId, long aProcessId) {
+  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);
 
@@ -513,22 +522,22 @@ public class GeckoSmsManager
          * - 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.surfaceView.getContext(),
+          PendingIntent.getBroadcast(GeckoApp.mAppContext,
                                      PendingIntentUID.generate(), sentIntent,
                                      PendingIntent.FLAG_CANCEL_CURRENT);
 
         PendingIntent deliveredPendingIntent =
-          PendingIntent.getBroadcast(GeckoApp.surfaceView.getContext(),
+          PendingIntent.getBroadcast(GeckoApp.mAppContext,
                                      PendingIntentUID.generate(), deliveredIntent,
                                      PendingIntent.FLAG_CANCEL_CURRENT);
 
         sm.sendTextMessage(aNumber, "", aMessage,
                            sentPendingIntent, deliveredPendingIntent);
       } else {
         ArrayList<String> parts = sm.divideMessage(aMessage);
         envelopeId = Postman.getInstance().createEnvelope(parts.size());
@@ -539,23 +548,23 @@ public class GeckoSmsManager
 
         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.surfaceView.getContext(),
+            PendingIntent.getBroadcast(GeckoApp.mAppContext,
                                        PendingIntentUID.generate(), sentIntent,
                                        PendingIntent.FLAG_CANCEL_CURRENT)
           );
 
           deliveredPendingIntents.add(
-            PendingIntent.getBroadcast(GeckoApp.surfaceView.getContext(),
+            PendingIntent.getBroadcast(GeckoApp.mAppContext,
                                        PendingIntentUID.generate(), deliveredIntent,
                                        PendingIntent.FLAG_CANCEL_CURRENT)
           );
         }
 
         sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
                                     deliveredPendingIntents);
       }
@@ -565,26 +574,26 @@ public class GeckoSmsManager
       if (envelopeId != Postman.kUnknownEnvelopeId) {
         Postman.getInstance().destroyEnvelope(envelopeId);
       }
 
       GeckoAppShell.notifySmsSendFailed(kUnknownError, aRequestId, aProcessId);
     }
   }
 
-  public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
+  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.surfaceView.getContext().getContentResolver();
+      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();
@@ -595,17 +604,17 @@ public class GeckoSmsManager
       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 static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+  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;
@@ -617,17 +626,17 @@ public class GeckoSmsManager
         class NotFoundException extends Exception { }
         class UnmatchingIdException extends Exception { }
         class TooManyResultsException extends Exception { }
         class InvalidTypeException extends Exception { }
 
         Cursor cursor = null;
 
         try {
-          ContentResolver cr = GeckoApp.surfaceView.getContext().getContentResolver();
+          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) {
@@ -682,34 +691,34 @@ public class GeckoSmsManager
     }
 
     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 static void deleteMessage(int aMessageId, int aRequestId, long 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.surfaceView.getContext().getContentResolver();
+          ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
           Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
 
           int count = cr.delete(message, null, null);
 
           if (count > 1) {
             throw new TooManyResultsException();
           }
 
@@ -725,17 +734,17 @@ public class GeckoSmsManager
     }
 
     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 static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long 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;
@@ -794,17 +803,17 @@ public class GeckoSmsManager
           }
 
           String restrictionText = restrictions.size() > 0 ? restrictions.get(0) : "";
 
           for (int i=1; i<restrictions.size(); ++i) {
             restrictionText += " AND " + restrictions.get(i);
           }
 
-          ContentResolver cr = GeckoApp.surfaceView.getContext().getContentResolver();
+          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;
           }
 
@@ -848,17 +857,17 @@ public class GeckoSmsManager
     }
 
     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 static void getNextMessageInList(int aListId, int aRequestId, long 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;
@@ -907,17 +916,19 @@ public class GeckoSmsManager
     }
 
     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 static void clearMessageList(int aListId) {
+  public void clearMessageList(int aListId) {
     MessagesListManager.getInstance().remove(aListId);
   }
 
-  public static void shutdown() {
+  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,29 @@ JAVAFILES = \
   GeckoAppShell.java \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceInfo.java \
   GeckoBatteryManager.java \
-  GeckoSmsManager.java \
   VideoPlayer.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/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -116,17 +116,16 @@ abstract public class GeckoApp
     private File mProfileDir;
     private static boolean sIsGeckoReady = false;
     private static int mOrientation;
 
     private IntentFilter mConnectivityFilter;
     private IntentFilter mBatteryFilter;
 
     private BroadcastReceiver mConnectivityReceiver;
-    private BroadcastReceiver mSmsReceiver;
     private BroadcastReceiver mBatteryReceiver;
 
     public static BrowserToolbar mBrowserToolbar;
     public static DoorHangerPopup mDoorHangerPopup;
     public static AutoCompletePopup mAutoCompletePopup;
     public Favicons mFavicons;
 
     private Geocoder mGeocoder;
@@ -1566,24 +1565,19 @@ 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(GeckoSmsManager.ACTION_SMS_RECEIVED);
-        smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
-        smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
-        mSmsReceiver = new GeckoSmsManager();
-        registerReceiver(mSmsReceiver, smsFilter);
-
-        GeckoSmsManager.init();
+        if (SmsManager.getInstance() != null) {
+          SmsManager.getInstance().init();
+        }
 
         final GeckoApp self = this;
  
         GeckoAppShell.getHandler().postDelayed(new Runnable() {
             public void run() {
                 
                 Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - pre checkLaunchState");
 
@@ -1799,21 +1793,22 @@ abstract public class GeckoApp
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
 
         mFavicons.close();
 
-        GeckoSmsManager.shutdown();
+        if (SmsManager.getInstance() != null) {
+          SmsManager.getInstance().shutdown();
+        }
 
         super.onDestroy();
 
-        unregisterReceiver(mSmsReceiver);
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
     public void onContentChanged() {
         super.onContentChanged();
         if (mAboutHomeContent != null)
             mAboutHomeContent.onActivityContentChanged(this);
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -1639,45 +1639,77 @@ public class GeckoAppShell
     static void hideProgressDialog() {
         // unused stub
     }
 
     /*
      * 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) {
-        GeckoSmsManager.send(aNumber, aMessage, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().send(aNumber, aMessage, aRequestId, aProcessId);
     }
 
     public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
-        return GeckoSmsManager.saveSentMessage(aRecipient, aBody, aDate);
+        if (SmsManager.getInstance() == null) {
+            return -1;
+        }
+
+        return SmsManager.getInstance().saveSentMessage(aRecipient, aBody, aDate);
     }
 
     public static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
-        GeckoSmsManager.getMessage(aMessageId, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getMessage(aMessageId, aRequestId, aProcessId);
     }
 
     public static void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
-        GeckoSmsManager.deleteMessage(aMessageId, aRequestId, 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) {
-        GeckoSmsManager.createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, 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) {
-        GeckoSmsManager.getNextMessageInList(aListId, aRequestId, aProcessId);
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getNextMessageInList(aListId, aRequestId, aProcessId);
     }
 
     public static void clearMessageList(int aListId) {
-        GeckoSmsManager.clearMessageList(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
--- a/mobile/android/base/GeckoSmsManager.java
+++ b/mobile/android/base/GeckoSmsManager.java
@@ -43,16 +43,17 @@ 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;
 
@@ -314,16 +315,17 @@ class MessagesListManager
     }
 
     mCursors.clear();
   }
 }
 
 public class GeckoSmsManager
   extends BroadcastReceiver
+  implements ISmsManager
 {
   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
@@ -349,17 +351,24 @@ public class GeckoSmsManager
    */
   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 static void init() {
+  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(ACTION_SMS_RECEIVED)) {
       // TODO: Try to find the receiver number to be able to populate
       //       SmsMessage.receiver.
@@ -475,21 +484,21 @@ public class GeckoSmsManager
           !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, int aRequestId, long aProcessId) {
+  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);
 
@@ -565,17 +574,17 @@ public class GeckoSmsManager
       if (envelopeId != Postman.kUnknownEnvelopeId) {
         Postman.getInstance().destroyEnvelope(envelopeId);
       }
 
       GeckoAppShell.notifySmsSendFailed(kUnknownError, aRequestId, aProcessId);
     }
   }
 
-  public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
+  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);
 
@@ -595,17 +604,17 @@ public class GeckoSmsManager
       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 static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+  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;
@@ -682,17 +691,17 @@ public class GeckoSmsManager
     }
 
     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 static void deleteMessage(int aMessageId, int aRequestId, long 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;
@@ -725,17 +734,17 @@ public class GeckoSmsManager
     }
 
     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 static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long 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;
@@ -848,17 +857,17 @@ public class GeckoSmsManager
     }
 
     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 static void getNextMessageInList(int aListId, int aRequestId, long 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;
@@ -907,17 +916,19 @@ public class GeckoSmsManager
     }
 
     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 static void clearMessageList(int aListId) {
+  public void clearMessageList(int aListId) {
     MessagesListManager.getInstance().remove(aListId);
   }
 
-  public static void shutdown() {
+  public void shutdown() {
+    GeckoApp.mAppContext.unregisterReceiver(this);
+
     SmsIOThread.getInstance().interrupt();
     MessagesListManager.getInstance().clear();
   }
 }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -78,17 +78,16 @@ FENNEC_JAVA_FILES = \
   GeckoAsyncTask.java \
   GeckoBatteryManager.java \
   GeckoConnectivityReceiver.java \
   GeckoDirProvider.java \
   GeckoEvent.java \
   GeckoEventListener.java \
   GeckoInputConnection.java \
   GeckoPreferences.java \
-  GeckoSmsManager.java \
   GeckoStateListDrawable.java \
   GeckoThread.java \
   GlobalHistory.java \
   LinkPreference.java \
   ProfileMigrator.java \
   PromptService.java \
   SurfaceLockInfo.java \
   Tab.java \
@@ -121,23 +120,28 @@ FENNEC_JAVA_FILES = \
   gfx/TileLayer.java \
   gfx/ViewportMetrics.java \
   gfx/WidgetTileLayer.java \
   ui/Axis.java \
   ui/PanZoomController.java \
   ui/SubdocumentScrollHelper.java \
   $(NULL)
 
+ifdef MOZ_WEBSMS_BACKEND
+FENNEC_JAVA_FILES += GeckoSmsManager.java
+endif
+
 FENNEC_PP_JAVA_FILES = \
   App.java \
   LauncherShortcuts.java \
   NotificationHandler.java \
   Restarter.java \
   db/BrowserContract.java \
   db/BrowserProvider.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/mobile/android/base/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);
+}