9

アプリケーションから緊急の SMS を送信しようとしています。SMS が正常に送信されていることを確認する必要があります。

SMS は、Android システムの起動後、チェックが行われた後に送信されています。

したがって、BOOT_COMPLETED インテント フィルターを処理するサービス クラスがあります。このクラスはチェックを行い、何かが真である場合、「サービスを拡張する」別のクラスを介して SMS メッセージを送信しようとします。

SMS が正常に送信されたことを確認したら、両方のサービス (ブート呼び出しを処理するサービスと SMS を送信するサービス) を終了する必要があります。

質問 1 : アプリケーションが応答しないというメッセージを取得せずに、SMS 送信関数をタイムアウト付きで呼び出すにはどうすればよいですか? 現在、私はこれを使用しています(動作しますが、正しい方法であるかどうかはわかりません):

Timer mTimer = new Timer();
//wait a small timeout prior to sending the message.
mTimer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        this.cancel(); //I don't want to run the timer more than once
        sms_sender sms = new sms_sender();
        sms.sendSMS(phoneNumber, messageText);
    }
}, 30000, 30000); //run sendSMS() after 30 seconds

質問 2 : sendSMS 関数を実装して、最後の試行が失敗したことに気付いた後、30 秒ごとに再試行するようにするにはどうすればよいですか?

質問 3 : SMS が正常に送信されたことに気付いた後、両方のサービスを停止するにはどうすればよいですか?

これは動作しない私のコードです:

public class sms_sender extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    final String SENT = "SMS_SENT";

    public void sendSMS(final String phoneNumber, final String message, final boolean check_result)
    {

        PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
        registerReceiver(new BroadcastReceiver(){
            @Override
            public void onReceive(Context arg0, Intent arg1) {
                if(!check_result)
                    return;
                switch (getResultCode())
                {
                    case Activity.RESULT_OK:
                        //exit
                        stopSelf();
                        return;
                    case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    case SmsManager.RESULT_ERROR_NO_SERVICE:
                    case SmsManager.RESULT_ERROR_NULL_PDU:
                    case SmsManager.RESULT_ERROR_RADIO_OFF:
                        //try again in 1 minute
                        Timer mTimer = new Timer();
                        mTimer.scheduleAtFixedRate(new TimerTask() {
                            @Override
                            public void run() {
                                this.cancel(); //no need to run again, if it fails, this exact code will run again
                                sendSMS(phoneNumber, message, true);
                            }
                        }, 60000, 60000);
                        return;
                }
            }
        }, new IntentFilter(SENT));

        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendTextMessage(phoneNumber, null, message, sentPI, null);
    }
}

現在、プログラムは PendingIntent 呼び出しでクラッシュします。onCreate メソッドにプライベート メンバー変数を使用して BroadCastReceiver を実装し、onReceive メソッドを介して sendSMS() 関数を再度呼び出そうとしましたが、onReceive は実行されないようでした。

- 編集 -

これが私の最終的な作業コードです。UIスレッドでは機能しないため、私のケースは特別だと思います。ブートで実行されるブロードキャスト レシーバーがあります。正常に送信されるまで SMS メッセージを送信しようとしています。

この Boot Broadcast Receiver はサービスを開始します。これはそれからのいくつかのコードです:

public class service extends Service{

    static public service serv;
    //member variable. Initializing to null so as to know whether to unregister the service or not
    private BroadcastReceiver messageSent = null;

    ...
    ...
    @Override
    public void onStart(Intent intent, int startid)
    {
    serv=this; //will use this static variable in order to shutdown the service when the message is successfully sent
    ...
    ...
        if(somethingIsTrue()){
            //register receiver
            messageSent = new sent_message();
            registerReceiver(messageSent, new IntentFilter(sms_sender.INTENT_MESSAGE_SENT));
            startMessageServiceIntent(messageText, phoneNumber); //function code can be found on accepted answer
        }
    }
}

sent_message クラスは次のとおりです。

public class sent_message extends BroadcastReceiver {

    private Context pubCon;

    private void startMessageServiceIntent(String message, String receiver) {
        Intent i = new Intent(pubCon, sms_sender.class);
        i.putExtra(sms_sender.EXTRA_MESSAGE, message);
        i.putExtra(sms_sender.EXTRA_RECEIVERS, new String[] { receiver });
        pubCon.startService(i);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        pubCon=context;
        switch (getResultCode()) {
            case Activity.RESULT_OK:
                    //all went OK, stop the service where this is called from
                service.serv.stopSelf();
                break;
            case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
            case SmsManager.RESULT_ERROR_NO_SERVICE:
            case SmsManager.RESULT_ERROR_NULL_PDU:
            case SmsManager.RESULT_ERROR_RADIO_OFF:
                    //try sending the message again after 30s
                new Handler().postDelayed(new Runnable(){
                    @Override
                    public void run(){
                        startMessageServiceIntent(service.messageText, service.phoneNumber);
                    }
                }, 30000);

                break;
        }

    }
}

また、sms_sender クラスの単純化された (1 つの受信者のみを受け入れる) バージョンは次のとおりです。

public class sms_sender extends IntentService {

    public static final String INTENT_MESSAGE_SENT = "message.sent";
    public static final String INTENT_MESSAGE_DELIVERED = "message.delivered";

    public static final String EXTRA_MESSAGE = "extra.message";
    public static final String EXTRA_RECEIVERS = "extra.receivers";

    public sms_sender() {
        super("sms_sender");
    }

    private static class IDGenerator {

        private static final AtomicInteger counter = new AtomicInteger();

        public static int nextValue() {
            return counter.getAndIncrement();
        }
    }

    public void sendSMS(String message, String receiver) {
        SmsManager sm = SmsManager.getDefault();

        PendingIntent sentPI = null;

        Intent sentIntent = new Intent(INTENT_MESSAGE_SENT);

        int sentID = IDGenerator.nextValue();
        sentPI = PendingIntent.getBroadcast(sms_sender.this, sentID, sentIntent,
                PendingIntent.FLAG_CANCEL_CURRENT);

        try {
            sm.sendTextMessage(receiver, null, message, sentPI, null);
        } catch (IllegalArgumentException e) {
            System.out.println("Illegal argument");
        }
    }

    protected void onHandleIntent(Intent intent) {
        String message = intent.getStringExtra(EXTRA_MESSAGE);
        String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS);
        sendSMS(message, receivers[0]);
    }
}
4

1 に答える 1