上一次,我们已经把那个锁的逻辑写好了,已经能够把要锁定的应用放到数据库里面了,那么今天我们就要完成真正的锁定了,要完成锁定,我们之前也说过了,就是通过监听
Android运行的任务栈,然后看看,当时是不是在运行我们已经在锁定的应用,如果真的是运行已经锁定的应用,那么就弹出输入密码的界面。因为我们是通过一个Service来控制是否打这个程序锁定的服务的,所有我们就要在设置中心里面进行一个设置的界面。
好,根据上面说我,我们就先把输入密码的界面先做出来
这个界面非常的简单啦,就是几个控件。
lock.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="40dip" android:background="@drawable/title_background" android:gravity="center_vertical|center_horizontal" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/lock" android:textColor="@android:color/white" android:textSize="22sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dip" android:gravity="center_vertical|center_horizontal" android:orientation="horizontal"> <ImageView android:id="@+id/iv_lock_app_icon" android:layout_width="48dip" android:layout_height="48dip" android:src="@drawable/app" android:contentDescription="@string/hello_world"/> <TextView android:id="@+id/tv_lock_app_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="15dip" android:textColor="#ffbc04e5" android:text="@string/hello_world"/> </LinearLayout> <EditText android:id="@+id/et_lock_pwd" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dip" android:hint="@string/inputPassword" android:inputType="textPassword"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dip" android:text="@string/protectedYes" android:onClick="confirm"/></LinearLayout>
com.xiaobin.security.ui.LockActivity
package com.xiaobin.security.ui;import android.app.Activity;import android.content.Context;import android.content.pm.ApplicationInfo;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.text.TextUtils;import android.view.KeyEvent;import android.view.View;import android.view.Window;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import com.xiaobin.security.R;import com.xiaobin.security.utils.MD5Encoder;public class LockActivity extends Activity{ private ImageView iv_app_icon; private TextView tv_app_name; private EditText et_app_pwd; private String password; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.lock); iv_app_icon = (ImageView) findViewById(R.id.iv_lock_app_icon); tv_app_name = (TextView) findViewById(R.id.tv_lock_app_name); et_app_pwd = (EditText) findViewById(R.id.et_lock_pwd); //拿到真实的密码 //这里我们为了方便,就使用了手机防盗里面的那个密码,大家可以自己做成可以让用户设置的功能 password = getSharedPreferences("config", Context.MODE_PRIVATE).getString("password", ""); try { String packageName = getIntent().getStringExtra("packageName"); //通过包名拿到applicationInfo ApplicationInfo appInfo = getPackageManager().getPackageInfo(packageName, 0).applicationInfo; //应用图标 Drawable app_icon = appInfo.loadIcon(getPackageManager()); //应用的名字 String app_name = appInfo.loadLabel(getPackageManager()).toString(); iv_app_icon.setImageDrawable(app_icon); tv_app_name.setText(app_name); } catch (Exception e) { e.printStackTrace(); } } //按钮的点击事件 public void confirm(View v) { String input = et_app_pwd.getText().toString().trim(); if(TextUtils.isEmpty(password)) { Toast.makeText(this, "您的密码还没有设置,请进入手机防盗进行设定", Toast.LENGTH_SHORT).show(); } else if(TextUtils.isEmpty(input)) { Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show(); } else if(password.equals(MD5Encoder.encode(input))) { finish(); } else { Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show(); } } //不让用户按后退键 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //屏蔽后退键 if(KeyEvent.KEYCODE_BACK == event.getKeyCode()) { return true;//阻止事件继续向下分发 } return super.onKeyDown(keyCode, event); }}
上面的那个逻辑也很简单了,也就是拿到用户之前在手机防盗里面设置的密码,然后进行判断,当然,各位也可以自己做一下,那个密码设置的功能。
那么接下来,我们就要讲一下那个锁定应用的核心了,也就是监听任务栈了,其实这个监听也很简单,就是我们开启一条线程,每隔一段时间就扫描一个Android的任务栈,看看是不是有我们已经锁定的应用要启动,如果有,那就启动我们的密码输入界面,如果没有,那就睡眠一段时间
通过任务栈拿到要启动的Activity也很简单的
//得到当前运行的任务栈,参数就是得到多少个任务栈,1就是只拿一个任务栈 //1对应的也就是正在运行的任务栈啦 List<RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(1); //拿到当前运行的任务栈 RunningTaskInfo runningTaskInfo = runningTaskInfos.get(0); //拿到要运行的Activity的包名 String packageName = runningTaskInfo.topActivity.getPackageName();
因为我们这些是要在后台长时间运行的,所以我们就要放到Service里面
com.xiaobin.security.service.WatchDogService
package com.xiaobin.security.service;import java.util.List;import android.app.ActivityManager;import android.app.ActivityManager.RunningTaskInfo;import android.app.Service;import android.content.Intent;import android.os.IBinder;import com.xiaobin.security.dao.AppLockDao;import com.xiaobin.security.ui.LockActivity;public class WatchDogService extends Service{ private AppLockDao dao; private List<String> apps; private ActivityManager activityManager; private Intent intent; private boolean flag = true; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); dao = new AppLockDao(this); apps = dao.getAllPackageName(); activityManager = (ActivityManager) getSystemService(Service.ACTIVITY_SERVICE); intent = new Intent(this, LockActivity.class); // 服务里面是没有任务栈的,所以要指定一个新的任务栈,不然是无法在服务里面启动activity的 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); new Thread() { public void run() { while (flag) { try { // 得到当前运行的任务栈,参数就是得到多少个任务栈,1就是只拿一个任务栈 // 1对应的也就是正在运行的任务栈啦 List<RunningTaskInfo> runningTaskInfos = activityManager .getRunningTasks(1); // 拿到当前运行的任务栈 RunningTaskInfo runningTaskInfo = runningTaskInfos .get(0); // 拿到要运行的Activity的包名 String packageName = runningTaskInfo.topActivity .getPackageName(); if (apps.contains(packageName)) { intent.putExtra("packageName", packageName); startActivity(intent); } else { } sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } @Override public void onDestroy() { super.onDestroy(); flag = false; }}
好啦,写完这个之后,我们就要去做一个开启这个服务的开关了,我们这次写在设置中心里面,其实我们设置中心的界面也和高级工具里的界面是差不多的了
setting.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="40dip" android:background="@drawable/title_background" android:gravity="center_vertical|center_horizontal" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/setting" android:textColor="@android:color/white" android:textSize="22sp" /> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip"> <LinearLayout android:layout_width="280dip" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:orientation="vertical"> <TextView android:layout_width="280dip" android:layout_height="wrap_content" android:textSize="20sp" android:text="@string/lock_service"/> <TextView android:id="@+id/tv_lock_tips" android:layout_width="280dip" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="#ffff0000" android:text="@string/lock_tips"/> </LinearLayout> <CheckBox android:id="@+id/cb_lock_state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true"/> </RelativeLayout> </LinearLayout>
com.xiaobin.security.ui.SettingActivity
package com.xiaobin.security.ui;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.view.Window;import android.widget.CheckBox;import android.widget.CompoundButton;import android.widget.CompoundButton.OnCheckedChangeListener;import android.widget.TextView;import com.xiaobin.security.R;import com.xiaobin.security.service.WatchDogService;public class SettingActivity extends Activity{ private TextView tv_lock_tips; private CheckBox cb_lock_state; private Intent appLockIntent; private SharedPreferences sp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.setting); appLockIntent = new Intent(this, WatchDogService.class); tv_lock_tips = (TextView) findViewById(R.id.tv_lock_tips); cb_lock_state = (CheckBox) findViewById(R.id.cb_lock_state); sp = getSharedPreferences("config", Context.MODE_PRIVATE); boolean isAppLockStart = sp.getBoolean("appLock", false); if(isAppLockStart) { tv_lock_tips.setText("服务已经开启"); cb_lock_state.setChecked(false); } else { tv_lock_tips.setText("服务没有开启"); cb_lock_state.setChecked(true); } cb_lock_state.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked) { startService(appLockIntent); tv_lock_tips.setText("服务已经开启"); } else { stopService(appLockIntent); tv_lock_tips.setText("服务没有开启"); } } }); }}
大家也可以看到,现在我们的设置中心还是非常的简单的,就只是开启和关闭服务而已,但我们会在后面慢慢完善的啦
好啦,写到这里,我们就差不多要完成这个程序锁的功能的了,但现在还要做一个操作,那就是在AndroidMainfest文件里面拿到权限才行
<uses-permission android:name="android.permission.GET_TASKS"/>
好啦,现在我们就可以测试一下我们的程序锁的啦,一测试,我们会发现,这个程序锁还是有很多bug来的,比如说,我们一输入密码后,进入到了相应的应用了,但它马上又会变回到输入密码的界面的了,还有一些其他问题的,修复这些问题都比较麻烦,所以我们明天再来修复它。
今天就先到这里了
最后,和大家说一下
为了方便大家的交流,我创建了一个群,这样子大家有什么疑问也可以在群上交流
群号是298440981
今天源码下载