Java tutorial
/* 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.telephony; import java.util.ArrayList; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginResult; 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.XFaceMainActivity; import com.polyvi.xface.event.XEvent; import com.polyvi.xface.event.XEventType; import com.polyvi.xface.event.XSystemEventCenter; import com.polyvi.xface.util.XLog; import com.polyvi.xface.util.XUtils; public class XTelephonyExt extends CordovaPlugin { 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 Context mContext; private static final String ACTION_PHONE_STATE_CHANGED = TelephonyManager.ACTION_PHONE_STATE_CHANGED; @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); mContext = cordova.getActivity(); mContentResolver = cordova.getActivity().getContentResolver(); genIncomingCallBroadcastReceiver(); cordova.getActivity().registerReceiver(mIncomingCallBroadcastReceiver, new IntentFilter(ACTION_PHONE_STATE_CHANGED)); } @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { try { if (action.equals(COMMAND_DELETE_ALL_CALL_RECORDS)) { boolean deleteSuccess = deleteAllCallRecords(args.getString(0)); PluginResult result = new PluginResult(PluginResult.Status.OK, deleteSuccess); callbackContext.sendPluginResult(result); } else if (action.equals(COMMAND_DELETE_CALL_RECORD)) { boolean deleteSuccess = deleteCallRecord(args.getString(0), args.getLong(1)); PluginResult result = new PluginResult(PluginResult.Status.OK, deleteSuccess); callbackContext.sendPluginResult(result); } else if (action.equals(COMMAND_FIND_CALL_RECORDS)) { JSONArray array = findCallRecords(args.getJSONObject(0), args.getInt(1), args.getInt(2)); callbackContext.success(array); } else if (action.equals(COMMAND_GET_CALL_RECORD)) { JSONObject object = getCallRecord(args.getString(0), args.getInt(1)); callbackContext.success(object); } else if (action.equals(COMMAND_GET_CALL_RECORD_COUNT)) { int count = getCallRecordCount(args.getString(0)); callbackContext.success(count); } else if (action.equals(COMMAND_INITIATE_VOICE_CALL)) { boolean isCallSuccess = false; boolean mobileNetAccessible = isSimCardAvailable(mContext); isCallSuccess = initiateVoiceCall(args.getString(0)); if (!mobileNetAccessible || !isCallSuccess) { PluginResult result = new PluginResult(PluginResult.Status.ERROR); callbackContext.sendPluginResult(result); } callbackContext.success(); } } catch (JSONException e) { callbackContext.error(e.toString()); } return true; } @Override public void onDestroy() { if (null != mIncomingCallBroadcastReceiver) { mContext.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)); mContext.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) { TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Service.TELEPHONY_SERVICE); XEvent evt = XEvent.createEvent(XEventType.CALL_RECEIVED, tm.getCallState()); ((XFaceMainActivity) mContext).getEventCenter().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; } }