Android SOS功能模块开发

一、sos需求

1、在Settings列表项中添加一项SOS

sos设置入口界面

Android SOS功能模块开发_第1张图片

2、求救功能描述:

Android SOS功能模块开发_第2张图片

3.设置紧急号码:此选项用户可以从电话本中选择联系人添加到1-5个紧急号码中,在1-5列表中点击可以直接进入到系统电话本中去选择;也可以自己手动输入添加。

Android SOS功能模块开发_第3张图片               Android SOS功能模块开发_第4张图片

4、编辑紧急短信内容:紧急短信内容可以编辑,修改,删除

5,触发规则:

(1)求救电话拨号规则:如果用户只设置一个SOS求救电话,如果对方无人接听,将连续拨打知道对方接通,电话每拨打一次,发送一条求救信息。发送信息次数与电话拨打次数一样。如果用户不想继续再拨打,如果用户自己挂断(拨打方),循环拨打将停止。如果对方挂断,继续拨打紧急联系人。

(2)如果用户设置多个SOS求救号码,如果第一个紧急联系人无人接听,将自动切换到第二个紧急联系人、以此类推、每拨号一次紧急联系人,同步发送一条紧急求救信息,以此类推。求救信息与求救电话次数一样。如果用户自己挂断(拨打方),循环拨打将停止。如果对方挂断,将立即拨打下一个紧急联系人。

(3)发送给紧急联系人的求救信息。除了用户自己编辑好的外,还需带有GPS定位信息,SOS求救发起后,软件自动打开GPS信息进行搜星定位,同时打开SIM卡数据业务辅助定位,定位成功后发出GPS经纬度信息到紧急联系人。

(4)如果用户没有设置SOS任何信息,在待机界面短按进入到设置界面,如果用户设置了SOS求救信息,在待机界面长按发出SOS求救电话和信息。

二、开发及流程

1、设置中添加sos设置项

(1)在packages/apps/Settings/src/com/android/settings/Settings.java中添加SosSettingsActivity和SosNumSettingsActivity,其实这两个类只是名义上索引类,并不实际存在,他们索引的类在后面会介绍,

(2)在packages/apps/Settings/src/com/android/settings/SettingsActivity.java中添加String[] SETTINGS_FOR_RESTRICTED的数组中添加

和在String[] ENTRY_FRAGMENTS数组中天添加

在这里你才看上面两个activity索引的两个正在实现的地方;它的索引只要在Settings的AndroidMainfest.xml中去实现即可,如下图所示

Android SOS功能模块开发_第5张图片

在方法doUpdateTilesList()上去挂载和设置sos设置项的显示和隐藏

2、接下来就是在要响应SOS按键:

(1)frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)方法中去监听sos按键,添加如下代码:

Android SOS功能模块开发_第6张图片

(2)、按键下去,当然的去调用电话去Android SOS功能模块开发_第7张图片

3,电话去响应请求

(1)在电话中创建一个sos的服务(SosDialService.java),记得在AndroidMainfest.xml中添加组件,去监听和接收按键请求响应;拨打紧急电话和发送短信

SosDialService.java:

package com.android.dialer;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.Service;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.WindowManager;

import com.android.internal.telephony.Phone;
import com.android.incallui.Call;
import com.android.incallui.CallList;
import android.telephony.TelephonyManager;
import android.telephony.SubscriptionInfo;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;

import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
import android.telephony.SubscriptionManager;
import android.provider.Settings;

import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

public class SosDialService extends Service {
    private String TAG = "SosDialService";
	
	private Context mContext;
	private static final long INTERVAL = 5 * 1000;

