2012年4月7日 星期六

[TQC+ Android] 3-7 判斷發送簡訊狀態 Use registerReceiver, SmsManager, PendingIntent





設計一發送簡訊的程式 , 並可得知發送之後的送達結果 , 這題使用BroadcastReceiver 等待程式發送簡訊的動作 , 而關於BroadcastReceiver的使用有兩種方法 , 一種是靜態的在AndroidManifest.xml中在<receiver> tag中註冊 , 另一種是動態的在程式中使用 registerReceiver() method 註冊和使用unregisterReceiver()註銷 , 另外既然要讓 BroadcastReceiver 可以判斷發送簡訊的動作 , 就要在 IntentFilter 中增加發送簡訊的action , 但是 Android SDK 沒有提供相關的action , 所以我們必須使用我們自己的 custom action string , 而這題我們使用動態註冊及註銷的方式搭配自訂的 action 來達成題目要求。




package COM.TQC.GDD03;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class GDD03 extends Activity
{
  private Button mButton1;
  private EditText mEditText1, mEditText2;
  
  PendingIntent sentIntent;
  SmsManager smsManager;
  mServiceReceiver mServiceReceiver;
    
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    /* Phone No. */
    mEditText1 = (EditText) findViewById(R.id.myEditText1);
    
    /* SMS BODY */
    mEditText2 = (EditText) findViewById(R.id.myEditText2);
    mButton1 = (Button) findViewById(R.id.myButton1);
    
    mEditText1.setText("5556");
    mEditText2.setText("DAVID_SEND");
    
    mServiceReceiver = new mServiceReceiver();
    //宣告一個自訂的BroadcastReceiver , 稍後我們會在onResume() 動態註冊它
    
    smsManager = SmsManager.getDefault();
    //SmsManager 類別可以協助我們送出簡訊 , 我們可以透過 這個static method getDefault()來取得 SmsManager預設的instance
    
    Intent smsIntent = new Intent("COM.TQC.GDD03.Send_Message");
 //替這個Intent 設定我們自訂的action : COM.TQC.GDD03.Send_Message
    //通常在action前我們會附加上 application package name
    
    smsIntent.putExtra("Data", "Hello!");
    //順便附加個字串
    
 sentIntent = PendingIntent.getBroadcast(GDD03.this, 0, smsIntent, PendingIntent.FLAG_CANCEL_CURRENT);
 //public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
 //使用這個static method 我們會接收到一個具有像Context.sendBroadcast()行為的PendingIntent instance.
 //我們使用 FLAG_CANCEL_CURRENT , 用意是在產生一個新的 PendingIntent之前 , 會把舊的先cancel掉
 
    mButton1.setOnClickListener(new Button.OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        // TODO Auto-generated method stub       
       
       smsManager.sendTextMessage(mEditText1.getText().toString(), null, mEditText2.getText().toString(), sentIntent, null);
       //送出簡訊 , 並附加一個 PendingIntent sentIntent , 用意是等它回報傳送結果(result code)
       //並且可以從sentIntent中取得相關資訊 , 例如一些額外的錯誤提示 , 或是我們預先加入的資訊如之前的"Data" 
      }
    });
  }
  
  public class mServiceReceiver extends BroadcastReceiver
  {
    @Override
    public void onReceive(Context context, Intent intent)
    {
      // TODO Auto-generated method stub
     
     Log.d("Test","Data:"+intent.getStringExtra("Data"));
     //顯示之前擺入sentIntent的附加資訊
     
     if(intent.getAction().equals("COM.TQC.GDD03.Send_Message"))
     { 
      switch(getResultCode()) //取得回傳的result code
      {
       case Activity.RESULT_OK:
       showToast("SMS sent");
       break;
      
       case SmsManager.RESULT_ERROR_RADIO_OFF:
       showToast("RADIO OFF");
       break;
       
       case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
       //如果是這個"一般錯誤"的case , 那麼 sentIntent 也許會附帶一組 "errorCode" 來記錄錯誤資訊
       break;
       
       case SmsManager.RESULT_ERROR_NULL_PDU:
          //Failed because no pdu provided 
          break;
          
       case SmsManager.RESULT_ERROR_NO_SERVICE:
          //Failed because service is currently unavailable
          break;
      
       default:
       showToast("NO SERVICE");
       break;
      }      
     }
    }
  }
   
  @Override
  protected void onResume()
  {
    // TODO Auto-generated method stub
    super.onResume();
    IntentFilter IFilter = new IntentFilter();
    IFilter.addAction("COM.TQC.GDD03.Send_Message");
    //宣告一個IntentFilter並使用我們之前自訂的action
    
    registerReceiver(mServiceReceiver,IFilter);
    //動態註冊BroadcastReceiver
  }
  
  @Override
  protected void onPause()
  {
    // TODO Auto-generated method stub
    super.onPause();
    unregisterReceiver(mServiceReceiver);
    //動態註銷BroadcastReceiver
  }
  
  public void showToast(String message)
  {
   Toast.makeText(this, message, Toast.LENGTH_LONG).show();
  }
}


在這裡有幾個重點要說明一下 , 我們選擇在 onResume() method去動態註冊custom BroadcastReceiver : mServiceReceiver , 然後選擇在onPause()的時候去註銷它 , 那是因為當程式進入pause狀態時 , 是沒辦法接收到 intent的。


另外根據PendingIntent的操作行為 , 我們選用不同的method 取得它的instance , 而它有三個不同的 static method可以協助我們取得instance , 分別是 getActivity(Context, int, Intent, int)getBroadcast(Context, int, Intent, int),getService(Context, int, Intent, int) 在這題我們要讓mServiceReceiver 可以接收到傳送簡訊的action , 所以使用getBroadcast() , 而 PendingIntent 就會附加在 SmsManager.sendTextMessage() 當傳送簡訊時被sent出去


SmsManager 類別中的 
public void sendTextMessage (String destinationAddress, String scAddress, String text, PendingIntent sentIntent,PendingIntent deliveryIntent) 可以協助我們送出簡訊 , 特別是如果參數 PendingIntent sentIntent 不是null的話 , 當傳送簡訊後可以透過 getResultCode() 取得回報的 result code , 我們再根據這個 result code去判斷簡訊發送的情形是否成功 , 或是有哪些錯誤訊息。




接下來是AndroiManifest.xml , 請記得由於我們有發送簡訊這個動作 , 所以記得宣告 use-permission : android.permission.SEND_SMS

    
        
            
                
                
            
        
    
    

 




最後是main.xml 

  
  
  
  
  
  
  
  
  
  
  














由於題目要求能判斷無線網路關閉的狀態 , 所以去設定無線裝置及網路的地方啟動飛航模式。



成功的判斷出因為沒有網路所以沒辦法成功發送簡訊的狀態




開啟另一個5556模擬器 , 可以看到畫面上有出現接收到簡訊的提示。



P.S. 題目中所要求的Variable和Method皆會保留 , 也會根據題目所要求的流程去實作 , 縱使題目要求繞遠路....



沒有留言:

張貼留言

Google Analytics