Android程序锁的实现以及逻辑

作者:ganchuanpu 时间:2022-09-29 19:50:57 

本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个“看门狗”的服务定时监视顶层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" />
标签:android,程序锁
0
投稿

猜你喜欢

  • Java解析XML格式数据的方法详解

    2022-03-25 09:28:25
  • Android studio 运行main 函数的方法

    2023-09-14 15:57:38
  • Android实现微信朋友圈发本地视频功能

    2021-06-18 07:56:03
  • Android之ArcSlidingHelper制作圆弧滑动效果

    2021-07-23 03:10:24
  • C#键值对容器的介绍

    2023-04-14 12:26:56
  • Android Studio多渠道打包的配置方法

    2023-06-15 23:19:48
  • 冒泡排序算法原理及JAVA实现代码

    2022-08-13 10:30:40
  • Android Studio配置Kotlin开发环境详细步骤

    2022-10-09 21:29:35
  • C#调用和实现WebService,纯手工打造!

    2023-12-12 14:58:30
  • Android 解决TextView排版参差不齐的问题

    2022-06-25 06:43:30
  • Mybatis批量插入Oracle数据的方法实例

    2021-05-24 23:32:31
  • Java源码深度分析String与StringBuffer及StringBuilder详解

    2022-04-01 09:55:50
  • 读取xml文件中的配置参数实例

    2023-10-16 16:20:41
  • Android提高Service优先级的方法分析

    2023-01-09 09:05:51
  • Spring Boot下的Job定时任务

    2021-10-23 05:16:14
  • c#使用Unity粒子实现炮塔发射系统

    2023-11-04 19:05:19
  • Java数据结构之AC自动机算法的实现

    2023-08-31 07:23:57
  • Java验证码功能的实现方法

    2023-07-05 21:28:21
  • Android自定义相机Camera实现手动对焦的方法示例

    2022-08-23 14:45:11
  • Maven中利用assembly插件打包jar包

    2022-07-09 04:32:14
  • asp之家 软件编程 m.aspxhome.com