blob: 98899c903684e13de1a20c343886e8678d35adf0 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.provider.Telephony.Sms.Intents;
import android.util.Config;
import android.util.Log;
/**
* WAP push handler class.
*
* @hide
*/
public class WapPushOverSms {
private static final String LOG_TAG = "WAP PUSH";
private final Context mContext;
private WspTypeDecoder pduDecoder;
private PowerManager.WakeLock mWakeLock;
/**
* Hold the wake lock for 5 seconds, which should be enough time for
* any receiver(s) to grab its own wake lock.
*/
private final int WAKE_LOCK_TIMEOUT = 5000;
public WapPushOverSms(Phone phone) {
mContext = phone.getContext();
createWakelock();
}
/**
* Dispatches inbound messages that are in the WAP PDU format. See
* wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
*
* @param pdu The WAP PDU, made up of one or more SMS PDUs
*/
public void dispatchWapPdu(byte[] pdu) {
if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
int index = 0;
int transactionId = pdu[index++] & 0xFF;
int pduType = pdu[index++] & 0xFF;
int headerLength = 0;
if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
(pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
return;
}
pduDecoder = new WspTypeDecoder(pdu);
/**
* Parse HeaderLen(unsigned integer).
* From wap-230-wsp-20010705-a section 8.1.2
* The maximum size of a uintvar is 32 bits.
* So it will be encoded in no more than 5 octets.
*/
if (pduDecoder.decodeUintvarInteger(index) == false) {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
return;
}
headerLength = (int)pduDecoder.getValue32();
index += pduDecoder.getDecodedDataLength();
int headerStartIndex = index;
/**
* Parse Content-Type.
* From wap-230-wsp-20010705-a section 8.4.2.24
*
* Content-type-value = Constrained-media | Content-general-form
* Content-general-form = Value-length Media-type
* Media-type = (Well-known-media | Extension-Media) *(Parameter)
* Value-length = Short-length | (Length-quote Length)
* Short-length = <Any octet 0-30> (octet <= WAP_PDU_SHORT_LENGTH_MAX)
* Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE)
* Length = Uintvar-integer
*/
if (pduDecoder.decodeContentType(index) == false) {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
return;
}
int binaryContentType;
String mimeType = pduDecoder.getValueString();
if (mimeType == null) {
binaryContentType = (int)pduDecoder.getValue32();
switch (binaryContentType) {
case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML;
break;
case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML;
break;
case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI;
break;
case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL;
break;
case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO;
break;
case WspTypeDecoder.CONTENT_TYPE_B_MMS:
mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS;
break;
default:
if (Config.LOGD) {
Log.w(LOG_TAG,
"Received PDU. Unsupported Content-Type = " + binaryContentType);
}
return;
}
} else {
if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO;
} else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS)) {
binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
} else {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
return;
}
}
index += pduDecoder.getDecodedDataLength();
int dataIndex = headerStartIndex + headerLength;
boolean dispatchedByApplication = false;
switch (binaryContentType) {
case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
dispatchWapPdu_PushCO(pdu, transactionId, pduType);
dispatchedByApplication = true;
break;
case WspTypeDecoder.CONTENT_TYPE_B_MMS:
dispatchWapPdu_MMS(pdu, transactionId, pduType, dataIndex);
dispatchedByApplication = true;
break;
default:
break;
}
if (dispatchedByApplication == false) {
dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex);
}
}
private void dispatchWapPdu_default(
byte[] pdu, int transactionId, int pduType, String mimeType, int dataIndex) {
byte[] data;
data = new byte[pdu.length - dataIndex];
System.arraycopy(pdu, dataIndex, data, 0, data.length);
Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setType(mimeType);
intent.putExtra("transactionId", transactionId);
intent.putExtra("pduType", pduType);
intent.putExtra("data", data);
sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
}
private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) {
Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO);
intent.putExtra("transactionId", transactionId);
intent.putExtra("pduType", pduType);
intent.putExtra("data", pdu);
sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
}
private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) {
byte[] data;
data = new byte[pdu.length - dataIndex];
System.arraycopy(pdu, dataIndex, data, 0, data.length);
Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS);
intent.putExtra("transactionId", transactionId);
intent.putExtra("pduType", pduType);
intent.putExtra("data", data);
sendBroadcast(intent, "android.permission.RECEIVE_MMS");
}
private void createWakelock() {
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WapPushOverSms");
mWakeLock.setReferenceCounted(true);
}
private void sendBroadcast(Intent intent, String permission) {
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
// receivers time to take their own wake locks.
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
mContext.sendBroadcast(intent, permission);
}
}