	private Timer timer = null;
	private String number;
	private int numbers;
	private static boolean ifEnd = false;
	private static boolean isRuning = false;
	private static CallList mCallList = null;
	private int state = Call.State.IDLE;
	private static TelephonyManager mPhone = null;
	private static SubscriptionManager mSubscriptionManager = null;
	private static TelecomManager mTelecomManager = null;
	private  PhoneAccountHandle mPhoneAccount = null;
	private  SosPhoneStateListener mPhoneState = null;
	private int times =0;
	private static final String[] mNumberKeys = { "sos_number", "sos_number1",
			"sos_number2", "sos_number3", "sos_number4" };
	

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onBind");
		return null;
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		
		mContext = getApplicationContext();
		Log.d(TAG, "onCreate, mContext = " + mContext);
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onStartCommand, mContext = " + mContext);
		return super.onStartCommand(intent, flags, startId);
	}
	
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
    	ifEnd = true;
	   	Log.d(TAG, "onDestroy,  ifEnd = " + ifEnd);
		timer.cancel();
		super.onDestroy();

	}
	
	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onUnbind");
		return super.onUnbind(intent);
	}
	
	@Override
	@Deprecated
	public void onStart(Intent intent, int startId) {
		// TODO Auto-generated method stub
		super.onStart(intent, startId);

		Log.d("lxm", "SosDialService.java onStart, intent = " + intent);
		
		numbers = 0;

		ifEnd = false;
		state = Call.State.IDLE;
		if(mCallList == null){
			mCallList = CallList.getInstance();
		}

		if(timer == null){
			timer = new Timer();
		}
		if (mSubscriptionManager == null) {
			mSubscriptionManager = SubscriptionManager.from(mContext);
		}
		
		if(mTelecomManager == null){
			mTelecomManager = TelecomManager.from(mContext);
		}
			
		if(mPhone == null) {
			mPhone = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
		}

		if(mPhoneState == null)
			mPhoneState = new SosPhoneStateListener();
		
		mPhone.listen(mPhoneState, PhoneStateListener.LISTEN_SERVICE_STATE);

		if (intent.getAction().equals("com.pyt.SOSPHONE") && (isRuning == false)) {
			
			if(mPhone.getSimState(0) != TelephonyManager.SIM_STATE_READY && mPhone.getSimState(1) != TelephonyManager.SIM_STATE_READY){
				
			      String message = mContext.getString(R.string.noSIM);
		            AlertDialog dialog = createDialog(mContext.getString(R.string.Warning), message);
		            dialog.show();
				
				Log.d(TAG, "SIM no ready!");
				
				return;
				
			}
			
			DialerApplication.startLocation();

			mPhoneAccount = mTelecomManager.getUserSelectedOutgoingPhoneAccount();
			Log.d(TAG, "onReceive.com.pyt.SOSPHONE, schedule, mPhoneAccount = " + mPhoneAccount);
			Log.d(TAG,"timer.start task");
			timer.schedule(new TimerTask() {
				@Override
				public void run() {
					int Phonestate = mPhone.getCallState();
					Call call = mCallList.getActiveCall();
					if(call != null) {
						Log.d(TAG, "callList.call = " + call);
						state = call.getState();
					}
					isRuning = true;
					Log.d(TAG,"ifEnd ="+ifEnd);
					if(ifEnd){
						mTelecomManager.setUserSelectedOutgoingPhoneAccount(mPhoneAccount);
						Log.d(TAG, "com.pyt.SOSPHONE_CANCEL, ifEnd = " + ifEnd + ", PhoneAccount = " + mPhoneAccount);
						isRuning = false;
//						timer.cancel();
						return;
					}

					times++;
					Log.d(TAG, "times = " + times + ", call.State = " + state + ", Phonestate = " + Phonestate  + ", ifEnd = " + ifEnd);

					if (state == Call.State.IDLE) {

						number = Settings.System.getString(
								mContext.getContentResolver(), mNumberKeys[numbers]);


						while(number == null || number.length() == 0)
						{
							if (++numbers > 4) {
								numbers = 0;
							}

							number = Settings.System.getString(
									mContext.getContentResolver(), mNumberKeys[numbers]);

						}

						Log.d(TAG, "numbers = " + numbers + ", number = " + number);

						if(Phonestate != TelephonyManager.CALL_STATE_IDLE)
							return;

						if (null != number && number.length() > 0) {

							String sim = Settings.System.getString(mContext.getContentResolver(),"sim_sets");
							int index = 0;
							if("SIM1".equals(sim)){
								index = 0;
							}else if("SIM2".equals(sim)){
								index = 1;
							}

							List phoneAccountsList = mTelecomManager.getCallCapablePhoneAccounts();

							int size = phoneAccountsList.size();

							Log.d(TAG, "index = " + index + ", phoneAccountsList.size() = " + size);

							if(size > 0)
							{
								if (index >= size)
									index = 0;
								mTelecomManager.setUserSelectedOutgoingPhoneAccount(phoneAccountsList.get(index));
							}else{
								ifEnd = true;
							}

							Log.d(TAG, "index2 = " + index);

							Intent dialIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + number));
							dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

							try {
								mContext.startActivity(dialIntent);

							} catch (ActivityNotFoundException e) {

							}

							Message msg = mHandlerSosMsg.obtainMessage();
							msg.obj = number;
							android.util.Log.d(TAG,"SosDialService.java message start");
							mHandlerSosMsg.sendMessageDelayed(msg, 30000);
						}


						if (++numbers > 4) {
							numbers = 0;
						}
					}

					if (state == Call.State.ACTIVE) {
						mTelecomManager.setUserSelectedOutgoingPhoneAccount(mPhoneAccount);
						Log.d(TAG, "timer.cancel(),TelephonyManager.State = " + state + ", PhoneAccount = " + mPhoneAccount);
						isRuning = false;
						times = 0;
						ifEnd = true;
//						timer.cancel();
						return;
					}
				}
			}, 0, INTERVAL);
		}
	}

	public void sendTextMessage(
	            String destinationAddress, String scAddress, String text,
	            PendingIntent sentIntent, PendingIntent deliveryIntent
	            ) {
	       
			String sim = Settings.System.getString(mContext.getContentResolver(),"sim_sets");
			android.util.Log.d(TAG,"SosDialService.java  sendTextMessage sim =  "+sim);
			int index = 0;
			if("SIM1".equals(sim)){
				index = 0;
			}else if("SIM2".equals(sim)){
				index = 1;
			} 
			
			int subInfoLength = 0;
			SubscriptionInfo subinfo = null; 
			
	        List SubInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
	        if(SubInfoList != null)
			   subInfoLength = SubInfoList.size();
			
			Log.d("", "sendTextMessage, text=" + text + ", destinationAddress=" + destinationAddress +", subInfoLength = " +subInfoLength);
			 
			if(subInfoLength <= 0)
				return;
			else if(subInfoLength == 1) {
				subinfo = SubInfoList.get(0);
			}
			else if(subInfoLength == 2){
				subinfo = mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(index);
			}
			
			if(subinfo != null){
				Log.d(TAG, "SmsManager.sendTextMessage, destinationAddress=" + destinationAddress + ",text=" + text +  ",subinfo=" + subinfo);
				
				 SmsManager manager = SmsManager.getDefault();  
				 ArrayList list = manager.divideMessage(text);  
		            	SmsManager.getSmsManagerForSubscriptionId(subinfo.getSubscriptionId()).sendMultipartTextMessage(destinationAddress,
		  	                  scAddress, list, null, null);

			}
		     
	    }
	    
	    
		public   Handler mHandlerSosMsg = new Handler(){
	    	public void handleMessage(android.os.Message msg) {

	    				String number = msg.obj.toString();
	    				String content = Settings.System.getString(mContext.getContentResolver(), "sos_content");
						android.util.Log.d(TAG,"SosDialService.java mHandlerSosMsg  number = "+number+"  content = "+content +"  Locflag = "+DialerApplication.getLocflag());
	    				if(DialerApplication.getLocflag()  < 3) {
	    					Message msg2 = mHandlerSosMsg.obtainMessage();	
	    					msg2.obj = number;
	    	  				mHandlerSosMsg.sendMessageDelayed(msg2, 30000);
	    					Log.d(TAG, "number = " + number + ",locFlag =" + DialerApplication.getLocflag() + ",content =" + content);
	    				}else {
							android.util.Log.d(TAG,"SosDialService.java mHandlerSosMsg boolean = "+DialerApplication.getLocationInfo().isEmpty());
	    					if(!DialerApplication.getLocationInfo().isEmpty()){
	    						if(content == null)
	            				 	content = mContext.getString(R.string.gps_info) + "\n" + DialerApplication.getLocationInfo();
	            				else
	            					content = content + "\n" + mContext.getString(R.string.gps_info) + "\n" + DialerApplication.getLocationInfo();
	    					}
	  	
	        				Log.d(TAG, "sos sms send, number = " + number + " ,content =" + content);

	        				if(null == content || content.length() == 0){
								content = mContext.getString(R.string.help);
							}

	        				  try {
	        						Log.d(TAG, "handleMessage ->sendTextMessage, number = " + number + " ,content =" + content);
	        						sendTextMessage(number, null, content, null, null);

	      						} catch (Exception e) {

	      							Log.e(TAG, "error:" + e);
	      						}

	    				}
	    				
	    		};
	        };

		private class SosPhoneStateListener extends PhoneStateListener {

			public void onServiceStateChanged(ServiceState serviceState) {
			    super.onServiceStateChanged(serviceState);

			    int pos = serviceState.getState();
			    Log.d(TAG, "Phonestate change==" + pos);
			    if(pos != ServiceState.STATE_IN_SERVICE){
					ifEnd = true;
				}
			  }
		};
		
		
	    private AlertDialog createDialog(String title, String message) {
	        final AlertDialog dialog  =  new AlertDialog.Builder(DialerApplication.getDialerContext())
	            .setTitle(title)
	            .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
	            .setCancelable(false)
	            .setNegativeButton(android.R.string.ok, new DialogInterface.OnClickListener() {
	                public void onClick(DialogInterface dialog, int which) {
	                    Log.d(TAG, "invalid sim card ");
	                }
	            })
	            .setMessage(message)
	            .create();
	        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
	        return dialog;
	    }
	    
		
}

