2010年10月23日

[android] SMSでのWAP PUSHを受信するには

android端末でSMSでのWAP PUSHを受信するには、WAP_PUSH_RECEIVEDのブロードキャスト通知を受信します。

IntentFilterの設定
端末がSMSのWAP_PUSHを受信すると"android.provider.Telephony.WAP_PUSH_RECEIVED"アクションのインテント通知がブロードキャストされます。BroadcastReceiverのインテントフィルターにWAP_PUSH_RECEIVEDアクションを登録して、WAP_PUSHの受信通知を受け取ります。このブロードキャスト処理はcom.android.internal.telephony.WapPushOverSmsクラスのdispatchWapPdu_defaultメソッドから発行されているようです。

  
    
    
  


Permissionの設定
WAP_PUSH_RECEIVEDを受信するにはRECEIVE_WAP_PUSH"のパーミッションが必要です。


BroadcastReceiverの処理
dispatchWapPdu_defaultから発行されたWAP_PUSH_RECEIVEDインテントには以下のExtraデータが格納されています
キー名内容備考
transactionIdPush信号のトランザクションID
pduTypePDUタイプ(Push信号なら0x06)詳細は"WAP-230-WSP-20010705-a"のTable 34(PDU Type Assignments)
headerWSP(Wireless Session Protocol)のヘッダ詳細は"WAP-230-WSP-20010705-a" の8.2.4章(Push and Confirmed Push Facilities)
dataPUSH信号の本体WBXML(Wireless Binary XML)形式

public class WapPushReceiver extends BroadcastReceiver {
  private static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
  private static final String TAG = "WAP_PUSH";

  @Override
  public void onReceive(Context context, Intent intent) {
    if (WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      if (extras != null) {
        int transactionId = extras.getInt("transactionId");
        int pduType = extras.getInt("pduType");
        byte[] header = extras.getByteArray("header");
        byte[] data = extras.getByteArray("data");
        
        Log.d(TAG, "contentType: " + ((intent.getType() != null) ? intent.getType() : ""));
        Log.d(TAG, "transactionId: " + Integer.toString(transactionId));
        Log.d(TAG, "pduType: " + Integer.toString(pduType));

        if (header != null) {
          for (int i = 0; i < header.length; i++) {
            Log.d(TAG, String.format("header[%03d]: 0x%02x (%s)", i, header[i], (char) header[i]));
          }
        } else {
          Log.d(TAG, "header is null");
        }

        if (data != null) {
          for (int i = 0; i < data.length; i++) {
            Log.d(TAG, String.format("data[%03d]: 0x%02x (%s)", i, data[i], (char) data[i]));
          }
        } else {
          Log.d(TAG, "data is null");
        }
      }
    }
  }
}

