2012-03-14 11 views
9

W mojej aplikacji zostanie wysłane powiadomienie wysyłane przez sms po akcji. Jak mogę się upewnić, że SMS zostanie wysłany?Jak upewnić się, że wiadomość SMS zostanie wysłana w systemie Android?

Na przykład, jeśli nie ma usuniętej karty sieciowej lub karty SIM, w jaki sposób mogę zagwarantować, że sms zostanie wysłany, gdy będzie dostępna sieć w późniejszym czasie? Czy można dodać sms do kolejki?

Czy to możliwe?

Dzięki z góry, Perumal

Odpowiedz

2

Można przechwycić SMS wysłany/dostarczenia statusu transmisji z odbiornikiem. BroadcastReceiver musi zostać zarejestrowany przed wysłaniem wiadomości SMS. Używam tego wdrożenia, wraz z klasy nadrzędnej, aby uzyskać wynik działania do stanu SENT lub DELIVERED (należy wybrać jedną z dwóch)

package com.mycie.myapp; 

import java.util.ArrayList; 
import java.util.logging.Level; 

import android.app.Activity; 
import android.app.PendingIntent; 
import android.content.Context; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.SystemClock; 
import android.telephony.SmsManager; 
import android.widget.Toast; 

extern class Sequencer; 
extern class Test; 
extern class Status; 

/** 
* Sends multipart SMS to multiple destinations and verifies the send and 
* deliver status of each part sent away. The operation is a success if all the 
* codes of the SMS_SENT of all the messages sent are equal to 
* {@link Activity#RESULT_OK}. 
*/ 
public class SendSms extends ModemDependentAtom { 

    private static final String LOG_TAG = "SendSms"; 

    // set this flag to true to print many traces to follow the machine state. 
    // NB: DEBUG level traces are always printed for the SEND and DELIVER status 
    // of the part, so you don't need to activate this flag to get them. 
    private static final boolean DEBUG = false; 

    public static final String SMS_DELIVERY = "com.mycie.myapp.SMS_DELIVERY"; 

    public static final String SMS_SENT = "com.mycie.myapp.SMS_SENT"; 

    // infinite time-out 
    public static final int TIMEOUT_INFINITE = -1; 

    // timeout per part. 
    private static final int DEFAULT_TIMEOUT = 10000; 

    private String mSmsNumber; 

    private String mSmsBody; 

    private int mTimeout; 

    private long mOrgRealtime; 

    private SendSmsReceiver mSendReceiver; 

    private SendSmsReceiver mDeliverReceiver; 

    private int mNbParts; 

    private int mDestIndex; 

    private int mState; 

    private String[] mNumbers; 

    private ArrayList<String> mParts; 

    private Status mStatus; 

    public enum SmsSendNotification { 
     SEND, 
     DELIVER 
    } 

    private final SmsSendNotification mSignificantNotification; 

    private ArrayList<PendingIntent> mSentIntents; 

    private ArrayList<PendingIntent> mDeliveryIntents; 

    public SendSms(SmsSendNotification significant) { 
     mSignificantNotification = significant; 

     mSmsNumber = ""; 
     mSmsBody = ""; 
     mTimeout = DEFAULT_TIMEOUT; 
     mOrgRealtime = 0; 
     mStatus = Status.NotDone; 
     mState = 0; 

     mSentIntents = new ArrayList<PendingIntent>(); 
     mDeliveryIntents = new ArrayList<PendingIntent>(); 
    } 

    private final class SendCallBack implements SendSmsReceiver.Callback { 

     SendCallBack(Sequencer sequencer, Test test) { 
      mSequencer = sequencer; 
      mTest = test; 
     } 

     private Sequencer mSequencer; 
     private Test mTest; 

