#安全卫士手机防盗#


###1.Activity的任务栈
1.类似一个木桶,每层只能放一个木块,我们放入木块和取出木块的时候只能从最上面开始操作

###2.Android中的坐标系
![](http://i.imgur.com/3h68mMz.png)

###3.用xml文件描述动画
在res文件夹下创建anim文件夹,anim文件夹下创建动画的xml文件

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:andro > //结束点y坐标
</translate>

###4.Activity进入和退出的动画
1.在finish()或者startActivity()方法后调用overridePendingTransition,设置进入和退出的动画

overridePendingTransition(R.anim.anim_in, R.anim.anim_out);

###5.识别手势动作

1.定义手势识别器
private GestureDetector mGestureDetector;

2.初始化手势识别器,处理手势,执行对应的逻辑
mGestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
// 当用户手指在屏幕上滑动的时候调用的方法
// e1 手指第一次触摸到屏幕的事件
// e2 手指离开屏幕一瞬间对应的事件
// velocityX 水平方向的速度
// velocityY 垂直方向的速度 单位像素/s
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (Math.abs(velocityX) < 200) {
Log.i(TAG, "移动的太慢,无效动作");
return true;
}
if (Math.abs(e2.getRawY() - e1.getRawY()) > 50) {
Log.i(TAG, "垂直方向移动过大,无效动作");
return true;
}
if ((e1.getRawX() - e2.getRawX()) > 200) {
Log.i(TAG, "向左滑动,显示下一个界面");
next();
return true;
}
if ((e2.getRawX() - e1.getRawX()) > 200) {
Log.i(TAG, "向右滑动,显示上一个界面");
pre();
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}

});

3.重写onTouchEvent方法,让手势识别器处理手势操作
@Override
public boolean onTouchEvent(MotionEvent event) {
// 让手势识别器识别传入进来的事件
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}

###6.GestureDetector.SimpleOnGestureListener其他方法补充

1.手指按下时触发
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

2.手指抬起时触发,单击事件
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

3.双击事件
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// TODO Auto-generated method stub
return super.onDoubleTapEvent(e);
}

4.长按事件
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub

}

5.手指在屏幕上拖动事件,手指一直没有离开屏幕
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}

6.滑动事件,当手指拖动之后抬起触发。手指在屏幕上滑动都会有一个速度,当手指离开的时候如果我们希望控件有惯性的继续滑动可以在此处实现
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
}

###7.将公共部分抽取为一个基类

1.新建一个XXXBaseActivity的基类,如果继承他的子类在公共的部分有不同的操作,则将该类声明为抽象类,否则则不需要
public abstract class SetupBaseActivity extends Activity {

2.抽取出公共部分的代码,并进行对应的修改
protected static final String TAG = "SetupBaseActivity";
// 1.定义一个手势识别器
private GestureDetector mGestureDetector;
protected SharedPreferences sp;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getSharedPreferences("config", MODE_PRIVATE);
// 2.初始化手势识别器
mGestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
// 当用户手指在屏幕上滑动的时候调用的方法
// e1 手指第一次触摸到屏幕的事件
// e2 手指离开屏幕一瞬间对应的事件
// velocityX 水平方向的速度
// velocityY 垂直方向的速度 单位像素/s
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (Math.abs(velocityX) < 200) {
Log.i(TAG, "移动的太慢,无效动作");
return true;
}
if (Math.abs(e2.getRawY() - e1.getRawY()) > 50) {
Log.i(TAG, "垂直方向移动过大,无效动作");
return true;
}
if ((e1.getRawX() - e2.getRawX()) > 200) {
Log.i(TAG, "向左滑动,显示下一个界面");
next();
return true;
}
if ((e2.getRawX() - e1.getRawX()) > 200) {
Log.i(TAG, "向右滑动,显示上一个界面");
pre();
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}

});
}
/**
* 当用户手指在屏幕上触摸的时候调用的方法
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// 让手势识别器识别传入进来的事件
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}

3.如果子类在公共的代码部分有不同的操作,将类声明为抽象类,声明对应的抽象方法,在不同的操作处调用抽象方法
/**
* 显示下一个
*/
public abstract void next();
/**
* 显示上一个
*/
public abstract void pre();

