Android 15.0 启动app时设置密码锁
在安卓15.0的系统产品开发中,对于限制某些app的启动的功能中,在项目中的需求是在点击app启动的时候,根据包名设置密码锁,当输入正确的密码的时候来启动这个app,否则
就不能启动这个app,达到限制使用app的目的,这就需要在app启动的时候,检测app的包名,然后在app启动的时候弹出输入密码的窗口,让用户输入只密码,当输入正确的密码
才可以使用app,这就需要先熟悉app的启动流程,然后来实现这个功能后
思路:
- 使用contentPrivide 储存已加锁的app包名字符串,使用 SystemProperties储存加锁状态和设置的密码
- 在launcher3中 点击桌面图标进行状态判断
- 在最近任务视图中,设置加锁后,立即清空最近任务视图
补丁如下:
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 nameshould 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 & RecentsViewComPendingAnimation.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 : "";
+ }
+
+
+
+@Overridepublic 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