Android 应用锁/程序锁(APPLock)的实现 http://shigongbo.blog.163.com/blog/static/976090201452572535715

转自:http://shigongbo.blog.163.com/blog/static/976090201452572535715


今天看到某Android安全软件有一个安全锁的功能,使用的时候,点击返回竟然是无效的,必须要用户输入密码!这用户体验也太差了!在网上查了一下,发现许多人都是在Activity中显示解锁画面,并屏蔽返回键。我感觉这样用户体验很差,于是就想自己实现一个。现在把主要思路和代码分享一下。

其实这个程序核心代码很少,不超过一百行就搞定。不过其中牵扯到的Android知识点很多,现在听我从头道来。
我们先来解释一下APPLock的原理。
用户启动APPLock,此时会列出所有的应用程序,选择要Lock的应用,将此应用的信息(包名)保存到数据库或文件。
并启动一个Service,我们称其为LockService,在后台一直监听,查看要Lock的应用是否被启动。
当用户启动了要Lock的应用,LockService就会察觉到,此时显示密码界面,让用户输入密码,密码正确后,密码界面消失。
如果密码界面正在显示的时候,用户点击返回,会怎么样?那肯定是密码界面消失,要启动的应用显示出来,这就不能达到应用锁的效果,所以开发者选择了在密码界面屏蔽返回键的方式。体验太差!

首先,要解决的就是怎么避免使用Activity显示解锁画面并屏蔽返回键这种不好的用户体验。
既要显示画面,又要不屏蔽返回键,怎么实现呢?
Service!对,就是在Service中显示画面。使用WindowManager加载layout的方式,让解锁画面显示在最前端。

View mLockView;
TextView mTextView;
WindowManager mWindowManager = null;

mContext = getApplicationContext();

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_FULLSCREEN |
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.RGBA_8888);
        params.gravity = (Gravity.CENTER);

        mLockView= layoutInflater.inflate(R.layout.lock_app_service, null);
        mTextView = (TextView) mLockView.findViewById(R.id.service_input_pwd);

        if (mWindowManager == null) {
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        }

        if (mWindowManager != null && mLockView!= null) {
            mWindowManager.addView(mLockView, params);
        }

把这段加到LockService中,它会显示一个覆盖屏幕的画面,也就是你xml定义的文件lock_app_service。
要使用这个功能,你还要在Manifest中添加权限

<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />


这样这个画面运行的时候就会在最前端覆盖整个屏幕了。
正式因为这是用WindowManager在最前端画出的,所以当前运行的Activity并不受影响,还是在正常运行,并不会改变生命周期,你可以在onPause中打印Log来印证,你会发现onPause并不会调用。

现在再看看怎么检测要Lock的应用开始启动了。Android中启动一个Activity的时候并没有对应的广播事件。启动一个Activity,首先是发送Intent,ActivityManagerService(AMS)会处理这个Intent。首先AMS会检测这个要启动的Activity是否存在,然后判断判断启动者是否有权限启动被启动的Activity(根据 PID和UID ),然后把被启动的Activity压入栈中。
我们就是根据这一特点,来判断刚刚启动的Activity是否为被Lock的。

ActivityManager mActivityManager;

mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);

ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity; String packageName = topActivity.getPackageName(); String className = topActivity.getClassName(); Log.v("LockService", "packageName == " + packageName); Log.v("LockService", "className == " + className);

从Log信息可以发现,此时出现的肯定是当前正在运行的应用的包名和Activity名字。
要运行这个功能,需要添加权限

<uses-permission android:name="android.permission.GET_TASKS"/>

OK,核心功能就只有这么几行,是不是不超过一百行!

剩下的工作就是界面配置和Service启动方面的了。我在这里只说一下思路。
1. 启动LockActivity。
这是一个含有list的界面,外加一个Lock开关按钮。当开关On状态,启动LockService。Off状态关闭LockService。
list中列出所有的APP应用。获取已经安装应用,代码如下

        List<PackageInfo> packages = getPackageManager().getInstalledPackages(0);         for(int i=0;i<packages.size();i++) {             PackageInfo packageInfo = packages.get(i);             Log.v("LockActivity", "packageInfo.packageName == " + packageInfo.packageName);             Log.v("LockActivity", "packageInfo.versionName == " + packageInfo.versionName);             Log.v("LockActivity", "packageInfo.versionCode == " + packageInfo.versionCode);         }

