之前在做卫士项目的时候,做程序锁的时候,遇到一个问题。
以往做程序锁的时候,我们都会选择开启一个后台服务,然后在服务中不断获取当前运行的栈信息,提取栈顶的packageName来判定当时运行的程序是否为锁程序。
但这种方式在API21之后不能用了,因为getRunningTasks这个方法在API21已经被弃用了。在Android 5.1的系统也不支持此种方式。
- 但别着急,在5.1版本后我们还有另一种方式来实现程序锁的功能。那就是Android的Accessibility功能。
- 官方文档是这样介绍的,渣英语翻译:对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。
今天我们使用这个功能实现程序锁功能。
1、第一步,在Android Manifest.xml文件中注册:
<service
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:name=".service.LockService"
android:label="程序锁" >
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
其中label就是此功能在辅助功能里的名字,
如上,而android:name:指的就是代码中服务了。
2.完成xml文件夹的accessibility_service_config:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
/>
<!--
android:description : 描述信息
监听的事件类型
发生这个事件之后,如何反馈 -->
其中的description指的就是此功能的描述,这个自己添加就可以了。
3、服务中的代码完成程序锁的功能,这里的LockService需要继承AccessibilityService
- 此类最少需要实现两个方法:
一. onAccessibilityEvent(AccessibilityEvent event):
响应AccessibilityEvent的事件,在用户操作的过程中,系统不断的发送sendAccessibiltyEvent(AccessibilityEvent event);然后通过onAccessibilityEvent()可以捕捉到该事件,然后分析。
二.public void onInterrupt():打断获取事件的过程,本例中暂不适用。
package com.jadyn.mobilesafe.service;
import android.accessibilityservice.AccessibilityService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import com.jadyn.mobilesafe.activity.DogCheckActivity;
import com.jadyn.mobilesafe.dao.AppLockDao;
import java.util.ArrayList;
import java.util.List;
/**
* Created by JadynAi on 2016/3/24.
*/
public class Dog2Service extends AccessibilityService {
protected static final String TAG = "Dog2Service";
private List<String> mLockInfos;
//这个集合是用于存储验证过的应用
private List<String> mVerifyList = new ArrayList<>();
private VerifyReceiver mVerifyReceiver ;
LockScreenReceiver mLockScreenReceiver;
AppLockDao mDao ;
@Override
public void onCreate() {
super.onCreate();
mDao = new AppLockDao(this);
mLockInfos = mDao.query();
registerReceiver();
}
//当发生改变的时候调用的代码
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
String packageName = (String) event.getPackageName();
Log.d(TAG, "PACKAGENAME==="+packageName);
//如果目前这个包名在验证过的集合中,那么就跳过下面的代码
if(mVerifyList.contains(packageName)){
return;
}
//判断从数据库查询出来的集合中有没有这个包名存在。
if(mLockInfos.contains(packageName)){
Log.d(TAG, "加锁程序: PACKAGEnAME = "+packageName );
Intent intent = new Intent(Dog2Service.this , DogCheckActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packagename", packageName);
startActivity(intent);
}else{
Log.d(TAG, "未加锁程序: PACKAGEnAME = "+packageName );
}
}
@Override
public void onInterrupt() {
}
private void registerReceiver() {
registerVerifyReceiver();
registerLockScreenReceiver();
//接收数据库改变的通知
Uri uri = Uri.parse("safe://com.jadyn.moblilesafe.db");
getContentResolver().registerContentObserver(uri, true, new DbObserver(new Handler()));
}
private void registerLockScreenReceiver() {
mLockScreenReceiver = new LockScreenReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mLockScreenReceiver, filter);
}
private void registerVerifyReceiver() {
mVerifyReceiver = new VerifyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.jadyn.mobilesafe.verify");
registerReceiver(mVerifyReceiver, filter);
}
//接收广播
class VerifyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//得到了早前在activity那边验证过的程序包名。
String packageName = intent.getStringExtra("packagename");
mVerifyList.add(packageName);
}
}
class LockScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//重置集合
mVerifyList.clear();
}
}
class DbObserver extends ContentObserver {
public DbObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
//在执行一次查询
mLockInfos = mDao.query();
}
}
@Override
public void onDestroy() {
super.onDestroy();
//标记着,不要再执行监听了。
unregisterReceiver(mVerifyReceiver);
unregisterReceiver(mLockScreenReceiver);
}
}
此代码中我们注册了两个广播和一个内容观察者。其中VerifyReceiver广播是用来接受验证界面发来的验证通过的广播。
LockScreenReceiver广播接受锁屏广播,用来保证锁屏后,打开程序会重新验证。
DbObserver,用来观察数据库操作类的,增删方法内的修改。
以上