/*
Copyright 2012-2013, Polyvi Inc. (http://polyvi.github.io/openxface)
This program is distributed under the terms of the GNU General Public License.
This file is part of xFace.
xFace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
xFace is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with xFace. If not, see <http://www.gnu.org/licenses/>.
*/
package com.polyvi.xface.extension;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import com.polyvi.xface.event.XEvent;
import com.polyvi.xface.event.XEventType;
import com.polyvi.xface.event.XSystemEventCenter;
import com.polyvi.xface.extension.XExtensionResult.Status;
import com.polyvi.xface.plugin.api.XIWebContext;
import com.polyvi.xface.util.XUtils;
public class XMessagingExt extends XExtension {
private static final Uri mSMSContentUri = Uri.parse("content://sms/");
private static final String FOLDERTYPE_DRAFT = "draft";
private static final String MESSAGE_TYPE_SMS = "SMS";
private static final String MESSAGE_TYPE_MMS = "MMS";
private static final String MESSAGE_TYPE_EMAIL = "Email";
private static final String COMMAND_SENDMESSAGE = "sendMessage";
private static final String COMMAND_GETQUANTITIES = "getQuantities";
private static final String COMMAND_GETMESSAGE = "getMessage";
private static final String COMMAND_GETALLMESSAGES = "getAllMessages";
private static final String COMMAND_FINDMESSAGES = "findMessages";
private static final String SMS_SENT = "SMS_SENT";
private static final String INTENT_ACTION = "android.provider.Telephony.SMS_RECEIVED";/**< 定义Intent的action,即需要的短信收到的action*/
private BroadcastReceiver mSendSMSBroadcastReceiver = null;
private BroadcastReceiver mMsgReceiveBroadcaseReveiver = null;
private XCallbackContext mCallbackCtx;
private enum SMS_RESULT_STATUS{
SEND_SUCCESS, //发送成功
ERROR_GENERIC_FAILURE, //通用错误
ERROR_NO_SERVICE, //无服务
ERROR_NULL_PDU, //没有PDU提供
ERROR_RADIO_OFF, //天线关闭
NO_STATUS //没有状态(用于native端的短信发送的默认状态)
}
@Override
public void sendAsyncResult(String result) {
}
@Override
public boolean isAsync(String action) {
return true;
}
@Override
public void init(XExtensionContext extensionContext, XIWebContext webContext){
super.init(extensionContext, webContext);
genMsgReceiveBroadcastReceive();
regMsgReceiver();
}
private void genMsgReceiveBroadcastReceive(){
if(null == mMsgReceiveBroadcaseReveiver){
mMsgReceiveBroadcaseReveiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
if(INTENT_ACTION.equals(intent.getAction())){
Bundle bundle = intent.getExtras();
if(null != bundle){
// 通过pdus获得接收到的所有短信消息,获取短信内容;
Object[] pdus = (Object[]) bundle.get("pdus");
// 构建短信对象数组
SmsMessage[] msgs = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
// 获取单条短信内容,以pdu格式存,并生成短信对象;
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
JSONArray receivedMsgs = buildSmsList(msgs);
XEvent evt = XEvent.createEvent(XEventType.MSG_RECEIVED,
receivedMsgs.toString());
XSystemEventCenter.getInstance().sendEventAsync(evt);
}
}
}
};
}
}
/**
* 构建接收到的短信列表
* */
private JSONArray buildSmsList(SmsMessage[] msgs){
JSONArray smsList = new JSONArray();
for(SmsMessage msg : msgs){
try {
JSONObject msgJsonObj = buildSmsJsonObj(msg);
smsList.put(msgJsonObj);
} catch (JSONException e) {
e.printStackTrace();
}
}
return smsList;
}
/**
* 构建一条短信的json对象
* */
private JSONObject buildSmsJsonObj(SmsMessage msg) throws JSONException{
JSONObject msgJsonObj = new JSONObject();
msgJsonObj.put("msgId", "");
msgJsonObj.put("subject", msg.getPseudoSubject());
msgJsonObj.put("body", msg.getDisplayMessageBody());
msgJsonObj.put("destinationAddresses", "");
msgJsonObj.put("originatingAddress", msg.getDisplayOriginatingAddress());
msgJsonObj.put("messageType", "SMS");
boolean isRead = false;
if(SmsManager.STATUS_ON_ICC_READ == msg.getStatusOnIcc()){
isRead = true;
}
msgJsonObj.put("isRead", isRead);
msgJsonObj.put("date", msg.getTimestampMillis());
return msgJsonObj;
}
private void regMsgReceiver() {
getContext().registerReceiver(
mMsgReceiveBroadcaseReveiver, new IntentFilter(INTENT_ACTION));
}
@Override
public XExtensionResult exec(String action,
JSONArray args, XCallbackContext callbackCtx) throws JSONException {
XExtensionResult.Status status = XExtensionResult.Status.OK;
String result = "";
mCallbackCtx = callbackCtx;
try {
if(action.equals(COMMAND_SENDMESSAGE)) {
return sendMessage(mWebContext, args.getString(0), args.getString(1), args.getString(2), args.getString(3));
}
else if(action.equals(COMMAND_GETQUANTITIES)) {
int numbers = getQuantities(args.getString(0), args.getString(1));
return new XExtensionResult(status, numbers);
}
else if(action.equals(COMMAND_GETALLMESSAGES)) {
JSONArray messages = getAllMessages(args.getString(0), args.getString(1));
return new XExtensionResult(status, messages);
}
else if(action.equals(COMMAND_GETMESSAGE)) {
JSONObject message = getMessage(args.getString(0), args.getString(1), args.getInt(2));
return new XExtensionResult(status, message);
}
else if(action.equals(COMMAND_FINDMESSAGES)) {
JSONArray messages = findMessages(args.getJSONObject(0), args.getString(1), args.getInt(2), args.getInt(3));
return new XExtensionResult(status, messages);
}
return new XExtensionResult(status, result);
}catch (IllegalArgumentException e) {
return new XExtensionResult(XExtensionResult.Status.ERROR);
}
catch (Exception e) {
return new XExtensionResult(XExtensionResult.Status.ERROR);
}
}
@Override
public void destroy() {
if (null != mSendSMSBroadcastReceiver) {
getContext().unregisterReceiver(
mSendSMSBroadcastReceiver);
mSendSMSBroadcastReceiver = null;
}
if(null != mMsgReceiveBroadcaseReveiver){
getContext().unregisterReceiver(
mMsgReceiveBroadcaseReveiver);
mMsgReceiveBroadcaseReveiver = null;
}
}
/**
* 根据查询条件返回满足条件记录的条数
*/
private int getRecordCount(Uri queryUri, String selection, String[] selectionArgs)
throws InvalidParameterException{
ContentResolver resolver = getContext()
.getContentResolver();
Cursor cursor = resolver.query(queryUri,
new String[] { BaseColumns._ID }, selection, selectionArgs,
null);
if (null == cursor) {
throw new InvalidParameterException();
}
final int count = cursor.getCount();
cursor.close();
return count;
}
/**
* 获取消息数量
* @param messageType 信息类型(如MMS,SMS,Email)
* @param folderType 文件夹类型
* @return 消息数量
*/
private int getQuantities(String messageType, String folderType) {
//TODO:这里只处理了短信,以后会有彩信和Email的操作
if (null == folderType) {// folderType为null,表示草稿箱
folderType = FOLDERTYPE_DRAFT;
}
folderType = folderType.toLowerCase();
Uri uri = Uri.withAppendedPath(mSMSContentUri, folderType);
//TODO:获取SIM卡内的信息
final int count = getRecordCount(uri, null, null);
return count;
}
/**
* 发送消息
* @param webContext app应用,包含app的描述信息、状态及UI界面
* @param messageType 信息类型(如MMS,SMS,Email)
* @param addr 目的地址
* @param body 消息内容
* @param subject 消息主题
* @return 返回状态结果
*/
private XExtensionResult sendMessage(XIWebContext webContext, String messageType, String addr, String body,
String subject) throws IllegalArgumentException {
// send SMS
if (messageType.equals(MESSAGE_TYPE_SMS)) {
return sendSMS(webContext, addr, body);
}
// send MMS
else if (messageType.equals(MESSAGE_TYPE_MMS)) {
// TODO:send MMS
return new XExtensionResult(XExtensionResult.Status.OK, "");
}
// send e-mail
else if (messageType.equals(MESSAGE_TYPE_EMAIL)) {
return sendEmail(addr, body, subject);
} else {
throw new IllegalArgumentException("message type illegal");
}
}
/**
* 发送短信
* @param app app应用,包含app的描述信息、状态及UI界面
* @param addr 目的地址
* @param body 消息内容
* @return 返回状态结果
*/
private XExtensionResult sendSMS(XIWebContext webContext, String addr, String body){
String regularExpression = "[+*#\\d]+";
if (!addr.matches(regularExpression)) {
throw new IllegalArgumentException(
"address must be digit,*,# or +");
}
IntentFilter smsSendIntentFilter = new IntentFilter(SMS_SENT);
genSendSMSBroadreceiver();
// 注册发送短信的广播接收器
getContext().registerReceiver(
mSendSMSBroadcastReceiver, smsSendIntentFilter);
SmsManager manager = SmsManager.getDefault();
ArrayList<String> textList = manager.divideMessage(body);
ArrayList<PendingIntent> smsSendPendingIntentList = genSMSPendingIntentList(textList);
manager.sendMultipartTextMessage(addr, null, textList,
smsSendPendingIntentList, null);
XExtensionResult er = new XExtensionResult(Status.NO_RESULT);
er.setKeepCallback(true);
return er;
}
/**
* 发送Email
* @param addr 目的地址
* @param body 消息内容
* @param subject 消息主题
* @return 返回状态结果
*/
private XExtensionResult sendEmail(String addr, String body, String subject){
String aEmailList[] = { addr };
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, aEmailList);
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
getContext().startActivity(emailIntent);
return new XExtensionResult(XExtensionResult.Status.OK, "");
}
/**
* 构建短信发送广播接收器
* */
private void genSendSMSBroadreceiver(){
if (null == mSendSMSBroadcastReceiver) {
mSendSMSBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
// 作无效状态标记
SMS_RESULT_STATUS status = SMS_RESULT_STATUS.NO_STATUS;
switch (getResultCode()) {
case Activity.RESULT_OK:// 发送成功
status = SMS_RESULT_STATUS.SEND_SUCCESS;
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:// 通用错误
status = SMS_RESULT_STATUS.ERROR_GENERIC_FAILURE;
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:// 无服务
status = SMS_RESULT_STATUS.ERROR_NO_SERVICE;
break;
case SmsManager.RESULT_ERROR_NULL_PDU:// 没有PDU提供
status = SMS_RESULT_STATUS.ERROR_NULL_PDU;
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:// 天线关闭
status = SMS_RESULT_STATUS.ERROR_RADIO_OFF;
break;
}
resolveSMSSendResult(status);
}
};
}
}
/**
* 构建短信的PendingIntent列表
*
* @param textList
* 短信内容列表
* @return 根据短信分段数量构建好的相应的短信pendingIntent列表
* */
private ArrayList<PendingIntent> genSMSPendingIntentList(
ArrayList<String> textList) {
Intent smsSendIntent = new Intent(SMS_SENT);
int count = (null == textList) ? 0 : textList.size();
ArrayList<PendingIntent> smsSendPendingIntentList = new ArrayList<PendingIntent>(count);
Iterator<String> itor = textList.iterator();
Context ctx = getContext();
while (itor.hasNext()) {
smsSendPendingIntentList.add(PendingIntent.getBroadcast(ctx, 0, smsSendIntent, 0));
itor.next();
}
return smsSendPendingIntentList;
}
/**
* 处理短信发送的结果
*
* @param status
* 短信发送结果状态
* */
private void resolveSMSSendResult(SMS_RESULT_STATUS status) {
XExtensionResult er = null;
Status extensionStatus = Status.OK;
if (status != SMS_RESULT_STATUS.SEND_SUCCESS) {
extensionStatus = Status.ERROR;
}
er = new XExtensionResult(extensionStatus, status.ordinal());
er.setKeepCallback(false);
mCallbackCtx.sendExtensionResult(er);
}
/**
* 获取消息
* @param messageType 信息类型(如MMS,SMS,Email)
* @param folderType 文件夹类型
* @param index 位置
* @return 消息实体对象
*/
private JSONObject getMessage(String messageType, String folderType, int index) throws JSONException {
//TODO:这里只处理了短信,以后会有彩信和Email的操作
if (null == folderType) {// folderType为null,表示草稿箱
folderType = FOLDERTYPE_DRAFT;
}
JSONObject message = new JSONObject();
try {
// 需要获取的信息
String[] projection = new String[] { "_id", "subject", "address", "body", "date", "read" };
folderType = folderType.toLowerCase();
Uri uri = Uri.withAppendedPath(mSMSContentUri, folderType);
ContentResolver resolver = getContext().getContentResolver();
Cursor cursor = resolver.query(uri, projection, null, null, "date desc");
if(null == cursor){
return message;
}
// 找到存放待读取短信的位置
if(!cursor.moveToPosition(index)) {
cursor.close();
return message;
}
//TODO:获取SIM卡内的信息
message = getMessageFromCursor(cursor);
cursor.close();
} catch (SQLiteException ex) {
ex.printStackTrace();
}
return message;
}
/**
* 获取所有消息
* @param messageType 信息类型(如MMS,SMS,Email)
* @param folderType 文件夹类型
* @return 消息实体对象数组
*/
private JSONArray getAllMessages(String messageType, String folderType) throws JSONException {
//TODO:这里只处理了短信,以后会有彩信和Email的操作
if (null == folderType) {// folderType为null,表示草稿箱
folderType = FOLDERTYPE_DRAFT;
}
JSONArray messages = new JSONArray();
try {
// 需要获取的信息
String[] projection = new String[] { "_id", "subject", "address", "body", "date", "read" };
folderType = folderType.toLowerCase();
Uri uri = Uri.withAppendedPath(mSMSContentUri, folderType);
ContentResolver resolver = getContext().getContentResolver();
Cursor cursor = resolver.query(uri, projection, null, null, "date desc");
if(null == cursor){
return messages;
}
if(!cursor.moveToFirst()) {
cursor.close();
return messages;
}
do {
//TODO:获取SIM卡内的信息
JSONObject message = getMessageFromCursor(cursor);
messages.put(message);
}while(cursor.moveToNext());
cursor.close();
} catch (SQLiteException ex) {
ex.printStackTrace();
}
return messages;
}
/**
* 查找指定的信息
* @param comparisonMsg 要查找的信息
* @param folderType 文件夹类型
* @param startIndex 起始索引
* @param endIndex 结束索引
* @return 消息实体对象数组
*/
private JSONArray findMessages(JSONObject comparisonMsg, String folderType,
int startIndex, int endIndex) throws JSONException {
// TODO:这里只处理了短信,以后会有彩信和Email的操作
if (null == folderType) {// folderType为null,表示草稿箱
folderType = FOLDERTYPE_DRAFT;
}
ArrayList<String> projections = new ArrayList<String>();
projections.add("_id");
projections.add("subject");
projections.add("address");
projections.add("body");
ArrayList<String> projectionsValue = new ArrayList<String>();
projectionsValue.add(comparisonMsg.optString("messageId"));
projectionsValue.add(comparisonMsg.optString("subject"));
projectionsValue.add(comparisonMsg.optString("destinationAddresses"));
projectionsValue.add(comparisonMsg.optString("body"));
StringBuilder selection = XUtils.constructSelectionStatement(projections, projectionsValue);
int isRead = comparisonMsg.getInt("isRead");
if (-1 != isRead) {
if (null == selection) {
selection = new StringBuilder();
} else {
selection.append(" AND ");
}
selection.append("read");
selection.append("=");
selection.append(isRead);
}
String selectionStr = null;
if (null != selection) {
selectionStr = selection.toString();
}
folderType = folderType.toLowerCase();
Uri findUri = Uri.withAppendedPath(mSMSContentUri, folderType);
JSONArray messages = new JSONArray();
try {
ContentResolver resolver = getContext().getContentResolver();
Cursor cursor = resolver.query(findUri, null, selectionStr, null,
null);
if (null == cursor) {
return messages;
}
int count = endIndex - startIndex + 1;
if(cursor.moveToPosition(startIndex)) {
do {
JSONObject message = getMessageFromCursor(cursor);
messages.put(message);
count--;
} while(cursor.moveToNext() && count > 0);
}
cursor.close();
} catch (SQLiteException ex) {
ex.printStackTrace();
}
return messages;
}
/**
* 读取message的数据
*/
private JSONObject getMessageFromCursor(Cursor cursor) throws JSONException {
//通过关键字获取该关键字对应的信息
String msgId = cursor.getString(cursor.getColumnIndex("_id"));
String subject = cursor.getString(cursor.getColumnIndex("subject"));
String smsBody = cursor.getString(cursor.getColumnIndex("body"));
long date = cursor.getLong(cursor.getColumnIndex("date"));
boolean isRead = cursor.getInt(cursor.getColumnIndex("read")) == 0 ? false : true;
String destAddress = cursor.getString(cursor.getColumnIndex("address"));
JSONObject message = new JSONObject();
message.put("messageId", msgId);
message.put("subject", subject);
message.put("body", smsBody);
message.put("destinationAddresses", destAddress);
message.put("messageType", MESSAGE_TYPE_SMS);
message.put("date", date);
message.put("isRead", isRead);
return message;
}
}