Android程序锁的实现以及逻辑

 更新时间:2016年10月22日 14:37:41   作者:ganchuanpu  
本篇文章主要是介绍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" />

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

相关文章

  • android仿知乎标题栏随ScrollView滚动变色

    android仿知乎标题栏随ScrollView滚动变色

    这篇文章主要为大家详细介绍了android仿知乎标题栏随ScrollView滚动变色,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • Android编程实现应用强制安装到手机内存的方法

    Android编程实现应用强制安装到手机内存的方法

    这篇文章主要介绍了Android编程实现应用强制安装到手机内存的方法,涉及Android中属性设置的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • Android手册之Toolbar搜索联动及监听小技巧

    Android手册之Toolbar搜索联动及监听小技巧

    这篇文章主要为大家介绍了Android手册之Toolbar搜索联动及监听小技巧示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Android自定义view实现滑动解锁效果

    Android自定义view实现滑动解锁效果

    这篇文章主要为大家详细介绍了Android自定义view实现滑动解锁效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • Android 单双击实现的方法步骤

    Android 单双击实现的方法步骤

    这篇文章主要介绍了Android 单双击实现的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Android编程设计模式之命令模式详解

    Android编程设计模式之命令模式详解

    这篇文章主要介绍了Android编程设计模式之命令模式,详细分析了命令模式的概念、功能、使用场景、用法及相关操作注意事项,需要的朋友可以参考下
    2017-12-12
  • Android实现文字消除效果

    Android实现文字消除效果

    由于项目和语音识别相关,有时候人在不经意间交流的无效音频会被识别出来,并展示于界面,为了美观,客户要求我们将这些无效的识别文本用一个从右到左的动画给清除,于是便有了下述的技术实现。感兴趣的朋友可以参考下
    2021-06-06
  • Android RecyclerView 滚动到中间位置的方法示例

    Android RecyclerView 滚动到中间位置的方法示例

    这篇文章主要介绍了Android RecyclerView 滚动到中间位置的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Android安卓中循环录像并检测内存卡容量

    Android安卓中循环录像并检测内存卡容量

    这篇文章主要介绍了Android安卓中循环录像并检测内存卡容量,当内存卡空间已满时,本文还实现自动删除视频列表里面的第一个文件,需要的朋友可以参考下
    2015-06-06
  • Android基础之使用Fragment控制切换多个页面

    Android基础之使用Fragment控制切换多个页面

    Android官方已经提供了Fragment的各种使用的Demo例子,在我们SDK下面的API Demo里面就包含了Fragment的各种使用例子,需要看Demo的朋友,直接看API Demo那个程序就可以了,不用到处去找。里面分开不同功能,实现了不同的类
    2013-07-07

最新评论