欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android程序锁的实现以及逻辑

程序员文章站 2024-03-04 21:09:42
本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个“看门狗”的服务定时监视顶层activity,如果activity对应的包名是之前上锁的应用程序的,则...

本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个“看门狗”的服务定时监视顶层activity,如果activity对应的包名是之前上锁的应用程序的,则弹出一个页面要求输入解锁密码。

效果如下:

Android程序锁的实现以及逻辑

1.基本思路

①.创建已加锁应用的数据库(字段:_id,packagename),如果应用已加锁,将加锁应用的包名维护到数据库中

②.已加锁+未加锁 == 手机中所有应用(appinfoprovider)

2.已加锁和未加锁的数据适配器

class myadapter extends baseadapter{
 private boolean islock;
 /**
 * @param islock 用于区分已加锁和未加锁应用的标示 true已加锁数据适配器 false未加锁数据适配器
 */
 public myadapter(boolean islock) {
 this.islock = islock;
 }
 @override
 public int getcount() {
 if(islock){
  tv_lock.settext("已加锁应用:"+mlocklist.size());
  return mlocklist.size();
 }else{
  tv_unlock.settext("未加锁应用:"+munlocklist.size());
  return munlocklist.size();
 }
 }

 @override
 public appinfo getitem(int position) {
 if(islock){
  return mlocklist.get(position);
 }else{
  return munlocklist.get(position);
 }
 }

 @override
 public long getitemid(int position) {
 return position;
 }

 @override
 public view getview(int position, view convertview, viewgroup parent) {
 viewholder holder = null;
 if(convertview == null){
  convertview = view.inflate(getapplicationcontext(), r.layout.listview_islock_item, null);
  holder = new viewholder();
  holder.iv_icon = (imageview) convertview.findviewbyid(r.id.iv_icon);
  holder.tv_name = (textview) convertview.findviewbyid(r.id.tv_name);
  holder.iv_lock = (imageview) convertview.findviewbyid(r.id.iv_lock);
  
  convertview.settag(holder);
 }else{
  holder = (viewholder) convertview.gettag();
 }
 final appinfo appinfo = getitem(position);
 final view animationview = convertview;
 
 holder.iv_icon.setbackgrounddrawable(appinfo.icon);
 holder.tv_name.settext(appinfo.name);
 if(islock){
  holder.iv_lock.setbackgroundresource(r.drawable.lock);
 }else{
  holder.iv_lock.setbackgroundresource(r.drawable.unlock);
 }
 holder.iv_lock.setonclicklistener(new onclicklistener() {
  @override
  public void onclick(view v) {
  //添加动画效果,动画默认是非阻塞的,所以执行动画的同时,动画以下的代码也会执行
  animationview.startanimation(mtranslateanimation);//500毫秒
  //对动画执行过程做事件监听,监听到动画执行完成后,再去移除集合中的数据,操作数据库,刷新界面
  mtranslateanimation.setanimationlistener(new animationlistener() {
   @override
   public void onanimationstart(animation animation) {
   //动画开始的是调用方法
   }
   @override
   public void onanimationrepeat(animation animation) {
   //动画重复时候调用方法
   }
   //动画执行结束后调用方法
   @override
   public void onanimationend(animation animation) {
   if(islock){
    //已加锁------>未加锁过程
    //1.已加锁集合删除一个,未加锁集合添加一个,对象就是getitem方法获取的对象
    mlocklist.remove(appinfo);
    munlocklist.add(appinfo);
    //2.从已加锁的数据库中删除一条数据
    mdao.delete(appinfo.packagename);
    //3.刷新数据适配器
    mlockadapter.notifydatasetchanged();
   }else{
    //未加锁------>已加锁过程
    //1.已加锁集合添加一个,未加锁集合移除一个,对象就是getitem方法获取的对象
    mlocklist.add(appinfo);
    munlocklist.remove(appinfo);
    //2.从已加锁的数据库中插入一条数据
    mdao.insert(appinfo.packagename);
    //3.刷新数据适配器
    munlockadapter.notifydatasetchanged();
   }
   }
  });
  }
 });
 return convertview;
 }
}
mlockadapter = new myadapter(true);
lv_lock.setadapter(mlockadapter);
  
