Android Accessibility实现程序锁功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/JadynAi/article/details/50976216

之前在做卫士项目的时候,做程序锁的时候,遇到一个问题。
以往做程序锁的时候,我们都会选择开启一个后台服务,然后在服务中不断获取当前运行的栈信息,提取栈顶的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,用来观察数据库操作类的,增删方法内的修改。

以上

猜你喜欢

转载自blog.csdn.net/JadynAi/article/details/50976216