Android---程序锁(2)业务逻辑

一.写在前面的话

终于,所有的考试都考完了,可以安安心心的敲敲代码了。上次记录程序锁只是搭建了一个界面,具体的业务逻辑还没有实现,然后昨晚看了视频之后,自己也敲了一遍代码,所以今天就抽个空记录一下。推荐黑马74期视频,确实很不错。老师们都讲的很详细。

二 总体思路和问题

思路:

1.程序锁是功能要时时刻刻对我们开启的应用进行监听,它是脱离Activity的存在,所以根据这一需求,我们可以将业务逻辑写在Service中。

2.程序锁的实现:也就是在点击加锁应用的时候,要提前弹出一个锁屏界面,也就是一个Activity,然后输入密码,如果密码正确,才进入应用。

3.有硬件方面知识的应该知道watchDog,顾名思义,看门狗。比如说在16位的单片机里面,就有这个东西存在,它存在的目的就是对某一个引脚时时刻刻进行监控。根据这一思想,可以在程序中也设定一watchDog,说白了就是一个可控制的死循环。对我们启动的程序进行时时刻刻的监控。

问题:
1.在应用启动之前,我们设置一个拦截Activity,那么久需要考虑回退栈的问题。

2.在看门狗程序里,过滤已经解锁的应用,通过发送广播来实现。

3.当我们开启了服务之后,再去添加上锁的程序,不能生效。这时候需要用到 内容观察者,观察数据库变化,一旦数据库变化,则放置包名的集合需要重新获取数据

4.挂起拦截界面的时候,不需要手机卫士的图标

5.回退按钮的处理,在拦截界面点击回退按钮时,直接回退到桌面。

这些问题都是机上敲了代码之后,才总计出来的

三.代码实现

1.watchDog代码

private void watch() {
        //1.在子线程中开启可控的死循环
        new Thread(new Runnable() {
            @Override
            public void run() {
                mPackageNameList = mDao.findAll();

                while (mIsWatch) {
                    //2检测现在正在开启的应用,任务栈
                    //3获取activity给管理者对象
                    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
                    //4.获取正在运行的任务栈的方法
                    List<ActivityManager.RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1);
                    ActivityManager.RunningTaskInfo runningTaskInfo = runningTasks.get(0);
                    //5.获取栈顶的activity
                    String topPackageName = runningTaskInfo.topActivity.getPackageName();
                    //6拿此报名和已加数据库或者已加锁的集合进行比较
                    if (mPackageNameList.contains(topPackageName)){
                        //弹出拦截界面 这个拦截的Activity要在一个单独的任务栈中,这样当密码正确的时候才会跳转到相应的程序界面
                          //如果现在检测的程序包名已经解锁,则不需要弹出拦截界面了
                        if (!topPackageName.equals(mSkipPackageName)){
                            Intent intent = new Intent(getApplicationContext(), enterPsdActivity.class);
                            intent.putExtra("topPackageName",topPackageName);
                            //在服务中开启Activity,需要设置图下的Flags
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }

                    }

                    //即使死循环再子线程中,也会消耗大量的内存,所以需要睡一下
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        }).start();
    }

2.拦截界面处,处理返回键,以及记录已经解锁的报名,传送回watchDog,免有一次的拦截;

public class enterPsdActivity extends Activity {

    private String mTopPackageName;
    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);
        //拿到Intent中所携带的信息
        mTopPackageName = getIntent().getStringExtra("topPackageName");
        setContentView(R.layout.activity_enter_psd);
        initUI();
        initData();
    }

    private void initData() {
        //通过传递过来的包名获取拦截应用的图标以及名称
        PackageManager packageManager = getPackageManager();
        try {
            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(mTopPackageName, 0);

            //设置图标
            iv_app_icon.setBackgroundDrawable(applicationInfo.loadIcon(packageManager));
            //设置名称
            tv_app_name.setText(applicationInfo.loadLabel(packageManager).toString());

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        //注册密码确定按钮的监听事件
        bt_submit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String psd = et_psd.getText().toString();
                if (!TextUtils.isEmpty(psd)){
                    if (psd.equals("123")){
                    //解锁进入应用
                        //关闭拦截的应用 告知watchDog不要再去监听已经解锁的应用,发送广播
                        Intent intent = new Intent("android.intent.action.SKIP");
                        intent.putExtra("topPackageName", mTopPackageName);
                        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();

    }
}

3.在广播接收者中,接收到从拦截界面传回的已经解锁了的应用

 private class innerReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取发送广播过程中传递过来的包名,跳过这个包名的检测
            mSkipPackageName = intent.getStringExtra("topPackageName");

        }
    }

3.内容观察者,用于当服务开启后,又添加了一个加锁的应用,则立即更新数据库

private class myContentObserver extends ContentObserver {
        /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. */
        public myContentObserver(Handler handler) {
            super(handler);
        }

        @Override //一旦数据库发生改变的时候回调的方法 也就是执行了 数据库的 insert() delete()方法
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    mPackageNameList = mDao.findAll();
                }
            }).start();
        }
    }

5.当服务关闭时,要释放所用到的资源。

   @Override
    public void onDestroy() {
        //注销广播
        if (mInnerReceiver!=null) {
            unregisterReceiver(mInnerReceiver);
        }
        //停下看门狗
        mIsWatch=false;

        //注销内容观察者
        if (mMyContentObserver!=null) {
            getContentResolver().unregisterContentObserver(mMyContentObserver);
        }
        super.onDestroy();
    }

四.后记

零零散散的,我自己将就着看。这学期的期末考试终于结束了。能够安心的坐在图书馆敲敲代码,看看书了。接下来还有两周的生产实习和短学期实践。院里除了会做这样的事情还会做什么,找一个外地的培训机构来学校给我们上课,实际上就是变相招生。短学期实践的负责老师也根本就不管事,第一天开个会,然后就没有任何消息了。坑的只是我们这些学生,出去面试实习单位,对方一听说7月24之后才能报道,就直接pass,这就是他妈学院做的一点好事。如果真的可以学到什么,我相信大多数学生不会反抗,但事实上,就是挂着羊头卖狗肉,还美其名日:贯彻发展国家什么xxx人才培养计划。!! 简直就是扯淡。

Android—程序锁(1)展示页面的搭建

你可能感兴趣的:(Android---程序锁(2)业务逻辑)