4.让子类实现所有的抽象方法
public class Setup1Activity extends SetupBaseActivity {
protected static final String TAG = "Setup1Activity";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup1);
}

@Override
public void next() {
openNewActivityAndFinish(Setup2Activity.class);
// 修改Activity切换的动画效果
overridePendingTransition(R.anim.anim_in, R.anim.anim_out);
}

@Override
public void pre() {

}
}
###8.获取手机sim卡串号
1.清单文件中添加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
2.拿到TelephonyManager
private TelephonyManager tm;
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
3.调用方法getSimSerialNumber
tm.getSimSerialNumber();

###9.使用控制台查看数据
1.adb shell 命令进入到控制台
2.cd 命令进入到文件夹
3.ls 命令列出该文件夹下所有文件
4.cat config.xml 命令查看config.xml文件内容

###10.联系人数据库
1.加权限
<uses-permission android:name="android.permission.READ_CONTACTS" />
2.data/data/com.android.provider.contacts/databases/contacts2.db
3.raw_contacts表contact_id列存联系人id
4.data表存联系人数据
5.mimetypes存数据类型

###11.获取联系人数据
public static List<ContactInfo> getAllContactInfos(Context context) {
List<ContactInfo> infos = new ArrayList<ContactInfo>();
ContentResolver resolver = context.getContentResolver();
// 查询raw_contact表
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
null, null, null);
while (cursor.moveToNext()) {
String id = cursor.getString(0);
System.out.println("Id:" + id);
if (id != null) {
ContactInfo info = new ContactInfo();
// 查询data表
Cursor datacursor = resolver.query(datauri, new String[] {
"data1", "mimetype" }, "raw_contact_id=?",
new String[] { id }, null);
while (datacursor.moveToNext()) {
String data1 = datacursor.getString(0);
String mimetype = datacursor.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)) {
info.setName(data1);
} else if ("vnd.android.cursor.item/im".equals(mimetype)) {
info.setQq(data1);
} else if ("vnd.android.cursor.item/email_v2"
.equals(mimetype)) {
info.setEmail(data1);
} else if ("vnd.android.cursor.item/phone_v2"
.equals(mimetype)) {
info.setPhone(data1);
}
}
datacursor.close();
infos.add(info);
}
}
cursor.close();
SystemClock.sleep(3000);
return infos;
}

联系人数据的另一种查询方式:[Contacts 联系人详解](http://blog.csdn.net/wssiqi/article/details/8152630)

###12.在另一个Activity中获取数据
1.在当前Activity中调用startActivityForResult
Intent intent = new Intent(this,SelectContactActivity.class);
startActivityForResult(intent, 0);
2.在另一个Activity中设置数据,调用setResult,设置对应的结果码和数据
String phone = infos.get(position).getPhone();
Intent data = new Intent();
data.putExtra("phone", phone);
//设置结果数据
setResult(0, data);
//关闭当前界面
finish();
3.在当前Activity中的onActivityResult中接收回传过来的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(data!=null){
String phone = data.getStringExtra("phone");
et_setup3_phone.setText(phone);
}
super.onActivityResult(requestCode, resultCode, data);
}

###13.获取大量数据时的优化方法
1.将获取数据的操作放在子线程里
2.界面上显示进度条
3.获取数据后更新界面
4.隐藏进度条

###14.子线程中想更新界面一个方便的方法
1.调用runOnUiThread方法
runOnUiThread(new Runnable() {
@Override
public void run() {
ll_loading.setVisibility(View.INVISIBLE);
lv_select_contact.setAdapter(new ContactAdapter());
}
});

###15.接收手机开机广播
1.添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2.创建开机广播接收者
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompleteReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG,"手机启动完毕了.");
//判断用户是否开启了手机防盗的功能.
SharedPreferences sp = context.getSharedPreferences("config", Context.MODE_PRIVATE);
boolean protecting = sp.getBoolean("protecting", false);
if(protecting){
Log.i(TAG,"防盗保护已经开启,检测sim卡是否一致.");
//用户绑定的sim串号
String savedSim = sp.getString("sim", "");
//获取当前手机里面的sim串号
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String currentSim = tm.getSimSerialNumber()+"afa";
if(savedSim.equals(currentSim)){
Log.i(TAG,"sim卡一致,还是您的手机");
}else{
Log.i(TAG,"sim卡不一致,手机可能被盗,发送报警短信");
String safenumber = sp.getString("safenumber", "");
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(safenumber, null, "SOS...phone may lost", null, null);
}
}
}
}
3.在清单文件里配置广播接收者
<receiver android:name="com.hb.mobilesafe.ui.receiver.BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