当用户点击list中的Item时候,将该应用的信息保存到数据库或者文件中。
2. LockService运行后,在其中写一个线程,不停地循环判断Activity栈顶是不是要Lock的Activity。
是,则显示密码界面,并保存当前状态。否则continue。
当用户输入了正确的密码,这则消失掉界面,代码为
mWindowManager.removeView(mLockView);
这样就显示了真正的Activity了。
当用户点击了返回,由于我们的LockService中的WindowManager并没有改变实际的启动Activity的生命周期,所以返回键还是作用在实际Activity上了,所以实际Activity消失,此时根据后台的循环判断,最上次的Activity栈已经不是要被Lock的,根据刚才保存的状态,同样将密码界面消失掉。

OK。大功告成。整个应用程序安全管家就完成了。

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Android 程序锁示例,其中使用了 SharedPreferences 存储密码信息: ```java public class AppLockService extends Service { private List<String> lockedApps; private String currentApp; private String password; @Override public void onCreate() { super.onCreate(); lockedApps = new ArrayList<>(); // 从 SharedPreferences 中获取需要定的应用程序列表和密码信息 SharedPreferences prefs = getSharedPreferences("applock", MODE_PRIVATE); Set<String> lockedAppsSet = prefs.getStringSet("locked_apps", null); if (lockedAppsSet != null) { lockedApps.addAll(lockedAppsSet); } password = prefs.getString("password", ""); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 监控当前正在运行的应用程序 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); currentApp = am.getRunningTasks(1).get(0).topActivity.getPackageName(); if (lockedApps.contains(currentApp)) { // 当前应用程序需要定,启动密码验证界面 Intent lockIntent = new Intent(this, LockActivity.class); lockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(lockIntent); } return START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } public void setPassword(String password) { // 设置密码,并将密码信息保存到 SharedPreferences 中 this.password = password; SharedPreferences.Editor editor = getSharedPreferences("applock", MODE_PRIVATE).edit(); editor.putString("password", password); editor.apply(); } public void addLockedApp(String packageName) { // 添加需要定的应用程序,并将应用程序列表保存到 SharedPreferences 中 lockedApps.add(packageName); SharedPreferences.Editor editor = getSharedPreferences("applock", MODE_PRIVATE).edit(); editor.putStringSet("locked_apps", new HashSet<>(lockedApps)); editor.apply(); } public void removeLockedApp(String packageName) { // 移除需要定的应用程序,并将应用程序列表保存到 SharedPreferences 中 lockedApps.remove(packageName); SharedPreferences.Editor editor = getSharedPreferences("applock", MODE_PRIVATE).edit(); editor.putStringSet("locked_apps", new HashSet<>(lockedApps)); editor.apply(); } public boolean checkPassword(String inputPassword) { // 检查用户输入的密码是否正确 return password.equals(inputPassword); } } ``` 在上述示例中,`AppLockService` 是一个服务,用于监控当前正在运行的应用程序,并启动密码验证界面。密码信息和需要定的应用程序列表存储在 SharedPreferences 中,可以通过 `setPassword()`、`addLockedApp()` 和 `removeLockedApp()` 方法进行设置和修改。`checkPassword()` 方法用于检查用户输入的密码是否正确。 以下是一个简单的密码验证界面示例: ```java public class LockActivity extends AppCompatActivity { private EditText passwordEditText; private AppLockService appLockService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lock); passwordEditText = findViewById(R.id.password_edit_text); appLockService = ((MyApplication) getApplication()).getAppLockService(); } @Override protected void onResume() { super.onResume(); getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); } @Override public void onBackPressed() { // 拦截返回键,不允许用户退出密码验证界面 } public void onOkButtonClick(View view) { String password = passwordEditText.getText().toString(); if (appLockService.checkPassword(password)) { // 密码正确,允许用户访问应用程序 finish(); } else { // 密码错误,提示用户并清空密码输入框 Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show(); passwordEditText.setText(""); } } public void onForgetButtonClick(View view) { // 提供密码忘记选项,可以通过提供预设的安全问题来重置密码 } } ``` 在上述示例中,`LockActivity` 是一个 Activity,用于显示密码验证界面。在 `onResume()` 方法中,设置了一些 Window 标志,以便在屏的情况下仍然可以显示界面。`onOkButtonClick()` 方法用于检查用户输入的密码是否正确,如果正确,则关闭密码验证界面;否则提示用户密码错误,并清空密码输入框。`onForgetButtonClick()` 方法提供了密码忘记选项,可以通过提供预设的安全问题来重置密码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值