munlockadapter = new myadapter(false);
lv_unlock.setadapter(munlockadapter);

3.已加锁和未加锁条目点击事件处理

holder.iv_lock.setonclicklistener(new onclicklistener() {
 @override
 public void onclick(view v) {
 //添加动画效果,动画默认是非阻塞的,所以执行动画的同时,动画以下的代码也会执行
 animationview.startanimation(mtranslateanimation);//500毫秒
 //对动画执行过程做事件监听,监听到动画执行完成后,再去移除集合中的数据,操作数据库,刷新界面
 mtranslateanimation.setanimationlistener(new animationlistener() {
  @override
  public void onanimationstart(animation animation) {
  //动画开始的是调用方法
  }
  @override
  public void onanimationrepeat(animation animation) {
  //动画重复时候调用方法
  }
  //动画执行结束后调用方法
  @override
  public void onanimationend(animation animation) {
  if(islock){
   //已加锁------>未加锁过程
   //1.已加锁集合删除一个,未加锁集合添加一个,对象就是getitem方法获取的对象
   mlocklist.remove(appinfo);
   munlocklist.add(appinfo);
   //2.从已加锁的数据库中删除一条数据
   mdao.delete(appinfo.packagename);
   //3.刷新数据适配器
   mlockadapter.notifydatasetchanged();
  }else{
   //未加锁------>已加锁过程
   //1.已加锁集合添加一个,未加锁集合移除一个,对象就是getitem方法获取的对象
   mlocklist.add(appinfo);
   munlocklist.remove(appinfo);
   //2.从已加锁的数据库中插入一条数据
   mdao.insert(appinfo.packagename);
   //3.刷新数据适配器
   munlockadapter.notifydatasetchanged();
  }
  }
 });
 }
});

4.程序锁必须在服务中去维护

Android程序锁的实现以及逻辑

①基本思路

  1. 判断当前开启的应用(现在手机可见任务栈)
  2. 如果开启的应用在已加锁的列表中,弹出拦截界面
  3. 看门狗服务,一直(死循环(子线程,可控))对开启的应用做监听
public class watchdogservice extends service {
 private boolean iswatch;
 private applockdao mdao;
 private list<string> mpacknamelist;
 private innerreceiver minnerreceiver;
 private string mskippackagename;
 private mycontentobserver mcontentobserver;
 @override
 public void oncreate() {
 //维护一个看门狗的死循环,让其时刻监测现在开启的应用,是否为程序锁中要去拦截的应用
 mdao = applockdao.getinstance(this);
 iswatch = true;
 watch();
 
 intentfilter intentfilter = new intentfilter(); 
 intentfilter.addaction("android.intent.action.skip");
 
 minnerreceiver = new innerreceiver();
 registerreceiver(minnerreceiver, intentfilter);
 
 
 //注册一个内容观察者,观察数据库的变化,一旦数据有删除或者添加,则需要让mpacknamelist重新获取一次数据
 mcontentobserver = new mycontentobserver(new handler());
 getcontentresolver().registercontentobserver(
  uri.parse("content://applock/change"), true, mcontentobserver);
 super.oncreate();
 }
 
 class mycontentobserver extends contentobserver{

 public mycontentobserver(handler handler) {
  super(handler);
 }
 
 //一旦数据库发生改变时候调用方法,重新获取包名所在集合的数据
 @override
 public void onchange(boolean selfchange) {
  new thread(){
  public void run() {
   mpacknamelist = mdao.findall();
  };
  }.start();
  super.onchange(selfchange);
 }
 }
 
 class innerreceiver extends broadcastreceiver{
 @override
 public void onreceive(context context, intent intent) {
  //获取发送广播过程中传递过来的包名,跳过次包名检测过程
  mskippackagename = intent.getstringextra("packagename");
 }
 }
 
