com.polyvi.xface.extension.XMessagingExt.java Source code

Java tutorial

Introduction

Here is the source code for com.polyvi.xface.extension.XMessagingExt.java

Source

/*
 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";
    /**< Intentaction??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) {// folderTypenull?
            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) {// folderTypenull?
            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) {// folderTypenull?
            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) {// folderTypenull?
            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;
    }
}