/*
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.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Service;
import android.content.ActivityNotFoundException;
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.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.provider.CallLog;
import android.telephony.TelephonyManager;
import android.webkit.WebView;
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.XLog;
import com.polyvi.xface.util.XUtils;
public class XTelephonyExt extends XExtension {
private static final String COMMAND_DELETE_ALL_CALL_RECORDS = "deleteAllCallRecords";
private static final String COMMAND_DELETE_CALL_RECORD = "deleteCallRecord";
private static final String COMMAND_GET_CALL_RECORD = "getCallRecord";
private static final String COMMAND_FIND_CALL_RECORDS = "findCallRecords";
private static final String COMMAND_GET_CALL_RECORD_COUNT = "getCallRecordCount";
private static final String COMMAND_INITIATE_VOICE_CALL = "initiateVoiceCall";
private final String CALL_RECORD_TYPE_RECEIVED = "RECEIVED";/** < 已接电话的通话记录类型 */
private final String CALL_RECORD_TYPE_OUTGOING = "OUTGOING";/** < 已拨电话的通话记录类型 */
private final String CALL_RECORD_TYPE_MISSED = "MISSED";/** < 未接电话的通话记录类型 */
private ContentResolver mContentResolver;
private final String CLASS_NAME = XTelephonyExt.class.getSimpleName();
private BroadcastReceiver mIncomingCallBroadcastReceiver = null;
private static final String ACTION_PHONE_STATE_CHANGED = TelephonyManager.ACTION_PHONE_STATE_CHANGED;
@Override
public void init(XExtensionContext extensionContext, XIWebContext webContext) {
super.init(extensionContext, webContext);
mContentResolver = getContext().getContentResolver();
genIncomingCallBroadcastReceiver();
getContext().registerReceiver(
mIncomingCallBroadcastReceiver,
new IntentFilter(ACTION_PHONE_STATE_CHANGED));
}
@Override
public void sendAsyncResult(String result) {
}
@Override
public boolean isAsync(String action) {
if (action.equals(COMMAND_INITIATE_VOICE_CALL)) {
return false;
}
return true;
}
@Override
public XExtensionResult exec(String action,
JSONArray args, XCallbackContext callbackCtx) throws JSONException {
XExtensionResult.Status status = XExtensionResult.Status.OK;
String result = "";
try {
if (action.equals(COMMAND_DELETE_ALL_CALL_RECORDS)) {
boolean delAllSuccess = deleteAllCallRecords(args.getString(0));
return new XExtensionResult(status, delAllSuccess);
} else if (action.equals(COMMAND_DELETE_CALL_RECORD)) {
boolean delSuccess = deleteCallRecord(args.getString(0),
args.getLong(1));
return new XExtensionResult(status, delSuccess);
} else if (action.equals(COMMAND_FIND_CALL_RECORDS)) {
JSONArray matchedCallRecord = findCallRecords(
args.getJSONObject(0), args.getInt(1), args.getInt(2));
return new XExtensionResult(status, matchedCallRecord);
} else if (action.equals(COMMAND_GET_CALL_RECORD)) {
JSONObject callRecord = getCallRecord(args.getString(0),
args.getInt(1));
return new XExtensionResult(status, callRecord);
} else if (action.equals(COMMAND_GET_CALL_RECORD_COUNT)) {
int callCount = getCallRecordCount(args.getString(0));
return new XExtensionResult(status, callCount);
} else if (action.equals(COMMAND_INITIATE_VOICE_CALL)) {
boolean isCallSuccess = false;
boolean mobileNetAccessible = isSimCardAvailable(getContext());
isCallSuccess = initiateVoiceCall(args.getString(0));
if ( !mobileNetAccessible || !isCallSuccess) {
status = Status.ERROR;
}
return new XExtensionResult(status, result);
}
return new XExtensionResult(status, result);
} catch (JSONException e) {
return new XExtensionResult(XExtensionResult.Status.ERROR, result);
}
}
@Override
public void destroy(){
if(null != mIncomingCallBroadcastReceiver){
getContext().unregisterReceiver(mIncomingCallBroadcastReceiver);
mIncomingCallBroadcastReceiver = null;
}
}
/**
* 删除所有通话记录
*
* @param[in] callRecordType 通话记录类型
*
* @return 全部删除通话记录是否成功
* */
private boolean deleteAllCallRecords(String callRecordType) {
int callType = getCallRecordType(callRecordType);
mContentResolver.delete(CallLog.Calls.CONTENT_URI, CallLog.Calls.TYPE
+ "=" + callType, null);
return true;
}
/**
* 删除指定id和通话记录类型的通话记录
*
* @param[in] callRecordType 通话记录类型
* @param[in] callRecordId 通话记录id
*
* @return 删除通话记录是否成功
* */
private boolean deleteCallRecord(String callRecordType, long recordId) {
int callType = getCallRecordType(callRecordType);
mContentResolver.delete(CallLog.Calls.CONTENT_URI, CallLog.Calls._ID
+ "=" + recordId + " and " + CallLog.Calls.TYPE + "="
+ callType, null);
return true;
}
/**
* 得到指定通话记录类型和id的通话记录
*
* @param[in] callRecordType 通话记录类型
* @param[in] callRecordIndex 通话记录的索引
*
* @return 返回通话记录的JSON对象
* */
private JSONObject getCallRecord(String callRecordType, int recordIndex) {
int callType = getCallRecordType(callRecordType);
Cursor c = mContentResolver.query(CallLog.Calls.CONTENT_URI,
new String[] { CallLog.Calls.NUMBER, CallLog.Calls._ID,
CallLog.Calls.CACHED_NAME, CallLog.Calls.TYPE,
CallLog.Calls.DATE, CallLog.Calls.DURATION },
CallLog.Calls.TYPE + "=" + callType, null,
CallLog.Calls.DEFAULT_SORT_ORDER);
String callRecordAddress = "";
String callRecordId = "";
String callRecordName = "";
long durationSeconds = 0;
long startTime = 0;
JSONObject callRecord = new JSONObject();
if (null != c) {
if (c.moveToPosition(recordIndex)) {
callRecordAddress = c.getString(0);
callRecordId = c.getString(1);
callRecordName = c.getString(2);
startTime = c.getLong(4);
durationSeconds = c.getLong(5);
}
c.close();
try {
callRecord.put("callRecordAddress", callRecordAddress);
callRecord.put("callRecordId", callRecordId);
callRecord.put("callRecordName", callRecordName);
callRecord.put("durationSeconds", durationSeconds);
callRecord.put("startTime", startTime);
callRecord.put("callRecordType", callRecordType);
} catch (JSONException e) {
XLog.e(CLASS_NAME, e.getMessage());
}
}
return callRecord;
}
/**
* 查找指定匹配的通话记录
*
* @param[in] comparisonCallRecord 待匹配的通话记录
* @param[in] startIndex 要查找的开始索引
* @param[in] endIndex 要查找的结束位置的索引
*
* @return 返回按照匹配的通话记录查找的所有通话记录的JSON数组
* */
private JSONArray findCallRecords(JSONObject comparisonCallRecord,
int startIndex, int endIndex) {
JSONArray result = new JSONArray();
if (null != comparisonCallRecord) {
try {
String callRecordId = comparisonCallRecord
.getString("callRecordId");
String callRecordAddress = comparisonCallRecord
.getString("callRecordAddress");
String callRecordName = comparisonCallRecord
.getString("callRecordName");
String callRecordType = comparisonCallRecord
.getString("callRecordType");
long startTime = comparisonCallRecord.getLong("startTime");
long durationSeconds = comparisonCallRecord
.getLong("durationSeconds");
ArrayList<String> projections = new ArrayList<String>();
projections.add(CallLog.Calls._ID);
projections.add(CallLog.Calls.NUMBER);
projections.add(CallLog.Calls.CACHED_NAME);
ArrayList<String> projectionsValue = new ArrayList<String>();
projectionsValue.add(callRecordId);
projectionsValue.add(callRecordAddress);
projectionsValue.add(callRecordName);
StringBuilder selection = XUtils.constructSelectionStatement(
projections, projectionsValue);
String selectionStr = buildSelectionStr(selection, startTime,
durationSeconds,callRecordType);
Cursor cursor = mContentResolver.query(
CallLog.Calls.CONTENT_URI, null, selectionStr, null,
CallLog.Calls.DEFAULT_SORT_ORDER);
if (null == cursor) {
return result;
}
int count = endIndex - startIndex + 1;
if (count > 0) {
if (cursor.moveToPosition(startIndex)) {
do {
JSONObject callRecord = getCallRecordFromCursor(cursor);
result.put(callRecord);
count--;
} while (cursor.moveToNext() && count > 0);
}
}
cursor.close();
} catch (JSONException e) {
XLog.e(CLASS_NAME, e.toString());
}
}
return result;
}
/**
* 获取指定通话记录类型的通话记录个数
*
* @param[in] callRecordType 通话记录类型
*
* @return 返回通话记录个数
* */
private int getCallRecordCount(String callRecordType) {
int callType = getCallRecordType(callRecordType);
Cursor c = mContentResolver.query(CallLog.Calls.CONTENT_URI,
new String[] { CallLog.Calls._ID }, CallLog.Calls.TYPE + "="
+ callType, null, CallLog.Calls.DEFAULT_SORT_ORDER);
int count = 0;
if (null != c) {
count = c.getCount();
}
c.close();
return count;
}
/**
* 拨打指定号码的电话
*
* @param[in] phoneNumber 要拨打的电话号码
* @return 拨打电话是否成功
* */
private boolean initiateVoiceCall(String phoneNumber) {
try {
if (isLegalPhoneNum(phoneNumber)) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse(WebView.SCHEME_TEL + phoneNumber));
getContext().startActivity(intent);
return true;
}
} catch (ActivityNotFoundException e) {
XLog.e(CLASS_NAME, e.toString());
} catch (SecurityException e) {
XLog.e(CLASS_NAME, e.toString());
}
return false;
}
/**
* 检测sim卡是否可用
* @param context
* @return
*/
public boolean isSimCardAvailable(Context context){
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return (info != null && info.isConnected() && checkSimCardState(tm));
}
/**
* 检查sim卡的状态
* @param tm
* @return
*/
private boolean checkSimCardState(TelephonyManager tm){
int simState = tm.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return false;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
return true;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
return true;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
return true;
case TelephonyManager.SIM_STATE_READY:
return true;
case TelephonyManager.SIM_STATE_UNKNOWN:
return false;
default:
return false;
}
}
private void genIncomingCallBroadcastReceiver(){
if(null == mIncomingCallBroadcastReceiver){
mIncomingCallBroadcastReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(ACTION_PHONE_STATE_CHANGED.equals(action)){
incomingCallResponse(intent);
}
}
};
}
}
private void incomingCallResponse(Intent intent){
Context ctx = getContext();
TelephonyManager tm = (TelephonyManager) ctx
.getSystemService(Service.TELEPHONY_SERVICE);
XEvent evt = XEvent.createEvent(XEventType.CALL_RECEIVED, tm.getCallState());
XSystemEventCenter.getInstance().sendEventAsync(evt);
}
/**
* 验证是否是合法的电话号码
* @param phoneNumber 待验证的电话号码
* @return 返回验证结果 -true 电话号码合法 -false 电话号码非法
* */
private boolean isLegalPhoneNum(String phoneNumber) {
String regExpression = "[+*#\\d]+";
return phoneNumber.matches(regExpression);
}
/**
* 根据js传进来的通话记录类型,获取native的通话记录类型
*
* @param[in] callRecordType 通话记录类型
*
* @return 返回native的通话记录类型
* */
private int getCallRecordType(String callRecordType) {
int callType = CallLog.Calls.INCOMING_TYPE;
if (CALL_RECORD_TYPE_RECEIVED.equals(callRecordType)) {
callType = CallLog.Calls.INCOMING_TYPE;
} else if (CALL_RECORD_TYPE_OUTGOING.equals(callRecordType)) {
callType = CallLog.Calls.OUTGOING_TYPE;
} else if (CALL_RECORD_TYPE_MISSED.equals(callRecordType)) {
callType = CallLog.Calls.MISSED_TYPE;
}
return callType;
}
/**
* 根据通话记录类型(整型)的到JS需要的字符串通话记录类型
* */
private String getCallRecordTypeStr(int type) {
String typeStr = CALL_RECORD_TYPE_RECEIVED;
switch (type) {
case CallLog.Calls.INCOMING_TYPE:
typeStr = CALL_RECORD_TYPE_RECEIVED;
break;
case CallLog.Calls.OUTGOING_TYPE:
typeStr = CALL_RECORD_TYPE_OUTGOING;
break;
case CallLog.Calls.MISSED_TYPE:
typeStr = CALL_RECORD_TYPE_MISSED;
break;
}
return typeStr;
}
/**
* 通过Cursor得到通话记录的JSON对象
* */
private JSONObject getCallRecordFromCursor(Cursor cursor) {
String callRecordId = cursor.getString(cursor
.getColumnIndex(CallLog.Calls._ID));
String callRecordAddress = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.NUMBER));
String callRecordName = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.CACHED_NAME));
int callRecordTypeInt = cursor.getInt(cursor
.getColumnIndex(CallLog.Calls.TYPE));
long startTime = cursor.getLong(cursor
.getColumnIndex(CallLog.Calls.DATE));
long durationSeconds = cursor.getLong(cursor
.getColumnIndex(CallLog.Calls.DURATION));
JSONObject callRecord = new JSONObject();
try {
callRecord.put("callRecordId", callRecordId);
callRecord.put("callRecordAddress", callRecordAddress);
callRecord.put("callRecordName", callRecordName);
callRecord.put("callRecordType",
getCallRecordTypeStr(callRecordTypeInt));
callRecord.put("startTime", startTime);
callRecord.put("durationSeconds", durationSeconds);
} catch (JSONException e) {
XLog.e(CLASS_NAME, e.toString());
}
return callRecord;
}
/**
* 根据已经得到的selection和电话开始时间和持续时间构建SQL语句字符串
*
* @param selection
* 初始构建的查询语句
* @param startTime
* 通话开始时间
* @param durationSeconds
* 通话持续时间
*
* @return SQL查询的条件语句字符串
* */
private String buildSelectionStr(StringBuilder selection, long startTime,
long durationSeconds,String type) {
if (-1 != startTime) {
if (null == selection) {
selection = new StringBuilder();
} else {
selection.append(" AND ");
}
selection.append(CallLog.Calls.DATE);
selection.append("=");
selection.append(startTime);
}
if (-1 != durationSeconds) {
if (null == selection) {
selection = new StringBuilder();
} else {
selection.append(" AND ");
}
selection.append(CallLog.Calls.DURATION);
selection.append("=");
selection.append(durationSeconds);
}
if(!"".equals(type)){
if (null == selection) {
selection = new StringBuilder();
} else {
selection.append(" AND ");
}
selection.append(CallLog.Calls.TYPE);
selection.append("=");
selection.append(getCallRecordType(type));
}
String selectionStr = null;
if (null != selection) {
selectionStr = selection.toString();
}
return selectionStr;
}
}