/*
* Copyright (C) 2007-2008 Esmertec AG.
* Copyright (C) 2007-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.mms.transaction;
import static android.provider.Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION;
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_DELIVERY_IND;
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_ORIG_IND;
import com.android.internal.telephony.Phone;
import com.android.mms.MmsConfig;
import com.android.mms.R;
import com.android.mms.data.Contact;
import com.android.mms.ui.MessageUtils;
import com.google.android.mms.ContentType;
import com.google.android.mms.MmsException;
import com.google.android.mms.pdu.DeliveryInd;
import com.google.android.mms.pdu.EncodedStringValue;
import com.google.android.mms.pdu.GenericPdu;
import com.google.android.mms.pdu.NotificationInd;
import com.google.android.mms.pdu.PduHeaders;
import com.google.android.mms.pdu.PduParser;
import com.google.android.mms.pdu.PduPersister;
import com.google.android.mms.pdu.ReadOrigInd;
import android.database.sqlite.SqliteWrapper;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.PowerManager;
import android.provider.Telephony.Mms;
import android.provider.Telephony.Mms.Inbox;
import android.provider.Telephony.Sms.Intents;
import android.telephony.SmsMessage;
import android.util.Config;
import android.util.Log;
import com.android.internal.telephony.Phone;
import android.telephony.TelephonyManager;
/**
* Receives Intent.WAP_PUSH_RECEIVED_ACTION intents and starts the
* TransactionService by passing the push-data to it.
*/
public class PushReceiver extends BroadcastReceiver {
private static final String TAG = "PushReceiver";
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
public static final String NOTIFY_SHOW_MMS_REPORT_ACTION = "com.sprd.notify_show_mms_report_action";
private class ReceivePushTask extends AsyncTask<Intent,Void,Void> {
private Context mContext;
public ReceivePushTask(Context context) {
mContext = context;
}
@Override
protected Void doInBackground(Intent... intents) {
Intent intent = intents[0];
int phoneId = intent.getIntExtra(Phone.PHONE_ID, 0);
// Get raw PDU push-data from the message and parse it
byte[] pushData = intent.getByteArrayExtra("data");
PduParser parser = new PduParser(pushData);
GenericPdu pdu = parser.parse(phoneId);
if (null == pdu) {
Log.e(TAG, "Invalid PUSH data");
return null;
}
PduPersister p = PduPersister.getPduPersister(mContext);
ContentResolver cr = mContext.getContentResolver();
int type = pdu.getMessageType();
long threadId = -1;
Log.d(TAG,"doInBackground type:"+type);
try {
switch (type) {
case MESSAGE_TYPE_DELIVERY_IND:
case MESSAGE_TYPE_READ_ORIG_IND: {
threadId = findThreadId(mContext, pdu, type);
if (threadId == -1) {
// The associated SendReq isn't found, therefore skip
// processing this PDU.
break;
}
Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
// Update thread ID for ReadOrigInd & DeliveryInd.
ContentValues values = new ContentValues(1);
values.put(Mms.THREAD_ID, threadId);
SqliteWrapper.update(mContext, cr, uri, values, null, null);
//===== fixed CR<NEWMS00127040> by luning at 11-10-12 begin =====
EncodedStringValue encodedStringValue = null;
String report = "";
String address = "";
if (type == MESSAGE_TYPE_DELIVERY_IND) {
DeliveryInd deliveryInd = (DeliveryInd) pdu;
if ( deliveryInd.getTo() != null ) {
encodedStringValue = deliveryInd.getTo()[0];
if (null != encodedStringValue) {
address = Contact.get(encodedStringValue.getString(), false).getName();
}
}
int status = deliveryInd.getStatus();
Log.d(TAG," MESSAGE_TYPE_DELIVERY_IND[status]:"+status);
if(status == PduHeaders.STATUS_FORWARDED || status == PduHeaders.STATUS_RETRIEVED){
report = String.format(mContext.getString(R.string.delivery_toast_body), address);
//fix bug 12277 begin
// }else{
// report = String.format(mContext.getString(R.string.delivery_toast_body_fail), address);
// }
} else if (status == PduHeaders.STATUS_REJECTED) {
report = String.format(mContext.getString(R.string.delivery_toast_body_fail_rejected),address);
} else if (status == PduHeaders.STATUS_EXPIRED) {
report = mContext.getString(R.string.delivery_toast_body_expired);
} else {
report = String.format(mContext.getString(R.string.delivery_toast_body_fail),address);
}
//fix bug 12277 end
} else {// must be MESSAGE_TYPE_READ_ORIG_IND
ReadOrigInd readOrigInd = (ReadOrigInd) pdu;
encodedStringValue = readOrigInd.getFrom();
if (null != encodedStringValue) {
address = Contact.get(encodedStringValue.getString(), false).getName();
}
int status = readOrigInd.getReadStatus();
if(status == PduHeaders.READ_STATUS_READ){
report = String.format(mContext.getString(R.string.read_report_toast_body), address);
} else if(status == PduHeaders.READ_STATUS__DELETED_WITHOUT_BEING_READ){
report = String.format(mContext.getString(R.string.delete_unread_report_toast_body), address);
}else{
report = String.format(mContext.getString(R.string.read_report_toast_body_fail), address);
}
}
Intent notify = new Intent(NOTIFY_SHOW_MMS_REPORT_ACTION);
notify.putExtra("report", report);
mContext.sendBroadcast(notify);
//===== fixed CR<NEWMS00127040> by luning at 11-10-12 end =====
break;
}
case MESSAGE_TYPE_NOTIFICATION_IND: {
NotificationInd nInd = (NotificationInd) pdu;
if (MmsConfig.getTransIdEnabled()) {
byte [] contentLocation = nInd.getContentLocation();
if ('=' == contentLocation[contentLocation.length - 1]) {
byte [] transactionId = nInd.getTransactionId();
byte [] contentLocationWithId = new byte [contentLocation.length
+ transactionId.length];
System.arraycopy(contentLocation, 0, contentLocationWithId,
0, contentLocation.length);
System.arraycopy(transactionId, 0, contentLocationWithId,
contentLocation.length, transactionId.length);
nInd.setContentLocation(contentLocationWithId);
}
}
if (!isDuplicateNotification(mContext, nInd)) {
Uri uri = p.persist(pdu, Inbox.CONTENT_URI, phoneId);
// Start service to finish the notification transaction.
// TODO: different class name for different phoneId
//(20120202)when receive a wap push message,then save the services-center number
SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
SmsMessage wappush_sms = msgs[0];
if(wappush_sms != null){
ContentValues values = new ContentValues(1);
values.put(Mms.SERVICE_CENTER, wappush_sms.getServiceCenterAddress());
SqliteWrapper.update(mContext, cr, uri, values, null, null);
}
//(20120202)=========================================
Intent svc;
if (TelephonyManager.getPhoneCount() > 1 || MessageUtils.isMSMS){
Log.i(TAG,"[PushReceiver] doInBackground TelephonyManager.getPhoneCount() > 1");
Log.i(TAG,"mPhoneId is"+phoneId);
svc = new Intent(mContext, TransactionServiceHelper
.getTransactionServiceClass(phoneId));
} else {
Log.i(TAG,"[PushReceiver] doInBackground [ELSE]TelephonyManager.getPhoneCount() > 1");
svc = new Intent(mContext, TransactionService.class);
}
svc.putExtra(TransactionBundle.URI, uri.toString());
svc.putExtra(TransactionBundle.TRANSACTION_TYPE,
Transaction.NOTIFICATION_TRANSACTION);
svc.putExtra(Phone.PHONE_ID, phoneId);
mContext.startService(svc);
} else if (LOCAL_LOGV) {
Log.v(TAG, "Skip downloading duplicate message: "
+ new String(nInd.getContentLocation()));
}
break;
}
default:
Log.e(TAG, "Received unrecognized PDU.");
}
} catch (MmsException e) {
Log.e(TAG, "Failed to save the data from PUSH: type=" + type, e);
} catch (RuntimeException e) {
Log.e(TAG, "Unexpected RuntimeException.", e);
}
if (LOCAL_LOGV) {
Log.v(TAG, "PUSH Intent processed.");
}
Intent receiveMms = new Intent("android.provider.Telephony.MMS_RECEIVED");
mContext.sendBroadcast(receiveMms);
return null;
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WAP_PUSH_RECEIVED_ACTION)
&& ContentType.MMS_MESSAGE.equals(intent.getType())) {
if (LOCAL_LOGV) {
Log.v(TAG, "Received PUSH Intent: " + intent);
}
// Hold a wake lock for 5 seconds, enough to give any
// services we start time to take their own wake locks.
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MMS PushReceiver");
wl.acquire(5000);
new ReceivePushTask(context).execute(intent);
}
}
private static long findThreadId(Context context, GenericPdu pdu, int type) {
String messageId;
if (type == MESSAGE_TYPE_DELIVERY_IND) {
messageId = new String(((DeliveryInd) pdu).getMessageId());
} else {
messageId = new String(((ReadOrigInd) pdu).getMessageId());
}
StringBuilder sb = new StringBuilder('(');
sb.append(Mms.MESSAGE_ID);
sb.append('=');
sb.append(DatabaseUtils.sqlEscapeString(messageId));
sb.append(" AND ");
sb.append(Mms.MESSAGE_TYPE);
sb.append('=');
sb.append(PduHeaders.MESSAGE_TYPE_SEND_REQ);
// TODO ContentResolver.query() appends closing ')' to the selection argument
// sb.append(')');
Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
Mms.CONTENT_URI, new String[] { Mms.THREAD_ID },
sb.toString(), null, null);
if (cursor != null) {
try {
if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
return cursor.getLong(0);
}
} finally {
cursor.close();
}
}
return -1;
}
private static boolean isDuplicateNotification(
Context context, NotificationInd nInd) {
byte[] rawLocation = nInd.getContentLocation();
if (rawLocation != null) {
String location = new String(rawLocation);
String selection = Mms.CONTENT_LOCATION + " = ?";
String[] selectionArgs = new String[] { location };
Cursor cursor = SqliteWrapper.query(
context, context.getContentResolver(),
Mms.CONTENT_URI, new String[] { Mms._ID },
selection, selectionArgs, null);
if (cursor != null) {
try {
if (cursor.getCount() > 0) {
// We already received the same notification before.
return true;
}
} finally {
cursor.close();
}
}
}
return false;
}
}