     @Override 
     public void onPartResult(int part, int code) { 

      Log.d(LOG_TAG, String.format("SEND part %d: %s", part, 
        SendSmsReceiver.getCodeString(code))); 

      Context context = Controller.controller.getApplication().getApplicationContext(); 

      if (mSendReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) == -1) { 
       // no more sent notification to receive. 
       int globalCode = mSendReceiver.findNotCode(Activity.RESULT_OK); 

       if (globalCode == -1) { 
        // all part were sent successfully. 
        globalCode = Activity.RESULT_OK; 
       } else { 
        // at least one part failed to be sent. 
        mSequencer.onTestEvent(mTest, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
          "one or more parts failed to be sent"); //$NON-NLS-1$ 

        mTest.setStatus(Status.Error); 
        mStatus = Status.Executed; 
       } 

       Log.d(LOG_TAG, "SMS send result: " + SendSmsReceiver.getCodeString(globalCode)); 

       Toast.makeText(context, 
         "SEND: " + SendSmsReceiver.getCodeString(globalCode), 
         Toast.LENGTH_LONG).show(); 
      } 
     } 
    }; 

    private final class DeliverCallBack implements SendSmsReceiver.Callback { 

     DeliverCallBack(Sequencer sequencer, Test test) { 
      mSequencer = sequencer; 
      mTest = test; 
     } 

     private Sequencer mSequencer; 
     private Test mTest; 

     @Override 
     public void onPartResult(int part, int code) { 

      Log.d(LOG_TAG, String.format("DELIVER part %d: %s", part, 
        SendSmsReceiver.getCodeString(code))); 

      if (mDeliverReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) == -1) { 
       // no more delivery notification to receive. 
       int globalCode = mDeliverReceiver.findNotCode(Activity.RESULT_OK); 

       if (globalCode == -1) { 
        // all part were sent successfully. 
        globalCode = Activity.RESULT_OK; 
       } else { 
        // at least one part failed to be sent. 
        mSequencer.onTestEvent(mTest, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
          "one or more parts failed to be delivered"); //$NON-NLS-1$ 

        mTest.setStatus(Status.Error); 
        mStatus = Status.Executed; 
       } 

       Context context = Controller.controller.getApplication().getApplicationContext(); 

       Log.d(LOG_TAG, "SMS deliver result: " + SendSmsReceiver.getCodeString(globalCode)); 

       Toast.makeText(context, 
         "DELIVER: " + SendSmsReceiver.getCodeString(globalCode), 
         Toast.LENGTH_LONG).show(); 

       // we can early examine the send results so do it. 
       examine(mSequencer, mTest); 
      } 
     } 
    }; 

    @Override 
    public Status process(Sequencer sequencer, Test test) { 

     if (mState == 0) { 

      mNumbers = PhoneUtils.splitNumbers(mSmsNumber); 

      PhoneUtils.parsePhoneNumbers(mNumbers, new PhoneUtils.PrivilegiateSms()); 

      AppData data = Controller.controller.getData(); 
      SmsManager smsManager = data.services.getSmsManager(); 
      mParts = smsManager.divideMessage(mSmsBody); 
      mNbParts = mParts.size(); 

      Context context = Controller.controller.getApplication().getApplicationContext(); 
      mSendReceiver = SendSmsReceiver.getInstance(context, 
        sequencer.getPosition(), SMS_SENT, new SendCallBack(sequencer, test)); 
      mDeliverReceiver = SendSmsReceiver.getInstance(context, 
        sequencer.getPosition(), SMS_DELIVERY, new DeliverCallBack(sequencer, test)); 

      if (DEBUG) { 
       Log.d(LOG_TAG, "broadcast receivers created."); 
      } 

      mDestIndex = 0; 
      if (DEBUG) { 
       Log.d(LOG_TAG, "state=1"); 
      } 
      mState = 1; 

      process(sequencer, test); 

      mStatus = Status.Active; 

     } else if (mState == 1) { 

      if (mDestIndex < mNumbers.length) { 
       Log.i(LOG_TAG, "Sending SMS to " + mNumbers[mDestIndex] + "..."); 
       Status result = sendMultipartText(sequencer, test, mNumbers[mDestIndex]); 
       if (result == Status.Error) { 
        // error: fail to send to a receiver. 
        test.setStatus(Status.Error); 

        mStatus = Status.Executed; 
       } else { 
        if (DEBUG) { 
         Log.d(LOG_TAG, "state=2"); 
        } 
        mState = 2; 
       } 
      } else { 
       // no more: completed. 
       if (DEBUG) { 
        Log.d(LOG_TAG, "No more recipient. Test OK."); 
       } 

       mStatus = Status.Executed; 
      } 

     } else if (mState == 2) { 
      if (mModemReset) { 

       sequencer.onTestEvent(test, Level.SEVERE, Sequencer.EXTERNAL_ERROR, 
         "the test probably caused a modem reset"); //$NON-NLS-1$ 

       test.setStatus(Status.Error); 
       mStatus = Status.Error; 

       mModemReset = false; 
      } 
      // wait for status to change. Force examination if timeout expires. 
      else if (isTimerExpired()) { 
       if (DEBUG) { 
        Log.d(LOG_TAG, "timeout"); 
       } 
       examine(sequencer, test); 
      } 
     } else { 
      // what? 
     } 

     if (mStatus != Status.Active) { 
      if (DEBUG) { 
       Log.d(LOG_TAG, "status = " + mStatus); 
      } 
     } else { 
      sequencer.wakeAfter(0); 
     } 

     return mStatus; 
    } 

    @Override 
    public void onFinalRelease(Status unused) { 
     super.onFinalRelease(unused); 

     if (DEBUG) { 
      Log.d(LOG_TAG, "broadcast receivers released."); 
     } 

     cancelPendingIntents(); 

     if (mSendReceiver != null) { 
      mSendReceiver.discard(); 
      mSendReceiver = null; 
     } 

     if (mDeliverReceiver != null) { 
      mDeliverReceiver.discard(); 
      mDeliverReceiver = null; 
     } 
    } 

    @Override 
    public void reset() { 
     super.reset(); 

     mState = 0; 
     if (DEBUG) { 
      Log.d(LOG_TAG, "state=0"); 
     } 

     mStatus = Status.NotDone; 
    } 

    public void examine(Sequencer sequencer, Test test) { 

     // If a SENT result is missing then the test failed due to timeout. The 
     // method should have been called by the timeout handler, if not this is 
     // a programming error. 
     if (mSendReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) != -1) { 

      sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
        "not all send results received before timeout"); //$NON-NLS-1$ 

      test.setStatus(Status.Error); 
      mStatus = Status.Executed; 
     } 

     // If one or more SENT failed then the test failed. 
     else if (mSendReceiver.findNotCode(Activity.RESULT_OK) != -1) { 

      sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
        "failed to send at least one SMS part."); //$NON-NLS-1$ 

      test.setStatus(Status.Error); 
      mStatus = Status.Executed; 
     } 

     // Otherwise, if DELIVER is the significant notification then the 
     // test fails if there is one or more delivery failed. 
     else if (mSignificantNotification.equals(SmsSendNotification.DELIVER)) { 
      if (mDeliverReceiver.findCode(SendSmsReceiver.RESULT_UNDEFINED) != -1) { 

       // failed due to timeout on DELIVERY 
       sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
         "not all delivery results received before timeout"); //$NON-NLS-1$ 

       test.setStatus(Status.Error); 
       mStatus = Status.Executed; 

      } else if (mDeliverReceiver.findNotCode(Activity.RESULT_OK) != -1) { 

       // at least on part delivery failed. 
       sequencer.onTestEvent(test, Level.SEVERE, Sequencer.TEST_EXCEPTION, 
         "failed to deliver at least one SMS part."); //$NON-NLS-1$ 

       test.setStatus(Status.Error); 
       mStatus = Status.Executed; 

      } else { 
       // OK, proceed with next number. 
       if (DEBUG) { 
        Log.d(LOG_TAG, "send to next recipient, if any."); 
       } 
       mDestIndex ++; 
       mState = 1; 
      } 
     } else { 
      // SEND is significant and all SENT were OK: proceed with next number. 
      if (DEBUG) { 
       Log.d(LOG_TAG, "send to next receiver, if any."); 
      } 
      mDestIndex ++; 
      mState = 1; 
     } 
    } 

    private Status sendMultipartText(Sequencer sequencer, Test test, 
      String number) { 

     Intent sent; 
     Intent delivery; 
     PendingIntent sentIntent; 
     PendingIntent deliveryIntent; 

     AppData data = Controller.controller.getData(); 
     SmsManager smsManager = data.services.getSmsManager(); 
     Context context = Controller.controller.getApplication().getApplicationContext(); 

     if (mNbParts > 1) { 
      Log.i(LOG_TAG, String.format("SMS is devided in %d parts.", mNbParts)); 
     } 

     cancelPendingIntents(); 

     String serial = getNewSerial(number); 

     int iPart; 
     for (iPart = 0; iPart < mNbParts; iPart++) { 
      Uri uri = new Uri.Builder() 
       .scheme(String.format("pos%d", sequencer.getPosition())) 
       .authority(serial) 
       .appendQueryParameter("part", Integer.toString(iPart)) 
       .build(); 
      sent = new Intent(SMS_SENT, uri); 

      sentIntent = PendingIntent.getBroadcast(context, 0, sent, 0); 
      if (sentIntent == null) { 
       sequencer.onTestEvent(test, Level.SEVERE, Sequencer.PROGRAM_ERROR, 
         "null " + SMS_SENT + " intent"); //$NON-NLS-1$ 
       return Status.Error; 
      } 

      mSentIntents.add(sentIntent); 

      delivery = new Intent(SMS_DELIVERY, uri); 

      deliveryIntent = PendingIntent.getBroadcast(context, 0, delivery, 0); 
      if (deliveryIntent == null) { 
       sequencer.onTestEvent(test, Level.SEVERE, Sequencer.PROGRAM_ERROR, 
         "null " + SMS_DELIVERY + " intent"); 
       return Status.Error; 
      } 

      mDeliveryIntents.add(deliveryIntent); 
     } 

     this.mOrgRealtime = SystemClock.elapsedRealtime(); 
     if (DEBUG) { 
      Log.d(LOG_TAG, "timeout: " + getRealTimeout()); 
     } 

     mSendReceiver.restart(serial, mNbParts); 
     mDeliverReceiver.restart(serial, mNbParts); 

     smsManager.sendMultipartTextMessage(number, null, 
       mParts, mSentIntents, mDeliveryIntents); 

     return Status.Executed; 
    } 

    private static String getNewSerial(String number) { 
     String serial = number + "." + SystemClock.uptimeMillis(); 
     return serial; 
    } 

    private void cancelPendingIntents() { 
     // cancel precedent pending intents. 
     for (PendingIntent pi : mSentIntents) { 
      pi.cancel(); 
     } 
     mSentIntents.clear(); 

     for (PendingIntent pi : mDeliveryIntents) { 
      pi.cancel(); 
     } 
     mDeliveryIntents.clear(); 
    } 

    private boolean isTimerExpired() { 
     boolean expired = false; 

     long timeout = getRealTimeout(); 
     if (timeout > 0) { 
      if (mOrgRealtime <= 0) { 
       mOrgRealtime = SystemClock.elapsedRealtime(); 
      } else { 
       long elapsed = SystemClock.elapsedRealtime() - mOrgRealtime; 
       if (elapsed > timeout) { 
        expired = true; 
       } 
      } 
     } 

     return expired; 
    } 

    private long getRealTimeout() { 
     long timeout; 

     if (mTimeout > 0) { 
      if (mSignificantNotification.equals(SmsSendNotification.SEND)) { 
       timeout = mTimeout * mNbParts; 
      } else { 
       // double the times if DELIVER is the significant status. 
       timeout = 2 * mTimeout * mNbParts; 
      } 
     } else { 
      timeout = TIMEOUT_INFINITE; 
     } 

     return timeout; 
    } 

    public void setTimeout(int timeout) { 
     mTimeout = timeout; 
    } 

    public void setNumber(final String number) { 
     mSmsNumber = PhoneUtils.normalizeList(number); 
    } 

    public String getNumber() { 
     return mSmsNumber; 
    } 

    public void setBody(final String body) { 
     mSmsBody = body; 
    } 

    public String getBody() { 
     return mSmsBody; 
    } 

    /** 
    * Send a text message to one or many receivers and forget about the 
    * notifications. 
    * @param number receiver(s) number(s), separated by a comma if more than one. 
    * @param text to send 
    */ 
    public static void sendMessage(String number, String text) { 
     AppData data = Controller.controller.getData(); 
     SmsManager smsManager = data.services.getSmsManager(); 

     ArrayList<String> parts = smsManager.divideMessage(text); 
     Log.d(LOG_TAG, String.format("sending SMS composed of %d parts.", parts.size())); //$NON-NLS-1$ 

     String[] array = PhoneUtils.splitNumbers(number); 
     for (String n : array) { 
      smsManager.sendMultipartTextMessage(n, null, parts, null, null); 
     } 
    } 

} 
Powiązane problemy