(2) 我们发送的紧急短信内容包含了地址信息,这里我们用到百度地图的服务(这里可以去了解一下如何引入百度地图的服务:http://lbsyun.baidu.com/apiconsole/key/create),在Dialer/src/com/android/dialer/DialerApplication.java中去获取到百度地图服务信息!

DialerApplication.java:

private void initLocation() {
		 
		   Log.d("lxm", "DialerApplication.java initLocation  ");

	       LocationClientOption option = new LocationClientOption();
	       option.setLocationMode(LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
	       option.setCoorType("gcj02");//可选,默认gcj02,设置返回的定位结果坐标系,
	       int span=1000;
	  
	       option.setScanSpan(span);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
	       option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
	       option.setOpenGps(true);//可选,默认false,设置是否使用gps
	       option.setLocationNotify(true);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
	       option.setIgnoreKillProcess(true);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
	       
	       if(mLocationClient ==null){
	    	   Log.d("lxm", "DialerApplication.java  initLocation DialerApplication->sContext = " + sContext);
	    	   mLocationClient = new LocationClient(sContext);
	       }
   
	       if(mMyLocationListener == null) {
			   mMyLocationListener = new BDLocationListener() {
				   @Override
				   public void onReceiveLocation(BDLocation location) {
					   Log.d(TAG, "DialerApplication.java  onReceiveLocation 1111 location retcode = " + location.getLocType() + ",locFlag = " + locFlag);
					   Log.d("lxm"," DialerApplication.java  LocType = "+location.getLocType()+"   BDG ="+BDLocation.TypeGpsLocation + "   BDN ="+BDLocation.TypeNetWorkLocation);
					   Log.d("lxm","  DialerApplication.java 111  time ="+ location.getTime()+"  Latitude ="+location.getLatitude()+"  Longitude ="+location.getLongitude() +"   addr ="+location.getAddrStr());
					   if (location.getLocType() == BDLocation.TypeGpsLocation
							   || location.getLocType() == BDLocation.TypeNetWorkLocation) {
						   mLocationInfo = sContext.getString(R.string.time) + location.getTime()
								   + sContext.getString(R.string.latitude) + location.getLatitude()
								   + sContext.getString(R.string.lontitude) + location.getLongitude()
								   + sContext.getString(R.string.addr) + location.getAddrStr();
						   Log.d("lxm", "location retcode = " + location.getLocType() + "\n" + mLocationInfo);

						   stopLocation();

					   } else if (locFlag > 3) {

						   mLocationInfo = "";
						   stopLocation();
					   } else if (location.getLocType() == BDLocation.TypeNetWorkException) {

						   locFlag++;
						   ;
						   RestartLocation();
					   }
					   Log.d("lxm", "DialerApplication.java onReceiveLocation 2222 location retcode = " + location.getLocType() + ",locFlag = " + locFlag);
				   }
				   @Override
				   public void onConnectHotSpotMessage(String s , int i){

				   }
			   };

		   }
	       mLocationClient.registerLocationListener(mMyLocationListener);

	       mLocationClient.setLocOption(option);
	   }
	   
	 public static void startLocation() {

		 Log.d("lxm", "DialerApplication.java  startLocation() 111");
	 	 locFlag = 0;

		 LocationManager locationManager = (LocationManager)sContext.getSystemService(Context.LOCATION_SERVICE);
		 if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
		             setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
	      }

		 setMobileDataEnabled();

		 if(mLocationClient != null) {
		 	Log.d("lxm","DialerApplication.java startLocation()  222");
		     mLocationClient.start();
		     mLocationClient.requestLocation();
		 }
	 }

	 public static void stopLocation() {

		 Log.d(TAG, "DialerApplication.java stopLocation");

		 locFlag = 3;  
		 if(mLocationClient != null) {
			 mLocationClient.stop();
		 }
	 }
	 
	 private static void RestartLocation() {

		 Log.d(TAG, "DialerApplication.java RestartLocation");
		
		 if(mLocationClient != null) {
			 mLocationClient.stop();
			 mLocationClient.start();
		     mLocationClient.requestLocation();
		 }
	 }
	 
	 public static int getLocflag() {

		 return locFlag;
	 }
	 
	 public static String getLocationInfo() {

		 return mLocationInfo;
	 }

 

到这里就介绍完毕了!

 

你可能感兴趣的:(sos)