動作ログ
WiFi接続時にiモードのメール受信通知がブロードキャストされた時のログです
10-23 13:10:28.263: DEBUG/WAP_PUSH(22039): contentType: application/vnd.wap.slc
10-23 13:10:28.263: DEBUG/WAP_PUSH(22039): transactionId: 0
10-23 13:10:28.263: DEBUG/WAP_PUSH(22039): pduType: 6
10-23 13:10:28.263: DEBUG/WAP_PUSH(22039): header is null
10-23 13:10:28.273: DEBUG/WAP_PUSH(22039): data[000]: 0x02 ( )
10-23 13:10:28.283: DEBUG/WAP_PUSH(22039): data[001]: 0x06 ( )
10-23 13:10:28.303: DEBUG/WAP_PUSH(22039): data[002]: 0x6a (j)
10-23 13:10:28.313: DEBUG/WAP_PUSH(22039): data[003]: 0x00 ( )
10-23 13:10:28.323: DEBUG/WAP_PUSH(22039): data[004]: 0x85 ( )
10-23 13:10:28.333: DEBUG/WAP_PUSH(22039): data[005]: 0x09 ( )
10-23 13:10:28.343: DEBUG/WAP_PUSH(22039): data[006]: 0x03 ( )
10-23 13:10:28.353: DEBUG/WAP_PUSH(22039): data[007]: 0x64 (d)
10-23 13:10:28.363: DEBUG/WAP_PUSH(22039): data[008]: 0x6f (o)
10-23 13:10:28.373: DEBUG/WAP_PUSH(22039): data[009]: 0x63 (c)
10-23 13:10:28.383: DEBUG/WAP_PUSH(22039): data[010]: 0x6f (o)
10-23 13:10:28.393: DEBUG/WAP_PUSH(22039): data[011]: 0x6d (m)
10-23 13:10:28.403: DEBUG/WAP_PUSH(22039): data[012]: 0x6f (o)
10-23 13:10:28.413: DEBUG/WAP_PUSH(22039): data[013]: 0x2e (.)
10-23 13:10:28.423: DEBUG/WAP_PUSH(22039): data[014]: 0x6e (n)
10-23 13:10:28.433: DEBUG/WAP_PUSH(22039): data[015]: 0x65 (e)
10-23 13:10:28.443: DEBUG/WAP_PUSH(22039): data[016]: 0x2e (.)
10-23 13:10:28.453: DEBUG/WAP_PUSH(22039): data[017]: 0x6a (j)
10-23 13:10:28.463: DEBUG/WAP_PUSH(22039): data[018]: 0x70 (p)
10-23 13:10:28.473: DEBUG/WAP_PUSH(22039): data[019]: 0x3f (?)
10-23 13:10:28.483: DEBUG/WAP_PUSH(22039): data[020]: 0x50 (P)
10-23 13:10:28.493: DEBUG/WAP_PUSH(22039): data[021]: 0x49 (I)
10-23 13:10:28.503: DEBUG/WAP_PUSH(22039): data[022]: 0x3d (=)
10-23 13:10:28.523: DEBUG/WAP_PUSH(22039): data[023]: 0x30 (0)
10-23 13:10:28.533: DEBUG/WAP_PUSH(22039): data[024]: 0x36 (6)
10-23 13:10:28.543: DEBUG/WAP_PUSH(22039): data[025]: 0x00 ( )
10-23 13:10:28.553: DEBUG/WAP_PUSH(22039): data[026]: 0x01 ( )

posted by meloncake at 23:59| Comment(0) | TrackBack(0) | Android

2010年10月12日

[android] SMSを受信するには

SMS(Short Message Service)を受信するにはSMS_RECEIVEDのブロードキャスト通知を受信します。

IntentFilterの設定
端末がSMSを受信すると"android.provider.Telephony.SMS_RECEIVED"アクションのインテント通知がブロードキャストされます。BroadcastReceiverのインテントフィルターにSMS_RECEIVEDアクションを登録して、SMSの受信通知を受け取ります。

  
    
  


Permissionの設定
SMS_RECEIVEDを受信するにはRECEIVE_SMSのパーミッション、SMSを読み取るにはREAD_SMSのパーミッションが必要です。



BroadcastReceiverの処理
SMS_RECEIVEDインテントのExtra(キー名:"pdus")にメッセージデータが格納されています。Object[]形式でメッセージが複数格納されていますので、for文等でメッセージを単体に分割します。メッセージ単体はPDU(protocol description unit)形式のbyte[]文字列ですのでSmsMessageクラスのcreateFromPdu(bute[] pdu)メソッドを呼び出し、byte[]形式のPDUデータをSmsMessageインスタンスへデコードします。

public class SMSReceiver extends BroadcastReceiver {
  private static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
  private static final String TAG = "SMSReceiver";

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SMS_RECEIVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      if (extras != null) {
        // pduのデコードとログ出力
        // サンプルのためBroadcastReceiverで処理(本来はServiceで)
        Object[] pdus = (Object[]) extras.get("pdus");
        for (Object pdu: pdus) {
          SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
          Log.d(TAG, "from:" + smsMessage.getOriginatingAddress());
          Log.d(TAG, "time:" + Long.toString(smsMessage.getTimestampMillis()));
          Log.d(TAG, "body:" + smsMessage.getMessageBody().replaceAll("\n", "\t"));
        }
      }
    }
  }
}

