1、在Settings列表项中添加一项SOS
sos设置入口界面
2、求救功能描述:
3.设置紧急号码:此选项用户可以从电话本中选择联系人添加到1-5个紧急号码中,在1-5列表中点击可以直接进入到系统电话本中去选择;也可以自己手动输入添加。
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中去实现即可,如下图所示
在方法doUpdateTilesList()上去挂载和设置sos设置项的显示和隐藏
2、接下来就是在要响应SOS按键:
(1)frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)方法中去监听sos按键,添加如下代码:
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;
}
到这里就介绍完毕了!