2012-03-14 36 views
9

Trong ứng dụng của tôi, sẽ có một tin nhắn thông báo gửi khi có hành động. Bây giờ làm cách nào để đảm bảo rằng SMS sẽ được gửi?Cách đảm bảo SMS được gửi trong Android

Ví dụ: nếu không có mạng hoặc thẻ sim bị xóa, làm cách nào để đảm bảo rằng tin nhắn sẽ được gửi sau khi có mạng khả dụng sau này? Có thể thêm sms vào hàng đợi không?

Điều này có khả thi không?

Thanks Trong Advance, Perumal

Trả lời

2

Bạn có thể nắm bắt trạng thái đã gửi/gửi SMS bằng thiết bị phát sóng. BroadcastReceiver phải được đăng ký trước khi bạn gửi tin nhắn SMS. Tôi sử dụng thực hiện này, cùng với một lớp cha mẹ, để có được kết quả của hoạt động lên đến SENT hoặc DELIVERED trạng thái (phải chọn một trong hai)

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); 
     } 
    } 

} 
0

Đối với các vấn đề đã đề cập, xin vui lòng xem Notify if a message you sent was sent successfully or not in Android và xem câu trả lời của Rupesh Yadav .. Nó sử dụng pendingIntent và BroadcastReceiver để lưu ý nếu một tin nhắn được gửi thành công hay không với điều kiện SWITCH đơn giản .. Nó làm việc cho tôi ..

Các vấn đề liên quan