| /* |
| * 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.app.Activity; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.provider.Telephony; |
| 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 SMSDispatcher mSmsDispatcher; |
| |
| /** |
| * 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, SMSDispatcher smsDispatcher) { |
| mSmsDispatcher = smsDispatcher; |
| mContext = phone.getContext(); |
| } |
| |
| /** |
| * 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 |
| * @return a result code from {@link Telephony.Sms.Intents}, or |
| * {@link Activity#RESULT_OK} if the message has been broadcast |
| * to applications |
| */ |
| public int 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 Intents.RESULT_SMS_HANDLED; |
| } |
| |
| 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 Intents.RESULT_SMS_GENERIC_ERROR; |
| } |
| 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 Intents.RESULT_SMS_GENERIC_ERROR; |
| } |
| 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 Intents.RESULT_SMS_HANDLED; |
| } |
| } 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 Intents.RESULT_SMS_HANDLED; |
| } |
| } |
| 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); |
| } |
| return Activity.RESULT_OK; |
| } |
| |
| 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); |
| |
| mSmsDispatcher.dispatch(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); |
| |
| mSmsDispatcher.dispatch(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); |
| |
| mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_MMS"); |
| } |
| } |
| |