※SmsMessageクラスはAPIレベル4(Donuts)を境に機能とパスが変更されています(Donuts以降、android.telephony.gsm.SmsMessageはdeprecated)

API Levelクラス備考
Cupcake(3)までandroid.telephony.gsm.SmsMessageGSMのみ
Donuts(4)以降android.telephony.SmsMessageGSMとCDMA

docomoの電源OFF・圏外時着信通知を受信した時のログです
10-12 01:33:18.840: DEBUG/SMSReceiver(5272): from:DoCoMo SMS
10-12 01:33:18.840: DEBUG/SMSReceiver(5272): time:1286814795000
10-12 01:33:18.840: DEBUG/SMSReceiver(5272): body:10/12 01:29     090********

posted by meloncake at 02:05| Comment(1) | TrackBack(0) | Android

2010年10月06日

[My docomo checker] 1.6.0を公開しました(料金プラン分析機能など)

◆FOMA通話料
・サマリーにFOMA通話料を表示するようにしました。
・タップすると当月末の通話料を予測表示します。

1.6.0_call_bill.png

◆料金プラン分析
・サマリーの料金プランの項目をタップすると当日に料金プラン変更した時の基本料金と通話料金がどのようになるか分析結果を表示します(予測ですので、プラン変更後の実請求額等を保証するものではありません)

1.6.0_plan_analyze.png

◆WiFi自動更新処理の改善
・WIFi接続限定時の自動更新処理に不具合があったため修正しました。

◆FAQへのリンク
・設定メニューにFAQへのリンクボタンを追加しました
1.6.0_faq.png

◆プロセス管理の改善
・自動更新の設定がOFFの時タスクができるだけ常駐しないようにしました。

◆その他
・軽微な不具合修正を行いました。
posted by meloncake at 02:43| Comment(1) | TrackBack(0) | my docomo checker

2010年10月05日

[android] WiFiのON/OFFを取得するには

ワイヤレス設定のWiFi ON/OFFを取得する方法です
※WiFiの接続状態ではなくWiFi設定のON/OFFです

IntentFilterの設定
WiFiのON/OFFが変更された時にWIFI_STATE_CHANGED_ACTIONのインテントが投げられるので、IntentFilterで受け取ります

  
    
  


Permissionの設定
WIFI_STATE_CHANGED_ACTIONのインテントを受け取るにはACCESS_WIFI_STATEのパーミッションが必要です


Receiverの処理
WifiManagerのgetWifiState()でWiFiのON/OFF状態を取得できます
public class WifiOnOffReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
    if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
      WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

      if (wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
        // WiFiがONになった時の処理
      } else if (wm.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
        // WiFiがOFFになった時の処理
      }
    }
  }
}

WifiState()の遷移
[WIFIをON ] → WIFI_STATE_ENABLING → WIFI_STATE_ENABLED
[WIFIをOFF] → WIFI_STATE_DISABLING → WIFI_STATE_DISABLED
[失 敗 時 ] → WIFI_STATE_UNKNOWN
posted by meloncake at 01:35| Comment(2) | TrackBack(0) | Android

2010年10月04日

[android] WiFiに接続しているかを判定する

WiFiに接続中かを判定する方法です。
ConnectivityManagerからActiviNetworkInfo()を取得できます。アクティブネットワークがWIFIでCONNECTEDであることを判定します
public static boolean isWifiConnected(Context context) {
  ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo info = cm.getActiveNetworkInfo();

  if (info != null) {
    return (
      (info.getType() == ConnectivityManager.TYPE_WIFI) &&
      (info.isConnected())
    );
  }

  return false;
}
Permissionの設定
ActiviNetworkInfo()を受け取るするにはACCESS_NETWORK_STATEのパーミッションが必要です

posted by meloncake at 01:04| Comment(0) | TrackBack(0) | Android