###16.发送短信
1.添加权限
<uses-permission android:name="android.permission.SEND_SMS" />
2.获得SmsManager
SmsManager smsManager = SmsManager.getDefault();
3.调用sendTextMessage方法
smsManager.sendTextMessage(safenumber, null, "SOS...phone may lost", null, null);

###17.解析短信
1.定义接收短信广播接收者
public class SmsReceiver extends BroadcastReceiver {

private static final String TAG = "SmsReceiver";

}
2.在清单文件中配置。将优先级配置为最高1000,接收到就终止广播,不在系统中提示接收到短信
<receiver android:name="com.hb.mobilesafe.ui.receiver.SmsReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
3.添加接收短信的权限
<uses-permission android:name="android.permission.RECEIVE_SMS" />
4.在onReceive方法中解析短信
@Override
public void onReceive(Context context, Intent intent) {
Object[] objs = (Object[]) intent.getExtras().get("pdus");
for(Object obj:objs){
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);
String body = smsMessage.getMessageBody();
if("#*location*#".equals(body)){
Log.i(TAG,"返回手机的位置..");
abortBroadcast();
}else if ("#*alarm*#".equals(body)){
Log.i(TAG,"播放报警音乐..");
abortBroadcast();
}else if ("#*wipedata*#".equals(body)){
Log.i(TAG,"立刻清除数据..");
abortBroadcast();
}else if ("#*lockscreen*#".equals(body)){
Log.i(TAG,"立刻锁屏..");
abortBroadcast();
}
}
}

###18.播放报警音乐
1.将音频文件放在res/raw目录下
2.具体实现,即使手机处于静音模式,也会播放音乐
MediaPlayer player = MediaPlayer.create(context, R.raw.ylzs);
player.start();


###1.定位方式
1.网络定位 (ip地址)
根据ip地址定位,如果是静态ip很准确,如果是动态ip是一个大概的范围
2.基站定位
根据附近的基站数量来决定定位的精度,附近基站越多定位越准确
3.GPS定位
通过三颗以上的卫星获取手机的位置(头顶必须空旷)
AGPS,利用网络进行大致定位,利用卫星进行修正定位

###2.获取手机经纬度
1.添加权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2.获取系统服务LocationManager
lm = (LocationManager) getSystemService(LOCATION_SERVICE);
3.请求位置数据
lm.requestLocationUpdates("gps", 60*1000, 100, locationListener);
4.不用的时候注销掉监听器
lm.removeUpdates(locationListener);
locationListener = null;

###3.位置监听器
private class MyLocationListener implements LocationListener{

//位置发生变化的时候
@Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
location.getLatitude(); //维度
location.getLongitude(); //经度
}

//当位置提供者状态发生变化的时候,可用-->不可用,不可用-->可用
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub

}

//当位置提供者可用的时候
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub

}

//当位置提供者不可用的时候
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub

}

}

###4.火星坐标系统
1. 是一种国家保密插件,其实就是对真实坐标系统进行人为的加偏处理,按照特殊的算法,将真实的坐标加密成虚假的坐标,而这个加偏并不是线性的加偏,所以各地的偏移情况都会有所不同。而加密后的坐标也常被人称为火星坐标系统。
2. 火星坐标的转化

//1.获取数据输入流
File file = new File("axisoffset.dat");
FileInputStream is = new FileInputStream(file);
//2.获取ModifyOffset实例
ModifyOffset mo = ModifyOffset.getInstance(is);
//3.转化为火星坐标,standard-->China
PointDouble result = mo.s2c(new PointDouble(113.9083f, 22.5854f));

