Android 15.0 启动app时设置密码锁

发布于:2025-08-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

在安卓15.0的系统产品开发中,对于限制某些app的启动的功能中,在项目中的需求是在点击app启动的时候,根据包名设置密码锁,当输入正确的密码的时候来启动这个app,否则
就不能启动这个app,达到限制使用app的目的,这就需要在app启动的时候,检测app的包名,然后在app启动的时候弹出输入密码的窗口,让用户输入只密码,当输入正确的密码
才可以使用app,这就需要先熟悉app的启动流程,然后来实现这个功能后

思路:

  1. 使用contentPrivide 储存已加锁的app包名字符串,使用 SystemProperties储存加锁状态和设置的密码
  2. 在launcher3中 点击桌面图标进行状态判断
  3. 在最近任务视图中,设置加锁后,立即清空最近任务视图

补丁如下:


diff --git a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/AndroidManifest-common.xml b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/AndroidManifest-common.xml
index 0e8cfdc60f9..a56f32bf53f 100644
--- a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/AndroidManifest-common.xml
+++ b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/AndroidManifest-common.xml
@@ -51,6 +51,9 @@
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
+    <uses-permission android:name="com.ro.settings.provider.READ_PREFS"/>
+    <uses-permission android:name="com.ro.settings.provider.WRITE_PREFS"/>
+
     <!--
     Permissions required for read/write access to the workspace data. These permission name
     should not conflict with that defined in other apps, as such an app should embed its package
diff --git a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2857afbce35..5a99c731b4b 100644
--- a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -73,6 +73,7 @@ import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SCREEN;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SELECT_ACTIVE;
 
+import android.os.SystemProperties;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -1755,6 +1756,13 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
             mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
             return;
         }
+        // 当应用加锁功能打开时,即清除最近任务标志位为true时,进入最近任务视图,模拟 全部清除 被点击,防止用户从最近任务视图启动app,跳过输入密码的功能
+        // TODO:升级到framework层进行加锁app的判断(需要考虑如何输入密码进行交互)
+        boolean needClean = SystemProperties.getBoolean("persist.sys.lock_app.clean_recent", false);
+        if (needClean){
+            mClearAllButton.performClick();
+            SystemProperties.set("persist.sys.lock_app.clean_recent", "false");
+        }
 
         if (taskGroups == null) {
             Log.d(TAG, "applyLoadPlan - taskGroups is null");
diff --git a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
index db31d64fbc7..a6a8d193ba6 100644
--- a/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
+++ b/LA.QSSI.15.0_MC9452/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@@ -15,6 +15,20 @@
  */
 
 package com.android.launcher3;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.DialogInterface;
+import android.text.InputType;
+import android.widget.EditText;
+import android.os.SystemProperties;
+import java.util.Locale;
+import java.util.Arrays;
+import java.util.List;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.database.Cursor;
+import android.content.ContentResolver;
 
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -295,6 +309,8 @@ public class Launcher extends StatefulActivity<LauncherState>
         implements Callbacks, InvariantDeviceProfile.OnIDPChangeListener,
         PluginListener<LauncherOverlayPlugin> {
     public static final String TAG = "Launcher";
+    private final Map<String, Long> mPasswordPassedMap = new HashMap<>();
+    private static final long PASSWORD_VALID_DURATION_MS = 2 * 60 * 60 * 1000; // 未重启launcher3的情况下,输入密码后,同一app 2小时内免输密码
 
     public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
 
@@ -2135,8 +2151,103 @@ public class Launcher extends StatefulActivity<LauncherState>
         }
     }
 
+
+    private void showPasswordDialog(Runnable onSuccess) {
+        Locale locale = Locale.getDefault();
+        boolean isChinese = locale.getLanguage().equals("zh");
+
+        // 动态生成密码输入弹窗
+        String pwd = SystemProperties.get("persist.sys.lock_app.setting.password", "");
+        String title = isChinese ? "请输入密码" : "Enter Password";
+        String positiveText = isChinese ? "确认" : "OK";
+        String negativeText = isChinese ? "取消" : "Cancel";
+        String wrongPasswordText = isChinese ? "密码错误" : "Wrong password";
+        String wrongPasswordTitle = isChinese ? "错误" : "Error";
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(title);
+
+        final EditText input = new EditText(this);
+        input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+        builder.setView(input);
+
+        builder.setPositiveButton(positiveText, (dialog, which) -> {
+            String enteredPassword = input.getText().toString();
+            if (pwd.equals(enteredPassword)) {
+                onSuccess.run();
+            } else {
+                new AlertDialog.Builder(this)
+                    .setTitle(wrongPasswordTitle)
+                    .setMessage(wrongPasswordText)
+                    .setPositiveButton(positiveText, null)
+                    .show();
+            }
+        });
+
+        builder.setNegativeButton(negativeText, (dialog, which) -> dialog.cancel());
+        builder.show();
+    }
+
+
+    private String getLockedAppList() {
+        String lockedApps = "";
+        Cursor cursor = null;
+        try {
+            final Uri uri = Uri.parse("content://com.ro.settings.lock_app/lock_app");
+            cursor = getContentResolver().query(uri, null, null, null, null);
+            if (cursor != null && cursor.moveToFirst()) {
+                lockedApps = cursor.getString(0);
+                // Log.d("Launcher3", "获取到的应用锁列表: " + lockedApps);
+            }
+        } catch (Exception e) {
+            // Log.e("Launcher3", "访问LockAppPrefsProvider出错", e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return lockedApps != null ? lockedApps : "";
+    }
+
+
+
+
     @Override
     public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
+
+
+        // TODO:升级到framework层进行加锁app的判断
+        boolean isLockEnabled = SystemProperties.getBoolean("persist.sys.lock_app.enabled", false);
+        if (isLockEnabled){
+            String app_list = getLockedAppList();
+
+            ComponentName component = intent.getComponent();
+            String packageName = component != null ? component.getPackageName() : "";
+
+            if (!packageName.isEmpty()) {
+                List<String> lockedApps = Arrays.asList(app_list.split(","));
+                if (lockedApps.contains(packageName)) {
+                    long now = System.currentTimeMillis();
+                    Long lastSuccessTime = mPasswordPassedMap.get(packageName);
+                    if (lastSuccessTime != null && (now - lastSuccessTime < PASSWORD_VALID_DURATION_MS)) {
+                        // 最近已通过密码验证,直接启动
+                        return super.startActivitySafely(v, intent, item);
+                    }
+
+                    // 否则弹出密码输入框
+                    showPasswordDialog(() -> {
+                        mPasswordPassedMap.put(packageName, System.currentTimeMillis());
+                        try {
+                            super.startActivity(intent, null);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    });
+                    return null;
+                }
+            }
+        }
+
         if (!hasBeenResumed()) {
             RunnableList result = new RunnableList();
             // Workaround an issue where the WM launch animation is clobbered when finishing the


网站公告

今日签到

点亮在社区的每一天
去签到