本篇文章主要是介绍 Android 程序锁的实现以及逻辑,它的目的是可以给程序加锁,上过锁的程序可以解锁,有兴趣的朋友可以了解一下。
Android 是一种基于 Linux 的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由 Google 公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用 "安卓" 或 "安致"。
本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个 "看门狗" 的服务定时监视顶层 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. 程序锁必须在服务中去维护
①基本思路
- 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" />
来源: http://www.phperz.com/article/17/0320/302442.html