# day04 ##html
## 手机防盗主页面的布局 ##java
参照完整版页面初始化页面全部的数据android
## 短信拦截广播 ## 作具体的短信功能git
- 权限 <uses-permission android:name="android.permission.RECEIVE_SMS" />sql
- 注册广播数据库
<receiver android:name="com.itheima.mobilesafe91.receiver.SmsReceiver" >json
<intent-filter android:priority="1000" >api
<action android:name="android.provider.Telephony.SMS_RECEIVED" />数组
</intent-filter>安全
</receiver>
- 获取短信
使用"pdus" 这个key来提取SMS pdus数组,其中,每一个对象表示一个SMS消息。 不用记
Object[] objs = (Object[]) intent.getExtras().get("pdus");//protocol description unit
for (Object pdu : objs) {
// 把每一个pdus字节数组转为SmsMessage对象
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
String body = sms.getMessageBody();// 短信内容
String phone = sms.getOriginatingAddress();// 短信电话
process(context, body);
}
private void process(Context context, String body) {
if (TextUtils.equals("#*location*#", body)) {
// gps数据
abortBroadcast();// 终止广播的继续传输 4.4以上 短信变为无序 没法拦截
} else if (TextUtils.equals("#*wipedata*#", body)) {
// 远程销毁数据
abortBroadcast();
} else if (TextUtils.equals("#*alarm*#", body)) {
// 播放报警音乐
MediaPlayer mp = MediaPlayer.create(context, R.raw.alarm);
mp.setLooping(true);// 设置循环播放
mp.setVolume(1.0f, 1.0f);// 设置音量 铃声音量和媒体音量不一样
mp.start();// 开始播放
abortBroadcast();
} else if (TextUtils.equals("#*lockscreen*#", body)) {
// 远程锁屏
abortBroadcast();
}
}
## 手机定位 ##
- 网络定位/wifi
运营商\位置提供服务商会收集wifi热点,ip 的 位置,
缺点:误差很大。
- 基站定位
工做原理:手机能打电话,须要基站发送信号。手机定位也能够用基站
手机附近能收到3个基站的信号,就能够定位了。
基站定位有可能很准确,好比基站多的地方,;
若是基站少的话就会相差很大。
精确度:几十米到几千米不等;受信号强度影响
- GPS定位
至少须要3颗卫星;
特色是:须要搜索卫星, 头顶必须是空旷的;
影响条件:云层、建筑、大树。
卫星:美国人、欧洲人的卫星。
北斗:中国的,使用有限制没有彻底开放,只是在大巴,战机等使用。
A-GPS: 辅助gps定位系统,经过GPS和网络共同定位,弥补GPS的不足,搜索卫星速度块, 精确度可达到15米之内, 通常手机都采用此种定位方式
- 写一个demo测试定位
// 获取位置服务管理器
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
List<String> allProviders = locationManager.getAllProviders();
System.out.println("allProviders ==" + allProviders);// passive, gps
long minTime = 0; // 定位的最短期
float minDistance = 0;// 定位的最短距离
// <uses-permission
// android:name="android.permission.ACCESS_COARSE_LOCATION"/> gps定位权限
// <uses-permission
// android:name="android.permission.ACCESS_FINE_LOCATION"/> 网络定位权限
listener = new MyLocationListener();
locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER, minTime,
minDistance, listener);
private class MyLocationListener implements LocationListener {
// 位置发生变化
@Override
public void onLocationChanged(Location location) {
double latitude = location.getLatitude();// 纬度
double longitude = location.getLongitude();// 经度
double altitude = location.getAltitude();// 海拔
float accuracy = location.getAccuracy();// 精确度
System.out.println("纬度 = " + latitude + "经度 = " + longitude + "海拔 = "
+ altitude + "精确度 = " + accuracy);
tvLoc.setText("纬度 = " + latitude + "\n经度 = " + longitude + "\n海拔 = "
+ altitude + "\n精确度 = " + accuracy);
}
// 位置服务的链接状态改变
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
System.out.println("onStatusChanged");
}
// 开启定位
@Override
public void onProviderEnabled(String provider) {
}
// 结束定位
@Override
public void onProviderDisabled(String provider) {
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//不须要服务的时候取消 节省电量
locationManager.removeUpdates(listener);
}
- 火星坐标
获取到坐标后在谷歌地图上查询,发现坐标有所偏移, 不许确.这是由于中国的地图服务,为了国家安全, 坐标数据都通过了政府加偏处理, 加偏处理后的坐标被称为火星坐标.
技术牛人经过对美国地图和中国地图的比对,生成了一个查询数据库, 专门用与标准坐标和火星坐标的转换.导入数据库文件axisoffset.dat和工具类ModifyOffset.java,建立一个java工程进行演示
public static void main(String[] args) {
try {
ModifyOffset offset = ModifyOffset instance = ModifyOffset.getInstance(new FileInputStream("axisoffset.dat"));//加载数据库文件
PointDouble s2c = offset.s2c(new PointDouble(116.29095863, 40.04359091));//标准坐标转为火星坐标
System.out.println(s2c);
} catch (Exception e) {
e.printStackTrace();
}
}
- 定位功能放到一个service里面
>GpsService.java
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
long minTime = 0; // 定位的时间 频率 多久去获取一次位置信息
float minDistance = 0;// 移动多少距离 才获取位置信息
// <uses-permission
// android:name="android.permission.ACCESS_COARSE_LOCATION"/> 网络定位权限
// <uses-permission
// android:name="android.permission.ACCESS_FINE_LOCATION"/> gps定位权限
locationListener = new MyLocationListener();
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);// 设置精确度为良好的
criteria.setCostAllowed(true);// 是否容许收费(流量)
locationManager.getBestProvider(criteria, true);// 获取最好的位置信息提供者
locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER, minTime,
minDistance, locationListener);
System.out.println("开启了gps服务");
private class MyLocationListener implements LocationListener {
// 位置发生变化
@Override
public void onLocationChanged(Location location) {
double latitude = location.getLatitude();// 纬度
double longitude = location.getLongitude();// 经度
// double altitude = location.getAltitude();// 海拔
// float accuracy = location.getAccuracy();// 精确度
System.out.println("纬度 = " + latitude + "经度 = " + longitude);
sendSms(latitude, longitude);// 发送报警短信
}
// 位置服务的链接状态改变
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
System.out.println("onStatusChanged");
}
// 开启定位
@Override
public void onProviderEnabled(String provider) {
}
// 结束定位
@Override
public void onProviderDisabled(String provider) {
}
}
@Override
public void onDestroy() {
super.onDestroy();
// service关闭的时候取消定位
locationManager.removeUpdates(locationListener);
}
- 开启服务
>在SmsReceiver里拦截到#*location*# 这条短信 开启定位服务的service
else if ("#*location*#".equals(messageBody)) {
// "gps追踪;
// LocationManager
Intent intent = new Intent(ctx, GpsService.class);
ctx.startService(intent);// 开启定位服
abortBroadcast();// 拦截掉短信 不让广播继续往下传
}
### 重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点 如何看接口文档申请数据###
- 发送位置信息短信
>根据获取的位置信息 经过一个查询接口查询出对应的位置信息 发送给安全号码
>http://api.jisuapi.com/geoconvert/coord2addr 接口文档
/**
* 处理位置信息 重点
*
* @param longitude
* @param latitude
*/
protected void process(final double longitude, final double latitude) {
// 获取安全号码
final String safeNum = SharedPreferencesUtils.getString(
getApplicationContext(), Constants.SJFD_SAFE_NUM, null);
final SmsManager smsManager = SmsManager.getDefault();
//
// 接口地址: http://api.jisuapi.com/geoconvert/coord2addr
// 支持格式:JSON,JSONP
// 请求方法:GET POST
// 请求示例:
// http://api.jisuapi.com/geoconvert/coord2addr?lat=30.2812129803&lng=120.11523398&type=google&appkey=yourappkey
//
// 请求参数:
// 参数名称 类型 必填 说明
// lat string 是 纬度
// lng string 是 经度
// type string 是 类型 默认是baidu 目前可选baidu、google
HttpUtils httpUtils = new HttpUtils(5000);
String url = "http://api.jisuapi.com/geoconvert/coord2addr";
RequestParams params = new RequestParams();
params.addQueryStringParameter("lat", latitude + "");
params.addQueryStringParameter("lng", longitude + "");
params.addQueryStringParameter("type", "google");
params.addQueryStringParameter("appkey", "cca834d3342236b5");
// 参1 请求方式 参2 请求接口 参3 请求参数 参4 返回监听
httpUtils.send(HttpMethod.GET, url, params,
new RequestCallBack<String>() {
// 请求失败
@Override
public void onFailure(HttpException arg0, String arg1) {
arg0.printStackTrace();
// 请求失败能够发送经纬度
smsManager.sendTextMessage(safeNum, null, "longitude ="
+ longitude + "latitude=" + latitude, null,
null);
}
// 请求成功
@Override
public void onSuccess(ResponseInfo<String> arg0) {
String result = arg0.result;// 获取返回结果
System.out.println("result=" + result);
try {
// 解析json数据
JSONObject jObject = new JSONObject(result);
JSONObject resultObj = jObject
.getJSONObject("result");
String addr = resultObj.getString("address");// 地址
// 发短信给安全号码
smsManager.sendTextMessage(safeNum, null, "wozai "
+ addr, null, null);
stopSelf();//中止当前服务
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
## 超级管理员 ##
> Administration官方文档介绍: http://developer.android.com/guide/topics/admin/device-admin.html
> 应用: 锁屏, 清除系统数据
> Demo中的案例演示
配置超级管理员步骤:
1. 自定义Receiver,继承DeviceAdminReceiver
2. 配置manifest
<receiver
android:name=".AdminReceiver"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
3. 添加配置文件@xml/device_admin_sample
4. 获取DevicePolicyManager
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE)
5. 一键锁屏
mDPM.lockNow();//锁屏
mDPM.resetPassword("123", 0);//设置锁屏密码
注意: 必须先打开设置->安全->设备管理器的权限,不然运行崩溃
6. 经过代码打开超级管理员权限
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
ComponentName component = new ComponentName(this, AdminReceiver.class);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, component);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"打开超级管理员权限,能够一键锁屏,删除数据等");
startActivity(intent);
7. 验证是否已经激活设备管理员
ComponentName component = new ComponentName(this, AdminReceiver.class);
if (mDPM.isAdminActive(component)) {
}
8. 一键锁屏
9. 清除数据
//mDPM.wipeData(0);//恢复出厂设置
//mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);//清除sdcard内容
- 将超级管理员功能整合到手机卫士中
>在手机防盗设置页面4 激活设备管理员
dm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
componentName = new ComponentName(this, AdminReceiver.class);
// 刚进入页面根据是否激活 设置对应的图片
if (dm.isAdminActive(componentName)) {
// 已经激活
imgActive.setImageResource(R.drawable.admin_activated);
} else {
imgActive.setImageResource(R.drawable.admin_inactivated);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.rl_sjfdset4_active:
// 判断是否激活
if (dm.isAdminActive(componentName)) {
// 已经激活 取消激活
dm.removeActiveAdmin(componentName);
imgActive.setImageResource(R.drawable.admin_inactivated);
} else {
// 没有激活 跳转到激活页面
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "安全卫士的设备管理员");
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
}
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ENABLE_ADMIN) {
//激活成功后返回
if (resultCode == Activity.RESULT_OK) {
imgActive.setImageResource(R.drawable.admin_activated);
}
}
}
>短信拦截后相关处理
1.生成DevicePolicyManager对象 做为成员变量
dm = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
//建立ComponentName对象 判断是否激活设备管理员时须要用到
who = new ComponentName(context, AdminReceiver.class);
2.对应的短信拦截功能
else if ("#*wipedata*#".equals(messageBody)) {
// 清除数据
dm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
abortBroadcast();// 拦截掉短信 不让广播继续往下传
} else if ("#*lockscreen*#".equals(messageBody)) {
if (dm.isAdminActive(who)) {
dm.lockNow();// 锁屏
dm.resetPassword("123", 0);//设置锁屏密码
}
abortBroadcast();// 拦截掉短信 不让广播继续往下传
}
## 骚扰拦截功能/黑名单管理 ##
- 添加黑名单须要用到sqlite数据库
1. 建立 BlackListDbHelper 继承自SQLiteOpenHelper
2. 写构造方法
public BlackListDbHelper(Context context) {
super(context, BlackListDBConstants.BLACK_DB, null, BlackListDBConstants.version);
}
BlackListDBConstants存储黑名单数据库相关的常量 包括数据库名称 版本 包名 字段 建立语句等。
public interface BlackListDBConstants {
String BLACK_DB = "black_db";// 黑名单数据库名称
int version = 1;// 黑名单数据库版本
String TABLE_NAME = "black_list";
String COLUMN_ID = "_id";
String COLUMN_NUMBER = "number";
String COLUMN_TYPE = "_type";
String SQL_CREATE = "create table " + TABLE_NAME + "(" + COLUMN_ID
+ " integer primary key autoincrement," + COLUMN_NUMBER + " varchar unique,"
+ COLUMN_TYPE + " integer)";
}
3.建立表
// 第一次建立数据库时调用
@Override
public void onCreate(SQLiteDatabase db) {
// 建立表
db.execSQL(BlackListDBConstants.SQL_CREATE);
}
// 数据库版本升级时调用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
4.建立DAO 写增删改查方法
BlackListDbHelper blackListDbHelper;
public BlackListDAO(Context ctx) {
blackListDbHelper = new BlackListDbHelper(ctx);
}
// 插入一条黑名单数据
public boolean add(String phone, int type) {
SQLiteDatabase database = blackListDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BlackListDBConstants.COLUMN_NUMBER, phone);
values.put(BlackListDBConstants.COLUMN_TYPE, type);
long insert = database.insert(BlackListDBConstants.TABLE_NAME, null, values);
database.close();
return insert != -1;
}
// 删除一条黑名单数据
public boolean delete(String phone) {
SQLiteDatabase database = blackListDbHelper.getWritableDatabase();
String whereClause = BlackListDBConstants.COLUMN_NUMBER + "= ?";
String[] whereArgs = new String[] { phone };
int delete = database.delete(BlackListDBConstants.TABLE_NAME, whereClause,
whereArgs);
database.close();
return delete != 0;
}
// 修改一条黑名单数据的拦截方式
public boolean update(String phone, int type) {
SQLiteDatabase database = blackListDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BlackListDBConstants.COLUMN_TYPE, type);
String whereClause = BlackListDBConstants.COLUMN_NUMBER + "= ?";
String[] whereArgs = new String[] { phone };
int update = database.update(BlackListDBConstants.TABLE_NAME, values,
whereClause, whereArgs);
database.close();
return update != 0;
}
// 查询一条黑名单数据的拦截方式
public int findType(String phone) {
SQLiteDatabase database = blackListDbHelper.getWritableDatabase();
String sql = "select " + BlackListDBConstants.COLUMN_TYPE + " from "
+ BlackListDBConstants.TABLE_NAME + " where "
+ BlackListDBConstants.COLUMN_NUMBER + " = ?";
String[] selectionArgs = new String[] { phone };
Cursor cursor = database.rawQuery(sql, selectionArgs);
int type = -1;
if (cursor != null) {
if (cursor.moveToNext()) {
type = cursor.getInt(0);
}
cursor.close();
}
database.close();
return type;
}
// 查询全部黑名单数据
public ArrayList<BlackInfo> findALL() {
SQLiteDatabase database = blackListDbHelper.getWritableDatabase();
String sql = "select " + BlackListDBConstants.COLUMN_NUMBER + ","
+ BlackListDBConstants.COLUMN_TYPE + " from "
+ BlackListDBConstants.TABLE_NAME;
Cursor cursor = database.rawQuery(sql, null);
ArrayList<BlackInfo> infos = new ArrayList<BlackInfo>();
if (cursor != null) {
while (cursor.moveToNext()) {
String number = cursor.getString(0);
int type = cursor.getInt(1);
BlackInfo info = new BlackInfo(number, type);
infos.add(info);
}
cursor.close();
}
database.close();
return infos;
}
5.测试DAO
> 建立一个类 TestBlackDAO 继承 AndroidTestCase
> 在AndroidManifest.xml里添加
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.itheima.mobilesafe81" >
</instrumentation>
application标签里面添加
<uses-library android:name="android.test.runner" >
</uses-library>
>测试
public void testAdd() {
BlackListDAO dao = new BlackListDAO(getContext());
dao.add("185100", 0);
dao.add("185105", 2);
dao.add("185107", 1);
}
public void delete() {
BlackListDAO dao = new BlackListDAO(getContext());
boolean delete = dao.delete("111");
assertEquals(delete, true);
}
public void testupdate() {
BlackListDAO dao = new BlackListDAO(getContext());
boolean update = dao.update("185107", 2);
assertEquals(update, true);
}
public void testfind() {
BlackListDAO dao = new BlackListDAO(getContext());
int type = dao.findType("185107");
assertEquals(type, 2);
}
- 添加一条数据
/**
* 保存或者更新的点击事件
*
* @param v
*/
public void confirmClick(View v) {
// 1.获取输入的号码
String number = etNum.getText().toString().trim();
// 2.判断是否为空
if (TextUtils.isEmpty(number)) {
Toast.makeText(getApplicationContext(), "号码不能为空", 0).show();
return;
}
// 3.获取拦截类型
int checkedRadioButtonId = rgType.getCheckedRadioButtonId();
// 4.判断是否为空
if (checkedRadioButtonId == -1) {
Toast.makeText(getApplicationContext(), "拦截类型不能为空", 0).show();
return;
}
int type = 0; // 根据选中的id 生成拦截方式
switch (checkedRadioButtonId) {
case R.id.rb_eb_number:
type = BlackInfo.TYPE_NUMBER;
break;
case R.id.rb_eb_sms:
type = BlackInfo.TYPE_SMS;
break;
case R.id.rb_eb_all:
type = BlackInfo.TYPE_ALL;
break;
default:
break;
}
// 保存
// 1.保存数据库
boolean success = mDao.insert(number, type);
if (success) {
Intent data = new Intent();
data.putExtra(EXTRA_NUMBER, number);// 电话号码
data.putExtra(EXTRA_TYPE, type);// 拦截方式
// 2.数据传回上一个页面
setResult(Activity.RESULT_OK, data);
// 3.页面消失
finish();
} else {
Toast.makeText(getApplicationContext(), "保存失败", 0).show();
}
}
- 获取传回的数据 在列表页面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ADD) {// 判断是添加返回
if (resultCode == Activity.RESULT_OK) {
// 1获取传回的数据
String number = data
.getStringExtra(EditBlackActivity.EXTRA_NUMBER);
int type = data.getIntExtra(EditBlackActivity.EXTRA_TYPE, 1);
System.out.println("number ="+number);
System.out.println("type ="+type);
}
}
}