一周前老师布置了一个任务,要求实现一个简单的手机防盗软件,这东西在好些年前非常流行,几乎每个XX管家都搞了一个这个功能,当然现在也是
时过境迁,其实好多功能已经不太能够实现了。
最近开始试着去画思维导图,其实这篇文章是来展现我高超的思维导图技巧的~
实际上就是把实验报告全部贴上来了,又水了一篇文章,真开心~
项目心得就不贴了,害羞
项目简介与功能说明
(主要介绍本项目的应用意义与要完成的所有功能)
项目分析与设计
(主要描述针项目的分析与设计过程,如:项目的总的结构框图,项目功能模块、项目的技术难点以及解决这些难点的方法)
三 项目实现与关键代码
(以流程图和关键代码来说明各功能模块的实现)
备注:
(1)流程图有点复杂,所以不方便用直线+实线,只好用虚线+曲线的形式给出。
(2)部分逻辑并未体现在图内,实际上设置信息及安全号码通过sharepreferences保存,所有功能模块执行前需要判断一次sharepreferences里的对应设置内容,只有当对应设置开关打开时才允许该功能模块执行。
(3)判断短信内容新添加了根据短信内容设置锁屏密码的机制,如发送lock88888,即将手机密码设置为88888。
关键代码:
实际上项目的重中之重就是SIM状态监听和短信监听了,核心功能的实现基本在这两部分,其余部分如开机启动监听,实际上是为了让项目整体更符合“手机防盗软件”定位的辅助部分。
SIM卡状态***(SIM卡状态监听广播)
public class SimReceiver extends BroadcastReceiver {
private final static String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
static String old_phonen_umber = null;
static String new_phonen_umber = null;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_SIM_STATE_CHANGED)) {
//SharedPreferences
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
Boolean checkbox_core = sp.getBoolean("checkbox_core", false);
Boolean checkbox_sim = sp.getBoolean("checkbox_sim", false);
//Log.i("Theft_phone_number", "**访问onReceive开始,初始号码为:" + old_phonen_umber);
TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_NUMBERS) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
Log.i("Theft_phone_number", "没有给予对应的权限而退出");
return;
}
new_phonen_umber = tm.getLine1Number();
if (new_phonen_umber != null) {
if (!new_phonen_umber.isEmpty()) {
if (checkbox_core) {
Log.i("Theft_setting", "核心服务已启动");
if (checkbox_sim) {
Log.i("Theft_setting", "SIM监控服务已启动,一切准备就绪");
Log.i("Theft_phone_number", "执行了一次有效的电话号赋值:" + new_phonen_umber + "拟将新旧SIM信息进行替换");
if (old_phonen_umber == new_phonen_umber) {
Log.i("Theft_phone_number", "新旧SIM信息相同,不执行操作");
} else {
old_phonen_umber = new_phonen_umber;
Log.i("Theft_phone_number", "SIM卡发生变化,现在的SIM号码信息已经替换为:" + old_phonen_umber);
//读取...
String edittext_num = sp.getString("edittext_num", "");
if (!edittext_num.equals("")) {
SmsManager.getDefault().sendTextMessage(edittext_num, null, "请当心SIM卡状态发生变化,SIM卡号目前为:" + old_phonen_umber, null, null);
}
}
Log.i("Theft_phone_number", "---------------------onReceive执行结束---------------------");
} else {
Log.i("Theft_setting", "SIM监控服务未启动,终止");
}
} else {
Log.i("Theft_setting", "核心服务未启动,终止");
}
}
}
}
}
}
短信***(短信监听广播)
public class SmsReceiver extends BroadcastReceiver {
private DevicePolicyManager mDPM;
private PowerManager.WakeLock wakeLock;
private PowerManager pm;
KeyguardManager km;
KeyguardManager.KeyguardLock keyguradLock;
@SuppressLint("InvalidWakeLockTag")
@Override
public void onReceive(Context context, Intent intent) {
mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Bundle bundle=intent.getExtras();
if (bundle!=null){
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
Boolean checkbox_unlock = sp.getBoolean("checkbox_unlock", false);
Boolean checkbox_lock = sp.getBoolean("checkbox_lock", false);
String edittext_num = sp.getString("edittext_num", "");
Object[] objs= (Object[]) bundle.get("pdus");
SmsMessage[] smsMessages=new SmsMessage[objs.length];
for (int i=0;i<objs.length;i++){
smsMessages[i]=SmsMessage.createFromPdu((byte[])objs[i]);
//发送方的号码
String number=smsMessages[i].getDisplayOriginatingAddress();
Log.i("Theft_message","监听到的号码:"+number);
//获取短信的内容
String content = smsMessages[i].getDisplayMessageBody();
String pre_four = "nodata";
String tel = "123456";
Log.i("Theft_message","监听到的内容:"+content);
if (!TextUtils.isEmpty(content) && content.length()>=4){
pre_four = (content.substring(0,4));
Log.i("Theft_message","赋值pre_four为"+pre_four);
}
if(number.equals("+"+edittext_num)){
Log.i("Theft_message","监听到安全号码发送的消息,进行服务启动情况判断");
if(pre_four.equals("lock")){
if (checkbox_lock) {
Log.i("Theft_message", "远程锁屏服务已启动");
Log.i("Theft_message","执行锁定操作");
//mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);清除数据
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if(km.isKeyguardSecure()){
Log.i("Theft_message","已经锁定");
mDPM.lockNow();
}else{
Log.i("Theft_message","没有锁定,进行锁定");
//锁屏设置密码
if (!TextUtils.isEmpty(content) && content.length()>=4){
tel=(content.substring(4,content.length()));
Log.i("Theft_message","赋值tel为"+tel);
}
mDPM.resetPassword(tel, 0);
mDPM.lockNow();
}
}else{
Log.i("Theft_message","试图去进行判断锁屏情况,但是API等级不够");
}
}else{
Log.i("Theft_message", "远程锁屏服务未启动");
}
}else if(content.equals("unlock")){
if (checkbox_unlock) {
Log.i("Theft_message", "远程解锁服务已启动");
Log.i("Theft_message","执行解锁操作");
wakeLock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "unLock");
wakeLock.acquire();
// 键盘锁管理器对象
keyguradLock = km.newKeyguardLock("unLock");
keyguradLock.disableKeyguard();
}else{
Log.i("Theft_message", "远程解锁服务未启动");
}
}
}
}
//黑名单...
abortBroadcast();
}
}
项目调试与结果
(主要介绍项目调试中发现的问题和解决方法以及整个项目正常运行的结果截图)
(1)项目UI逻辑(优先级:核心组件>是否打开SIM监控>安全号码>远程锁屏&远程解锁)
只有核心组件被启动,才能开启后续功能模块。
只有SIM监控被启动,才能进行安全号码输入及保存。
只有SIM监控被启动,安全号码被设置完毕,才能启动远程锁屏和解锁,否则弹出如下提示。
(2)“钥匙”机制(项目实际为2个APP,一个为防盗软件本体,另一个为“钥匙”,防盗软件本体安装后无法在桌面看到图标)
如下图,无法看到本体的图标(本体名为手机防盗助手),但它确实其实已经安装了,可以看到的是Key的图标,打开Key会自动唤醒本体的UI界面,用户只需要在第一次进行配置和需要对配置进行修改的时候下载安装Key即可,平时完全可以把Key卸载,不会影响本体的运行。
上述机制很好的解决了,手机丢失情况下,防盗软件可能被有意卸载,通过隐藏图标的形式保障了本体的安全,而且由于获取了设备管理器权限,实际上在设置界面也是不能直接卸载应用的。
(3)动态权限申请(一般情况下,项目首次启动会进行权限申请,会直接跳到对应的申请界面)
这里其实权限要多了…
(4)远程锁定,格式lock+密码,可以将手机密码远程设置为指定内容。
点击发送,同时配置了完整的日志系统
(5)远程解锁,格式unlock,可以将手机远程唤醒
同样也配置了完整的日志系统
(6)为了适应API机制,加入了锁定检查,已经锁定的手机无法再次进行锁定,避免了异常的发生,已经锁定的手机收到锁定命令只会执行熄屏。
(7)开机自启动测试
可以看到,并未载入项目UI界面,但是项目已经在后台启动了,在控制台也又有对应的日志文件,同时输出了设备的配置信息。
(8)接上测试,SIM卡状态变化自动发送当前SIM卡号
由于系统重启时重新加载了SIM卡服务,等价于一次SIM卡插拔操作,项目后台自动发送了一条警告信息给安全号码,如下图。左为测试机,右为安全号码机(也已经成功收到短信)