 private void watch() {
 //1,子线程中,开启一个可控死循环
 new thread(){
  public void run() {
  mpacknamelist = mdao.findall();
  while(iswatch){
   //2.监测现在正在开启的应用,任务栈
   //3.获取activity管理者对象
   activitymanager am = (activitymanager) getsystemservice(context.activity_service);
   //4.获取正在开启应用的任务栈
   list<runningtaskinfo> runningtasks = am.getrunningtasks(1);
   runningtaskinfo runningtaskinfo = runningtasks.get(0);
   //5.获取栈顶的activity,然后在获取此activity所在应用的包名
   string packagename = runningtaskinfo.topactivity.getpackagename();
   
   //如果任务栈指向应用有切换,将mskippackagename空字符串
   
   //6.拿此包名在已加锁的包名集合中去做比对,如果包含次包名,则需要弹出拦截界面
   if(mpacknamelist.contains(packagename)){
   //如果现在检测的程序,以及解锁了,则不需要去弹出拦截界面
   if(!packagename.equals(mskippackagename)){
    //7,弹出拦截界面
    intent intent = new intent(getapplicationcontext(),enterpsdactivity.class);
    intent.setflags(intent.flag_activity_new_task);
    intent.putextra("packagename", packagename);
    startactivity(intent);
   }
   }
   //睡眠一下,时间片轮转
   try {
   thread.sleep(500);
   } catch (interruptedexception e) {
   e.printstacktrace();
   }
  }
  };
 }.start();
 
 }
 @override
 public ibinder onbind(intent arg0) {
 return null;
 }
 @override
 public void ondestroy() {
 //停止看门狗循环
 iswatch = false;
 //注销广播接受者
 if(minnerreceiver!=null){
  unregisterreceiver(minnerreceiver);
 }
 //注销内容观察者
 if(mcontentobserver!=null){
  getcontentresolver().unregistercontentobserver(mcontentobserver);
 }
 super.ondestroy();
 }
}
public class enterpsdactivity extends activity {
 private string packagename;
 private textview tv_app_name;
 private imageview iv_app_icon;
 private edittext et_psd;
 private button bt_submit;

 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 //获取包名
 packagename = getintent().getstringextra("packagename");
 setcontentview(r.layout.activity_enter_psd);
 initui();
 initdata();
 }

 private void initdata() {
 //通过传递过来的包名获取拦截应用的图标以及名称
 packagemanager pm = getpackagemanager();
 try {
  applicationinfo applicationinfo = pm.getapplicationinfo(packagename,0);
  drawable icon = applicationinfo.loadicon(pm);
  iv_app_icon.setbackgrounddrawable(icon);
  tv_app_name.settext(applicationinfo.loadlabel(pm).tostring());
 } catch (namenotfoundexception e) {
  e.printstacktrace();
 }
 
 bt_submit.setonclicklistener(new onclicklistener() {
  @override
  public void onclick(view v) {
  string psd = et_psd.gettext().tostring();
  if(!textutils.isempty(psd)){
   if(psd.equals("123")){
   //解锁,进入应用,告知看门口不要再去监听以及解锁的应用,发送广播
   intent intent = new intent("android.intent.action.skip");
   intent.putextra("packagename",packagename);
   sendbroadcast(intent);
   
   finish();
   }else{
   toastutil.show(getapplicationcontext(), "密码错误");
   }
  }else{
   toastutil.show(getapplicationcontext(), "请输入密码");
  }
  }
 });
 }

 private void initui() {
 tv_app_name = (textview) findviewbyid(r.id.tv_app_name);
 iv_app_icon = (imageview) findviewbyid(r.id.iv_app_icon);
 
 et_psd = (edittext) findviewbyid(r.id.et_psd);
 bt_submit = (button) findviewbyid(r.id.bt_submit);
 }
 
 @override
 public void onbackpressed() {
 //通过隐式意图,跳转到桌面
 intent intent = new intent(intent.action_main);
 intent.addcategory(intent.category_home);
 startactivity(intent);
 super.onbackpressed();
 }
}

Android程序锁的实现以及逻辑

5.隐藏最近打开的activity

<activity
  android:excludefromrecents="true"
  android:name="com.itheima.mobilesafe.enterpwdactivity"
  android:launchmode="singleinstance" />

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。