Android程序锁的实现以及逻辑

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

效果如下:

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.程序锁必须在服务中去维护

①基本思路

  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();
 }
}

5.隐藏最近打开的activity

<activity
  android:excludeFromRecents="true"
  android:name="com.itheima.mobilesafe.EnterPwdActivity"
  android:launchMode="singleInstance" />

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

(0)

相关推荐

  • Android 自定义手势--输入法手势技术

    进行软件开发时,通常我们都喜欢使用较新版本的工具,但这里我为什么使用低版本的SDK来开发Android游戏呢?这里介绍下原因: 1.Android SDK 属于向下兼容!那么低版本可以运行的,高版本基本上更是没问题!(当然每次SDK的更新也会带来新功能,或者修改了一些原来的BUG等等,那么其实对于游戏开发来说,如果你的游戏中不需要更高的SDK版本的支持情况下,完全不必去追求最新的SDK!) 2.使用低版本进行游戏开发这样能兼顾更多的机型,获取更多的用户! 3.大家都知道Android SDK 每

  • Android开发之自定义View(视图)用法详解

    本文实例讲述了Android开发之自定义View(视图)用法.分享给大家供大家参考,具体如下: View类是Android的一个超类,这个类几乎包含了所有的屏幕类型.每一个View都有一个用于绘图的画布,这个画布可以进行任意扩展.在游戏开发中往往需要自定义视图(View),这个画布的功能更能满足我们在游戏开发中的需要.在Android中,任何一个View类都只需重写onDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本形式等. 为了实现自定义View,需要创建

  • Android实现显示电量的控件代码

    下面介绍了Android实现显示电量的控件代码,具体代码如下: 1.目录结构,本人是使用安卓死丢丢. 2.运行界面,输入框中输入数值,点击刷新,会再电池中显示出相应的电量 3.绘制自定义电池控件,首先,新建一个类BatteryState继承View private Context mContext; private float width; private float height; private Paint mPaint; private float powerQuantity=0.5f;/

  • Android自定义滑动接听电话控件组实例

    本文根据组件开发思想,首先介绍android自定义控件,然后将自定义的控件封装为jar包.最为实现滑动接听电话控件组. 一.目录结构 二.运行效果 三.代码实现 首先,自定义一个类IncomingPhone继承RelativeLayout public IncomingPhone(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; TextView textView = new Tex

  • Android滑动动态分页实现方法

    本文实例讲述了Android滑动动态分页实现方法.分享给大家供大家参考,具体如下: 实现 Android.widget.AbsListView.OnScrollListener 主要代码: private int lastItemIndex; @Override public void onScroll(AbsListView v, int firstVisibleItem,int visibleItemCount, int totalItemCount) { lastItemIndex = f

  • Android实现底部弹出PopupWindow背景逐渐变暗效果

    在Android开发中,经常需要通过点击某个按钮弹出对话框或者选择框,通过Dialog或者PopupMenu.PopupWindow都能实现. 这里主要介绍后两者:PopupMenu.PopupWindow的实现. 先看两个效果图上边PopupMenu,下边PopupWindow: PopupMenu PopupWindow 一.PopupMenu实现: PopupMenu实现起来比较简单,主要用来实现根据按钮附近弹出的对话框. 首先定义一个menu文件\res\menu\headmenu.xm

  • android中对文件加密解密的实现

    现在项目里面有一个需求,本项目里面下载的视频和文档都不允许通过其他的播放器播放,在培训机构里面这样的需求很多.防止有人交一份钱,把所有的课件就拷给了别人.这样的事情培训机构肯定是不愿意的.现在我项目里面也出了这么个需求.下面介绍一下我的实现. 文件加解密的流程及原理 1.加密方法:存储文件时,从输入流中截取文件的字节数组,对字节数组进行加密,至于加密的方式和算法就可以视需求而定了,然后把加密后的字节数组写入到文件中,最后生成加密后的文件: 2.解密方法:同加密方法一样,只不过是对字节数据进行解密

  • android项目手机卫士来电显示号码归属地

    昨日实现了360手机卫士的来电显示归属地的功能,具体的功能就是当来电的时候,显示当前号码的归属地,学习之后发现操作 非常的简单,具体实现代码如下: AddressService.java package com.qingguow.mobilesafe.service; import com.qingguow.mobilesafe.utils.NumberQueryAddressUtil; import android.app.Service; import android.content.Int

  • Android实现屏幕锁定源码详解

    最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

  • Android程序锁的实现以及逻辑

    本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个"看门狗"的服务定时监视顶层activity,如果activity对应的包名是之前上锁的应用程序的,则弹出一个页面要求输入解锁密码. 效果如下: 1.基本思路 ①.创建已加锁应用的数据库(字段:_id,packagename),如果应用已加锁,将加锁应用的包名维护到数据库中 ②.已加锁+未加锁 == 手机中所有应用(AppInfoProvider) 2.已加锁和未加锁的数据适配器 class MyAdapter ex

  • Android开发之开门狗在程序锁中的应用实例

    本文实例讲述了Android开发之开门狗在程序锁中的应用方法.分享给大家供大家参考,具体如下: protected static final String TAG = "WatchDogService"; private AppLockDao dao; private List<String> lockApps; private ActivityManager am; private Intent lockappintent; @Override public IBinde

  • Android程序开发仿新版QQ锁屏下弹窗功能

    新版的qq,可以在锁屏下弹窗显示qq消息,正好目前在做的项目也需要这一功能.经过各种试验和资料查找,终于实现,过程不难,但是却有一些地方需要注意. 下面是实现过程. 1.使用Activity,而不是View QQ的弹窗一开始我以为是悬浮View,用WindowManager去添加,但是无论如何就是不显示,后来在朋友提示下换成Activity来实现,在锁屏状态下就能弹窗了. 2.Activity的设置 Activity需要进行以下设置,才可以在锁屏状态下弹窗. 首先是onCreate方法,需要添加

  • 推荐几本Android程序员必读书籍

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发,从语言上来看,Android应用开发基于的是Java语言,但是这都是我们要自己下功夫去学习的事情. 不管你是Android菜鸟还是Android大神,一定能够找到一本适合自己阅读的书籍,抓紧来看看吧! 高尔基曾说"书是人类进步的阶梯",今天小编就为大家整理了一些优秀Android程序员都会阅读的书籍,帮助大家成为一个优秀的程序员 第1本书

  • Android屏幕锁屏弹窗的正确姿势DEMO详解

    在上篇文章给大家介绍了Android程序开发仿新版QQ锁屏下弹窗功能.今天通过本文给大家分享android锁屏弹窗的正确姿势. 最近在做一个关于屏幕锁屏悬浮窗的功能,于是在网上搜索了很多安卓屏幕锁屏的相关资料,鉴于网上的资料比较零碎,所以我在这里进行整理总结.本文将从以下两点对屏幕锁屏进行解析: 1. 如何监听系统屏幕锁屏 2. 如何在锁屏界面弹出悬浮窗 如何监听系统屏幕锁屏 经过总结,监听系统的锁屏可以通过以下两种方式: 1) 代码直接判定 2) 接收广播 1) 代码直接判定 代码判断方式,也

  • 深入理解Android M 锁屏密码存储方式

    Android M 之前锁屏密码的存储 在 Android M 之前,锁屏密码的存储格式很简单,其使用了 64 位随机数作为 salt 值,此 salt 值被存储在 SQLite 数据库 /data/system/locksettings.db 中.密码在存储的时候,会将输入的密码加上此随机数组成新的字符串.然后对新的字符串分别进行 SHA-1 和 MD5 加密,将加密后的密文通过 MD5 + SHA-1 的方式进行字符串拼接,组成新的密文存储在 /data/system/password.ke

  • Python实现过滤单个Android程序日志脚本分享

    在Android软件开发中,增加日志的作用很重要,便于我们了解程序的执行情况和数据.Eclipse开发工具会提供了可视化的工具,但是还是感觉终端效率会高一些,于是自己写了一个python的脚本来通过包名来过滤某一程序的日志. 原理 通过包名得到对应的进程ID(可能多个),然后使用adb logcat 过滤进程ID即可得到对应程序的日志. 源码 复制代码 代码如下: #!/usr/bin/env python #coding:utf-8 #This script is aimed to grep

  • Android程序开发之自定义设置TabHost,TabWidget样式

    先看效果: 京东商城底部菜单栏 新浪微博底部菜单栏 本次学习效果图: 第一,主布局文件(启动页main.xml,位于res/layout目录下)代码 <?xml version="." encoding="utf-"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_paren

  • Android程序开发之防止密码输入错误 密码明文显示功能

    在使用App的时候,首次登录都需要用户输入密码的,有些朋友为了安全起见密码设置的比较长,导致很多次密码都输入错误,严重影响了用户体验效果.这一点移动开发者做好了准备工作,因为手机的私密性比较强,在输入密码的时候,可以显示输入,增强准确性,提升用户体验度.这当然要付出代价的,需要额外的代码编写功能.下面通过本文给大家介绍如何编写密码明文显示的功能,仅供参考. 本文源码的GitHub下载地址 要点 (1) 重写EditText, 添加提示密码显示和隐藏的图片. (2) 判断点击位置, 切换EditT

  • Android程序开发之ListView 与PopupWindow实现从左向右滑动删除功能

    文章实现的功能是:在ListView的Item上从右向左滑时,出现删除按钮,点击删除按钮把Item删除. 看过文章后,感觉没有必要把dispatchTouchEvent()和onTouchEvent()两个方法都重写,只要重写onTouchEvent就好了.于是对代码作了一些调整: public class MyListView extends ListView { private static final String TAG = "MyListView"; private int

随机推荐