###5.获取手机位置功能所需知识点
1.获取手机经纬度
2.转化为火星坐标
3.由于获取经纬度是耗时任务,在Service中来获取

###6.在服务中停掉自己
1.调用stopSelf()方法

###7.创建设备管理员的步骤
1.新建一个类,继承DeviceAdminReceiver
public class MyAdmin extends DeviceAdminReceiver {

}
2.在清单文件中进行配置
<receiver
android:name="com.hb.mobilesafe.ui.receiver.MyAdmin" //广播接收者的全类名
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.android:name处填入广播接收者的全类名
4.新建label和description对应的字符串,声明标签和描述的内容
5.新建device_admin_sample.xml文件,声明要使用的管理员权限
<device-admin xmlns:andro>
<uses-policies>
<limit-password /> //设置密码规则
<watch-login /> //监视屏幕解锁尝试次数
<reset-password /> //更改屏幕解锁密码
<force-lock /> //锁定屏幕
<wipe-data /> //清除所有数据
<expire-password /> //设置锁定屏幕密码的有效期
<encrypted-storage /> //设置存储设备加密
<disable-camera /> //停用相机
</uses-policies>
</device-admin>

###8.清除数据
1.拿到设备策略管理器
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
2.调用wipeData方法
dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);

###9.设置密码并锁屏
1.拿到设备策略管理器
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
2.设置密码调用resetPassword方法
dpm.resetPassword("123", 0);
3.锁屏调用lockNow方法
dpm.lockNow();

###10.一键锁屏应用的问题
1.没有激活设备管理员,导致锁屏功能不能用
2.激活了设备管理员,导致不能卸载

###10.一键锁屏的优化
1.如果未激活设备管理员权限,用代码打开设备管理员激活界面
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who = new ComponentName(this, MyAdmin.class);
if (dpm.isAdminActive(who)) {
dpm.lockNow();
} else {
Toast.makeText(this, "请先激活超级管理员", 0).show();
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,who);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"请开启管理员权限,开启后可以锁屏,不装扣500块钱");
startActivity(intent);
}
2.要卸载具有设备管理员权限的应用,要首先将其设别管理员权限取消,然后在进行卸载
//取消设备管理员权限
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who = new ComponentName(this, MyAdmin.class);
dpm.removeActiveAdmin(who);
//卸载当前应用
Intent intent = new Intent();
intent.setAction("android.intent.action.DELETE");
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse("package:"+getPackageName()));
startActivity(intent);

###11.MD5加密
1.获取MessageDigest实例
MessageDigest digest = MessageDigest.getInstance("md5");
2.使用digest获取加密后的byte数组
byte[] result = digest.digest(password.getBytes());
3.将加密后的byte数组转化为定长的16进制字符串
StringBuilder sb = new StringBuilder();
for(byte b : result){
int number = b&0xff-3;//加盐
String str = Integer.toHexString(number);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
return sb.toString();

- MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。它的作用是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数)。
- MD5是哈希散列算法,对于MD5而言,有两个特性是很重要的,第一:明文数据经过散列以后的值是定长的;第二:是任意一段明文数据,经过散列以后,其结果必须永远是不变的。前者的意思是可能存在有两段明文散列以后得到相同的结果,后者的意思是如果我们散列特定的数据,得到的结果一定是相同的。

 

手机防盗向导页面:

 1 package com.hb.mobilesafe.activities;
 2 
 3 import android.os.Bundle;
 4 import android.view.Window;
 5 
 6 import com.hb.demo_mobilesafe.R;
 7 
 8 public class StepOnePage_Activity extends StepBaseActivity {
 9     
10     @Override
11     protected void onCreate(Bundle savedInstanceState) {
12         // TODO Auto-generated method stub
13         super.onCreate(savedInstanceState);
14         requestWindowFeature(Window.FEATURE_NO_TITLE);
15         setContentView(R.layout.activity_step1);
16         
17 
18     }
19     @Override
20     void showNext() {
21         openAndFinishActivity(StepTwoPage_Activity.class);
22         overridePendingTransition(R.anim.next_go, R.anim.next_dispper);
23         finish();
24         
25     }
26     @Override
27     void showPre() {
28         
29     }
30     
31 }
View Code

相关文章: