package org.orange.familylink.sms; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.orange.familylink.AlarmActivity; import org.orange.familylink.ContactDetailActivity; import org.orange.familylink.MainActivity; import org.orange.familylink.R; import org.orange.familylink.ContactDetailActivity.Contact; import org.orange.familylink.data.CommandMessageBody; import org.orange.familylink.data.Location; import org.orange.familylink.data.Message.Code; import org.orange.familylink.database.Contract; import org.orange.familylink.data.ResponseMessageBody; import org.orange.familylink.data.Settings; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import android.util.Log; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; /** * 短信接收的service,这个服务是前台服务 * @author Orange Team * */ public class SmsReceiverService extends Service { public static final String ACTION_FOREGROUND = "org.orange.familylink.FOREGROUND"; public static final String ACTION_BACKGROUND = "org.orange.familylink.BACKGROUND"; private static final Class<?>[] mSetForegroundSignature = new Class[] { boolean.class}; private static final Class<?>[] mStartForegroundSignature = new Class[] { int.class, Notification.class}; private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class}; private NotificationManager mNM; private Method mSetForeground; private Method mStartForeground; private Method mStopForeground; private Object[] mSetForegroundArgs = new Object[1]; private Object[] mStartForegroundArgs = new Object[2]; private Object[] mStopForegroundArgs = new Object[1]; static Context mContext; SmsObserver smsObserver; /** * 存储接收到的信息,调用SmsMessage中的receiveAndSave()方法 * @author Orange Team * */ public static class HandlerOfMessage extends Handler{ private HandlerOfMessage(){} @Override public void handleMessage(Message msg){ super.handleMessage(msg); Bundle bundle = msg.getData(); //获取信息中的body String bodyResult = bundle.getString("bodyResult"); //获取信息中的电话号码 String addressResult = bundle.getString("addressResult"); SmsMessage localMessage = new SmsMessage(); //对接收的信息进行存储 Uri uri = localMessage.receiveAndSave(mContext, bodyResult, addressResult); localMessage.receive(bodyResult, Settings.getPassword(mContext)); if (localMessage.getCode() == null) return; final int code = localMessage.getCode(); if (Code.isInform(code)) { if (Code.Extra.Inform.hasSetUrgent(code)) { //监护方接收到紧急消息,启动AlarmActivity startAlarm(uri); } else if (Code.Extra.Inform.hasSetRespond(code)) { //监护方接收到受顾方返回的响应消息 onReceiveRespondMessage(addressResult, localMessage, code); } } else if (Code.isCommand(code)) { //受顾方接收监护方的命令消息 onReceiveCommandMessage(addressResult, localMessage, code); } } private void onReceiveRespondMessage(String messageAddress, SmsMessage message, int code) { final Gson gson = new Gson(); final ResponseMessageBody messageBody = gson.fromJson( message.getBody(), ResponseMessageBody.class); // 查询此消息响应的命令 if (messageBody.getId() == null) throw new NullPointerException("responseMessageBody's id is null"); final String[] projection = { Contract.Messages.COLUMN_NAME_ADDRESS, Contract.Messages.COLUMN_NAME_CODE}; Uri uri = ContentUris.withAppendedId( Contract.Messages.MESSAGES_ID_URI, messageBody.getId()); Cursor cursor = mContext.getContentResolver().query( uri, projection, null, null, null); if (cursor.getCount() != 1) { if (cursor.getCount() == 0) { throw new IllegalStateException( "Can't find command to whom this message respond"); } else { throw new RuntimeException(); } } // 检查此消息的发送者和命令的接受者 是否一致 cursor.moveToFirst(); String commanded = cursor.getString(cursor .getColumnIndex(Contract.Messages.COLUMN_NAME_ADDRESS)); if (!messageAddress.equals(commanded)) { throw new IllegalStateException("The sender of response " + "message isn't the receiver of the command message"); } // 确认此消息应答的消息,是个命令消息 int codeIndex = cursor.getColumnIndex(Contract.Messages.COLUMN_NAME_CODE); if (cursor.isNull(codeIndex)) { throw new IllegalStateException("The message to whom this " + "message respond isn't a command message"); } final int commandCode = cursor.getInt(codeIndex); cursor.close(); if (!Code.isCommand(commandCode)) { throw new IllegalStateException("The message to whom this " + "message respond isn't a command message"); } // 根据命令类型,处理此响应消息 if (Code.Extra.Command.hasSetLocateNow(commandCode)) { //监护方接收到受顾方返回的现在定位结果 startMap(gson.fromJson(messageBody.getContent(), Location.class)); } } /** * 监护方接收到本应用发出的短信,之后通过这个方法分析短信的内容是否为紧急消息,如果是就会启动警告界面来提供帮助 * @param uri */ private void startAlarm(Uri uri){ long messageId = ContentUris.parseId(uri); Intent mIntent = new Intent(mContext, AlarmActivity.class); mIntent.putExtra(AlarmActivity.EXTRA_ID, messageId); mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(mIntent); } /** * 接收到命令消息时被调用 */ private void onReceiveCommandMessage(String messageAddress, SmsMessage localMessage, int code){ final Gson gson = new Gson(); CommandMessageBody messageBody = gson.fromJson( localMessage.getBody(), CommandMessageBody.class); ResponseMessageBody response = new ResponseMessageBody(); response.setId(messageBody.getId()); if (Code.Extra.Command.hasSetLocateNow(code)) { // Location location; // location = new Location();//TODO get current location // response.setContent(gson.toJson(location)); } final SmsMessage message = new SmsMessage(); message.setCode(Code.INFORM | Code.Extra.Inform.RESPONSE); message.setBody(response.toJson()); // 发送消息 Contact contact = ContactDetailActivity.getDefaultContact(mContext); if(!contact.phone.equals(messageAddress)) { throw new IllegalStateException( "Message's sender isn't the default contact"); } message.sendAndSave(mContext, contact.id, contact.phone); } /** * 监护方接收到受顾方返回的现在定位结果 * @param location 应答现在定位命令的位置信息 */ private void startMap(Location location){ //MapActivity } } /** * 监听器类,监听到收件箱中有新的短信来之后看是否为本应用发出的短信,如果是就截获到本应用中,且删除收件箱中的这条短信 * @author Orange Team * */ public final class SmsObserver extends ContentObserver{ private Handler mHandler; public SmsObserver(Handler handler){ super(handler); mHandler = handler; } @Override public void onChange(boolean selfChange){ //信息中的body String bodyResult = null; //信息中的电话号码 String addressResult = null; //信息中的ID long idResult = 0; ContentResolver contentResolver = mContext.getContentResolver(); Uri uri = Uri.parse("content://sms/inbox"); //查询收件箱中的短信,看此短信是否是设置中设置的号码发过来的短信 Cursor cursor = contentResolver.query( uri, new String[] {"_id", "address", "body"}, "address like ? and read = 0", getAddressOfSetting(), "date DESC"); if(cursor.moveToFirst()){ // if the cursor isn't empty bodyResult = cursor.getString(cursor.getColumnIndex("body")); //此时这个短信已经符合是设置中设置的号码发过来的,如果短信不是SmsMessage说明不是本应用发出的,结束 if(!isSmsMessage(bodyResult)) { cursor.close(); return; } addressResult = cursor.getString(cursor.getColumnIndex("address")); idResult = cursor.getLong(cursor.getColumnIndex("_id")); cursor.close(); }else{ cursor.close(); return; } if(idResult != 0){ //删除收件箱中的短信 contentResolver.delete( Uri.parse("content://sms/conversations/" + getThreadId()), "read = 0 and _id = ?", new String[] {String.valueOf(idResult)}); } Message msg = new Message(); Bundle bundle = new Bundle(); //数据封装到bundle中 bundle.putString("bodyResult", bodyResult); bundle.putString("addressResult", addressResult); msg.setData(bundle); mHandler.sendMessage(msg); } /** * 获取对话的id * @return ThreadId long类型 */ public long getThreadId(){ long threadId = -1; String SORT_ORDER = "date DESC"; Cursor cursor = mContext.getContentResolver().query( Uri.parse("content://sms/inbox"), new String[] {"_id", "thread_id", "address", "date"}, "address like ?", getAddressOfSetting(), SORT_ORDER); if(cursor.moveToFirst()){ threadId = cursor.getLong(cursor.getColumnIndex("thread_id")); } cursor.close(); return threadId; } /** * 检查指定内容是否是本应用发送的{@link SmsMessage} * @param body 需检查的短信的内容 * @return 如果是本应用发送的{@link SmsMessage},返回true;否则返回false */ protected boolean isSmsMessage(String body){ try{ new SmsMessage().receive(body, Settings.getPassword(mContext)); return true; } catch(JsonSyntaxException e) { return false; } } /** * 此方法用于获取设置中的联系人的号码然后生成字符串数组 * @return */ protected String[] getAddressOfSetting(){ final int TYPES_OF_PHONE = 1; String[] phones = new String[TYPES_OF_PHONE]; phones[0] = "%" + ContactDetailActivity.getDefaultContact(mContext).phone; return phones; } } /** * bindService时会调用这个方法 */ @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate(){ mContext = SmsReceiverService.this; smsObserver = new SmsObserver(new HandlerOfMessage()); //对系统的收件箱注册监听 mContext.getContentResolver().registerContentObserver( Uri.parse("content://sms"), true, smsObserver); //获取通知的管理类 mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); try { mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature); mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); return; } catch (NoSuchMethodException e) { // 运行旧版本 mStartForeground = mStopForeground = null; } try { mSetForeground = getClass().getMethod("setForeground", mSetForegroundSignature); } catch (NoSuchMethodException e) { throw new IllegalStateException( "OS doesn't have Service.startForeground OR Service.setForeground!"); } } /** * */ @Override public int onStartCommand(Intent intent, int flags, int startId){ handleCommand(intent); return START_STICKY; } /** * 处理notification显示的内容,且调用启动前台服务的方法 * @param intent 启动这个服务时的Intent,且这个intent要设置ACTION */ void handleCommand(Intent intent) { //启动这个服务时设置的ACTION这个ACTION设置为ACTION_FOREGROUND说明为启用前台服务 if (ACTION_FOREGROUND.equals(intent.getAction())) { NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_launcher) .setContentTitle(getText(R.string.SMS_receiver_service_title)) .setContentText(getText(R.string.SMS_receiver_service_content)); Intent resultIntent = new Intent(this, MainActivity.class); //制造一个回退activity栈,使得从notification进入应用后退出时是退到home TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addParentStack(MainActivity.class); stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent =stackBuilder.getPendingIntent( 0, PendingIntent.FLAG_UPDATE_CURRENT ); mBuilder.setContentIntent(resultPendingIntent); //启动前台服务方法的调用 startForegroundCompat(R.string.SMS_receiver_service_title, mBuilder.build()); } else if (ACTION_BACKGROUND.equals(intent.getAction())) { stopForegroundCompat(R.string.SMS_receiver_service_title); } } void invokeMethod(Method method, Object[] args) { try { method.invoke(this, args); } catch (InvocationTargetException e) { Log.w("ForegroundService", "Unable to invoke method", e); } catch (IllegalAccessException e) { Log.w("ForegroundService", "Unable to invoke method", e); } } /** * 启动前台服务 * @param id notification显示的标题字符的id * @param notification */ void startForegroundCompat(int id, Notification notification) { // API为2。0以后的版本使用startForeground if (mStartForeground != null) { mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[1] = notification; invokeMethod(mStartForeground, mStartForegroundArgs); return; } // API小于2.0的版本使用setForeground mSetForegroundArgs[0] = Boolean.TRUE; invokeMethod(mSetForeground, mSetForegroundArgs); mNM.notify(id, notification); } /** * 结束前台服务 * @param id */ void stopForegroundCompat(int id) { // API为2。0以后的版本使用stopForeground if (mStopForeground != null) { mStopForegroundArgs[0] = Boolean.TRUE; invokeMethod(mStopForeground, mStopForegroundArgs); return; } // API小于2.0的版本使用setForeground mNM.cancel(id); mSetForegroundArgs[0] = Boolean.FALSE; invokeMethod(mSetForeground, mSetForegroundArgs); } /** * */ @Override public void onDestroy(){ //注销对系统收件箱的监听 mContext.getContentResolver().unregisterContentObserver(smsObserver); //停止前台服务 stopForegroundCompat(R.string.SMS_receiver_service_title); } }