前言

应用锁的功能可以说是很普遍了,大致就是在 startActivity 对应代码处进行拦截就行。

最开始在网上找了点资料,没有能合适直接用的,就自己搞了下,这里简单做个笔记。

Android应用锁实现

那就给大伙先来个效果图先康康

思路分析

由于我们的目标应用是系统 Settings ,这家伙的入口不唯一,一开始是想着在 Launcher3 中进行拦截就行,

最终效果不太完美,后来改到 ActivityStarter 中 startActivity()

是怎么找到这个地方的呢?因为之前改过一个 Q 版本以上不能后台拉起 Activity 的问题,当时报错的地方

就在这里,后来想了下报错不就是被拦截了么,这样我们也可以在此处定制密码进行拦截。

1、找到拦截启动位置,startActivity()

2、读取要拉起 Activity 对应包名和需要加锁 APP 包名判断

3、在加锁清单中,弹出验证界面,验证成功,继续执行 startActivity

4、无需加锁,直接放行

上代码

1、Launcher3 中可拦截的地方

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java

public boolean startActivitySafely(View v, Intent intent, ItemInfo item,@Nullable String sourceContainer) {if (TestProtocol.sDebugTracing) {android.util.Log.d(TestProtocol.NO_START_TAG,"startActivitySafely outer");}//cczheng add testcodefinal String packageName = intent.getComponent().getPackageName();android.util.Log.i("ActivityStarter111","packageName="+packageName);if ("com.android.settings".equals(packageName)) {//android.widget.Toast.makeText(this, "foo", 1000).show();//return true;}//endif (!hasBeenResumed()) {// Workaround an issue where the WM launch animation is clobbered when finishing the// recents animation into launcher. Defer launching the activity until Launcher is// next resumed.addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));UiFactory.clearSwipeSharedState(true /* finishAnimation */);return true;}boolean success = super.startActivitySafely(v, intent, item, sourceContainer);if (success && v instanceof BubbleTextView) {// This is set to the view that launched the activity that navigated the user away// from launcher. Since there is no callback for when the activity has finished// launching, enable the press state and keep this reference to reset the press// state when we return to launcher.BubbleTextView btv = (BubbleTextView) v;btv.setStayPressed(true);addOnResumeCallback(btv);}return success;}

在此处判断包名后可直接 new 对话框进行交互,优点方便简单,缺点不能完全加锁。

2、ActivityStarter 中可拦截的地方

我这里偷懒了,界面没啥美化可言,你们自己按需调整。这里面引入 R 资源估计会有问题,所以这里直接

java 代码写布局了,通过 window 方式展示。

要拦截的包名清单可以通过 ContentProvider 查询,毕竟有 Context,自己按需增加。

frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java


import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.InputType;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;//cczheng add for appLockPass Sboolean isLocked;boolean isPassCheck;private void showAppLockPasswordWindow(Context mContext, IApplicationThread caller, Intent intent, Intent ephemeralIntent,String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,String callingPackage, int realCallingPid, int realCallingUid, int startFlags,SafeActivityOptions options,boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {final WindowManager.LayoutParams params =  new WindowManager.LayoutParams();params.width = 380;params.height = 230;params.format = Color.parseColor("#ADADAD");params.type = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;params.setTitle("AppLock");WindowManager mWM = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);final LinearLayout parentLayout = new LinearLayout(mContext);parentLayout.setOrientation(LinearLayout.VERTICAL);parentLayout.setBackgroundColor(Color.WHITE);LinearLayout.LayoutParams layoutParams= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);parentLayout.setLayoutParams(layoutParams);TextView titleText = new TextView(mContext);LinearLayout.LayoutParams contentParams= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);titleText.setLayoutParams(contentParams);titleText.setText("Please enter app password");titleText.setTextColor(Color.BLACK);titleText.setTypeface(Typeface.create(titleText.getTypeface(), Typeface.NORMAL), Typeface.BOLD);titleText.setPadding(10, 10, 0, 0);parentLayout.addView(titleText);EditText passText = new EditText(mContext);passText.setLayoutParams(contentParams);passText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);passText.setTextColor(Color.BLACK);parentLayout.addView(passText);Button okBtn = new Button(mContext);LinearLayout.LayoutParams btnParams= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);btnParams.gravity = Gravity.RIGHT;okBtn.setLayoutParams(btnParams);okBtn.setBackgroundColor(Color.TRANSPARENT);okBtn.setText("Confirm");okBtn.setTextColor(Color.parseColor("#3996E8"));okBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String password = passText.getText().toString();//android.widget.Toast.makeText(mContext, password, 1000).show();if (parentLayout!=null){mWM.removeViewImmediate(parentLayout);//parentLayout = null;}if ("123".equals(password)) {isPassCheck = true;startActivity(caller, intent, ephemeralIntent,resolvedType, aInfo, rInfo,voiceSession,  voiceInteractor,resultTo,  resultWho,  requestCode,  callingPid,  callingUid,callingPackage,  realCallingPid,  realCallingUid,  startFlags,options,ignoreTargetSecurity,  componentSpecified,  outActivity,inTask,  allowPendingRemoteAnimationRegistryLookup,originatingPendingIntent,  allowBackgroundActivityStart);}else {isPassCheck = false;}}});parentLayout.addView(okBtn);try {mWM.addView(parentLayout, params);} catch (WindowManager.BadTokenException e) {e.printStackTrace();}}IApplicationThread mscaller; Intent msintent, msephemeralIntent;String msresolvedType, msresultWho, mscallingPackage;ActivityInfo msaInfo;ResolveInfo msrInfo;int msrequestCode, mscallingPid, mscallingUid, msrealCallingPid, msrealCallingUid, msstartFlags;boolean msignoreTargetSecurity, mscomponentSpecified, msallowPendingRemoteAnimationRegistryLookup, msallowBackgroundActivityStart;IVoiceInteractionSession msvoiceSession;IVoiceInteractor msvoiceInteractor;IBinder msresultTo;SafeActivityOptions msoptions;ActivityRecord[] msoutActivity;TaskRecord msinTask;PendingIntentRecord msoriginatingPendingIntent;//Eprivate int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,String callingPackage, int realCallingPid, int realCallingUid, int startFlags,SafeActivityOptions options,boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);int err = ActivityManager.START_SUCCESS;// Pull the optional Ephemeral Installer-only bundle out of the options early.final Bundle verificationBundle= options != null ? options.popAppVerificationBundle() : null;................................checkedOptions = mInterceptor.mActivityOptions;}//cczheng add for appLockPass Sandroid.util.Log.e("ActivityStarter","callingPackage="+callingPackage);final String packageName = intent.getComponent().getPackageName();android.util.Log.i("ActivityStarter","packageName="+packageName+" abort="+abort);if (("com.android.launcher3".equals(callingPackage) || "com.android.systemui".equals(callingPackage)) && "com.android.settings".equals(packageName)) {isLocked = true;}else{isLocked = false;}if (isPassCheck) {android.util.Log.i("ActivityStarter","isPassCheck pass goto activity");isLocked = false;isPassCheck = false;}mscaller = caller;msintent = intent;msephemeralIntent = ephemeralIntent;msresolvedType = resolvedType;msaInfo = aInfo;msvoiceSession = voiceSession;msvoiceInteractor = voiceInteractor;msresultTo = resultTo;msresultWho = resultWho;msrequestCode = requestCode;mscallingPid = callingPid;mscallingUid = callingUid;mscallingPackage = callingPackage;msrealCallingPid = realCallingPid;msrealCallingUid = realCallingUid;msstartFlags = startFlags;msoptions = options;msignoreTargetSecurity = ignoreTargetSecurity;mscomponentSpecified = componentSpecified;msoutActivity = outActivity;msinTask = inTask;msallowPendingRemoteAnimationRegistryLookup = allowPendingRemoteAnimationRegistryLookup;msoriginatingPendingIntent = originatingPendingIntent;msallowBackgroundActivityStart = allowBackgroundActivityStart;new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {if (isLocked) {showAppLockPasswordWindow(mService.mContext, mscaller, msintent, msephemeralIntent,msresolvedType, msaInfo, msrInfo,msvoiceSession,  msvoiceInteractor,msresultTo,  msresultWho,  msrequestCode,  mscallingPid,  mscallingUid,mscallingPackage,  msrealCallingPid,  msrealCallingUid,  msstartFlags,msoptions,msignoreTargetSecurity,  mscomponentSpecified,  msoutActivity,msinTask,  msallowPendingRemoteAnimationRegistryLookup,msoriginatingPendingIntent,  msallowBackgroundActivityStart);}}});if (isLocked) {android.util.Log.d("ActivityStarter","START_SWITCHES_CANCELED=");return ActivityManager.START_SWITCHES_CANCELED;}///add EEif (abort) {if (resultRecord != null) {resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,RESULT_CANCELED, null);}// We pretend to the caller that it was really started, but// they will just get a cancel result.ActivityOptions.abort(checkedOptions);return START_ABORTED;}........................

以上几个坑点说一下

callingPackage 是调用 startActivity 方法的初始者,可以看到我这里加了过滤,必须是 SystemUI 和 Launcher3

调用的情况下才进行拦截,系统启动时我们看到的安卓正在启动中就是 Settings 中的 FallbackHome,此时 callingPackage 为 null

这样会卡住进不去系统,所以需要过滤。

showAppLockPasswordWindow() 需要在 Handler 执行,ActivityStarter 中不能直接进行 UI 线程操作,不然会报错。

符合拦截条件时需要先将此次 startActivity return,异步去显示 UI 操作,根据密码结果再递归一次 startActivity

所以 showAppLockPasswordWindow() 放到了内部类中,传递参数需要为 final 或者全局变量,所以上面加了一大堆全局赋值的,参数也太多了点。

android10.0(Q) AOSP 增加应用锁功能相关推荐

  1. Android 8.0 开机动画,RK3326 android10.0(Q) 开机logo+开关机动画替换

    RK3326 android10.0(Q) 开机logo+开关机动画替换 2020年08月14日 | 萬仟网移动技术 | 我要评论 开机logouboot和kernel阶段的logo分别为开机显示的第 ...

  2. android10.0(Q) root QCOM-SM6125 user版本打开root权限

    推荐两个性能优化学习地址: Blog androidperformance MTK 6735/6739/6755/6763 android8.1 user版本打开root权限(adb root权限和 ...

  3. android10.0(Q) android11(R) 时区相关问题

    一.默认关闭自动更新时区 将自动更新时区开关 def_auto_time_zone 的值设置为 false. 文件路径:platform/frameworks/base/packages/Settin ...

  4. android10.0(Q) root MTK 6765 user版本打开root权限(adb root权限和 apk root权限)

    前言 everybody,好久不见,我胡汉三又回来了,android10.0 root 安排!!! 相比较 Android8.1.9.0 而言,Q 版本 的 root变得相当麻烦,10.0 中引入了动 ...

  5. SysAid 9.0 发布,增加移动设备管理功能

    SysAid 9.0 提供新的移动设备管理功能,可让管理员控制所有的移动设备,并集成进了资产管理:提供了新的知识库 UI 设计和双屏远程控制.此外 SysAid 的 ITIL 得到了PinkVERIF ...

  6. Android10.0(Q) 实现通话中播放音乐/通话背景音(答录机/魔音功能)

    前言 这个功能大体意思类似机器人交互的效果,一般多应用到客服接听场景中,电话接通自动播放一段录音给 对方听,根据选项操作录音解析等完成一整个流程.这里面电话接通播放声音给对方听普通应用是做不到的, 因 ...

  7. Android6.0 源码增加黑名单功能

    [目标] 实现 8.1 中黑名单拦截功能 [实现] 涉及到的文件 frameworks/base/api/current.txt frameworks/base/api/system-current. ...

  8. EDEN-MACE 1.4.0 更新,增加数据清理功能

    EDEN-MACE 是一套灵活的管理佣金的分销管理系统,它涵盖并且总结了目前流行的分销模式,让分销更加简单. 为了能够让用户更加方便的使用,此次新增数据清理功能,即你可以随意的测试数据, 只要点一下数 ...

  9. android10.0(Q) Launcher3 去掉抽屉

    效果图 修改思路 1.增加变量 launcher3.is_full_app,用来动态切换 2.增加两套布局,对应有抽屉和无抽屉 3.去除 allAppsButton 4.将 AllAppsContai ...

最新文章

  1. Eclipse工作空间还原到最初状态
  2. 如何编写高性能的C#代码(四)字符串的另类骚操作
  3. Crosstool-ng制作交叉编译工具链
  4. Tiff – 比较两种字体差异
  5. Oracle中NB的中文处理
  6. 舍伍德算法解决线性时间选择
  7. 数据分析项目实战——链家深圳二手房房源数据分析
  8. chromecast协议_如何将Chromecast用作快速信息仪表板
  9. Eterm协议中文汉字编码
  10. 关于游戏手柄按键的设计
  11. java.vm.info_JNI完全指南(十)——JavaVM与JNIEnv
  12. PV、UV、IP含义及关系
  13. 循环经济下的商业模式
  14. 美军派网络部队前往韩国 防“萨德”泄密
  15. 【ESP 保姆级教程】疯狂传感器篇 —— 案例:ESP8266 + MQ7一氧化碳传感器 + 串口输出
  16. Python笔记 - Python切片
  17. 示波器和Multisim的使用
  18. 【论文精读】Local-Adaptive Image Alignment Based on Triangular Facet Approximation
  19. 清除系统垃圾文件的bat脚本
  20. Github上Python超越Java,人工智能程序员大热

热门文章

  1. Excel合并多列增加指定字符指定字符替换为换行符调整行高步骤
  2. 车截导航显示服务器错误怎么办,车载导航常见故障
  3. 如何用js进行日期的加减(天数)?
  4. C/C++数据结构——最优屏障(栈)
  5. HTTP的几种请求方法
  6. Java初学者轻便易于上手的小项目(2020最新)
  7. JAVA 命令行运行java项目
  8. mysql分表 ---Merge
  9. 蒸妙熏蒸,疏通身体的“堵”
  10. 《微服务系列:Eureka服务注册发现中心》