From aa1e5bc954cd1e4e61226329edaf586777f5bde3 Mon Sep 17 00:00:00 2001
From: jhonboy121 <alfredmathew05@gmail.com>
Date: Tue, 1 Feb 2022 19:54:15 +0530
Subject: [PATCH] base: Add support for app lock

Changes are imported from the original frameworks/base commit
Ie35c6c7103b8bed644d510d8268d6c99cb71a1a2 and adapted for
lmo framework.

Change-Id: Ib3cae7e882e98c6668a68e148c0aaccbea60fb3b
Co-authored-by: Dhina17 <dhinalogu@gmail.com>
---
 .../notification/StatusBarNotification.java   | 31 ++++++-
 data/etc/com.android.settings.xml             |  1 +
 .../RemoteInputNotificationRebuilder.java     |  5 +-
 .../SensitiveContentCoordinator.kt            |  6 +-
 .../inflation/NotifUiAdjustmentProvider.kt    |  2 +-
 .../inflation/NotificationRowBinderImpl.java  |  2 +-
 .../row/ExpandableNotificationRow.java        | 26 ++++--
 .../phone/StatusBarNotificationPresenter.java |  2 +-
 .../AppLockManagerServiceInternal.java        | 80 +++++++++++++++++++
 .../locksettings/LockSettingsService.java     |  2 +
 .../server/notification/BubbleExtractor.java  |  6 +-
 .../NotificationManagerInternal.java          |  3 +
 .../NotificationManagerService.java           | 54 +++++++++++--
 .../notification/NotificationRecord.java      | 10 +++
 .../NotificationRecordExtractorData.java      | 11 ++-
 .../server/pm/LauncherAppsService.java        | 16 ++++
 .../server/trust/TrustManagerService.java     | 11 +++
 .../server/wm/ActivityStartInterceptor.java   | 41 ++++++++++
 .../wm/ActivityTaskManagerInternal.java       |  2 +
 .../server/wm/ActivityTaskManagerService.java | 30 +++++++
 20 files changed, 313 insertions(+), 28 deletions(-)
 create mode 100644 services/core/java/com/android/server/libremobileos/AppLockManagerServiceInternal.java

diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index bb56939ac72f..19ea650012f5 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -71,10 +71,13 @@ public class StatusBarNotification implements Parcelable {
 
     private Context mContext; // used for inflation & icon expansion
 
+    private boolean mIsContentSecure;
+
     /** @hide */
     public StatusBarNotification(String pkg, String opPkg, int id,
             String tag, int uid, int initialPid, Notification notification, UserHandle user,
-            String overrideGroupKey, long postTime) {
+            String overrideGroupKey, long postTime,
+            boolean isContentSecure) {
         if (pkg == null) throw new NullPointerException();
         if (notification == null) throw new NullPointerException();
 
@@ -90,6 +93,7 @@ public class StatusBarNotification implements Parcelable {
         this.overrideGroupKey = overrideGroupKey;
         this.key = key();
         this.groupKey = groupKey();
+        mIsContentSecure = isContentSecure;
     }
 
     /**
@@ -137,6 +141,7 @@ public class StatusBarNotification implements Parcelable {
         }
         this.key = key();
         this.groupKey = groupKey();
+        mIsContentSecure = in.readBoolean();
     }
 
     /**
@@ -237,6 +242,7 @@ public class StatusBarNotification implements Parcelable {
         } else {
             out.writeInt(0);
         }
+        out.writeBoolean(mIsContentSecure);
     }
 
     public int describeContents() {
@@ -276,7 +282,8 @@ public class StatusBarNotification implements Parcelable {
     StatusBarNotification cloneShallow(Notification notification) {
         StatusBarNotification result = new StatusBarNotification(this.pkg, this.opPkg,
                 this.id, this.tag, this.uid, this.initialPid,
-                notification, this.user, this.overrideGroupKey, this.postTime);
+                notification, this.user, this.overrideGroupKey,
+                this.postTime, mIsContentSecure);
         result.setInstanceId(this.mInstanceId);
         return result;
     }
@@ -560,4 +567,24 @@ public class StatusBarNotification implements Parcelable {
         return logTag.substring(0, MAX_LOG_TAG_LENGTH - hash.length() - 1) + "-"
                 + hash;
     }
+
+    /**
+     * Set whether the notification content is secure.
+     *
+     * @param isContentSecure whether the content is secure.
+     * @hide
+     */
+    public void setIsContentSecure(boolean isContentSecure) {
+        mIsContentSecure = isContentSecure;
+    }
+
+    /**
+     * Check whether the notification content is secure.
+     *
+     * @return true if content is secure, false otherwise.
+     * @hide
+     */
+    public boolean getIsContentSecure() {
+        return mIsContentSecure;
+    }
 }
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index dcc96861bc31..b6ce6518cf3e 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -65,5 +65,6 @@
         <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
         <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
         <permission name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS" />
+        <permission name="com.android.permission.MANAGE_APP_LOCK" />
     </privapp-permissions>
 </permissions>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java
index 90abec17771c..a05c5bbf6f86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java
@@ -134,8 +134,7 @@ public class RemoteInputNotificationRebuilder {
                 newNotification,
                 sbn.getUser(),
                 sbn.getOverrideGroupKey(),
-                sbn.getPostTime());
+                sbn.getPostTime(),
+                sbn.getIsContentSecure());
     }
-
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index aeeeb4fb054d..1b1cee80d9d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -103,9 +103,11 @@ private class SensitiveContentCoordinatorImpl @Inject constructor(
                     else -> lockscreenUserManager.needsSeparateWorkChallenge(notifUserId)
                 }
             }
-            val needsRedaction = lockscreenUserManager.needsRedaction(entry)
+            val isSecure = entry.sbn.isContentSecure
+            val needsRedaction = isSecure || lockscreenUserManager.needsRedaction(entry)
             val isSensitive = userPublic && needsRedaction
-            entry.setSensitive(isSensitive, deviceSensitive)
+            entry.setSensitive(isSensitive, isSecure || deviceSensitive)
+            entry.row.setForceHideContents(isSecure)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
index 058545689c01..b2bcd6780144 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
@@ -120,6 +120,6 @@ class NotifUiAdjustmentProvider @Inject constructor(
         isConversation = entry.ranking.isConversation,
         isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled,
         isMinimized = isEntryMinimized(entry),
-        needsRedaction = lockscreenUserManager.needsRedaction(entry),
+        needsRedaction = entry.sbn.isContentSecure || lockscreenUserManager.needsRedaction(entry),
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index e20614178885..34fbbcbdbc1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -222,7 +222,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
         params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
         params.setUseLowPriority(isLowPriority);
 
-        if (mNotificationLockscreenUserManager.needsRedaction(entry)) {
+        if (mNotificationLockscreenUserManager.needsRedaction(entry) || entry.getSbn().getIsContentSecure()) {
             params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
         } else {
             params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d92d11b18d74..99febcece1ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -387,6 +387,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
     private float mBottomRoundnessDuringLaunchAnimation;
     private float mSmallRoundness;
 
+    private boolean mForceHideContents = false;
+
     public NotificationContentView[] getLayouts() {
         return Arrays.copyOf(mLayouts, mLayouts.length);
     }
@@ -2247,12 +2249,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
     private void updateChildrenVisibility() {
         boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
                 && mGuts.isExposed();
-        mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren
+        mPrivateLayout.setVisibility(!mForceHideContents
+                && !mShowingPublic
+                && !mIsSummaryWithChildren
                 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
         if (mChildrenContainer != null) {
-            mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren
-                    && !hideContentWhileLaunching ? VISIBLE
-                    : INVISIBLE);
+            mChildrenContainer.setVisibility(!mForceHideContents
+                && !mShowingPublic
+                && mIsSummaryWithChildren
+                && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
         }
         // The limits might have changed if the view suddenly became a group or vice versa
         updateLimits();
@@ -2427,6 +2432,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
     }
 
     public boolean isExpandable() {
+        if (mForceHideContents) return false;
         if (mIsSummaryWithChildren && !shouldShowPublic()) {
             return !mChildrenExpanded;
         }
@@ -2597,6 +2603,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
 
     @Override
     public int getIntrinsicHeight() {
+        if (mForceHideContents) return getCollapsedHeight();
         if (isUserLocked()) {
             return getActualHeight();
         } else if (mGuts != null && mGuts.isExposed()) {
@@ -2845,7 +2852,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
                 mChildrenContainer.animate().cancel();
             }
             resetAllContentAlphas();
-            mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
+            mPublicLayout.setVisibility((mShowingPublic || mForceHideContents) ? VISIBLE : INVISIBLE);
             updateChildrenVisibility();
         } else {
             animateShowingPublic(delay, duration, mShowingPublic);
@@ -2920,7 +2927,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
     }
 
     private boolean shouldShowPublic() {
-        return mSensitive && mHideSensitiveForIntrinsicHeight;
+        return mForceHideContents || (mSensitive && mHideSensitiveForIntrinsicHeight);
     }
 
     public void makeActionsVisibile() {
@@ -3558,6 +3565,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
         }
     }
 
+    public void setForceHideContents(boolean forceHide) {
+        if (mForceHideContents == forceHide) return;
+        mForceHideContents = forceHide;
+        updateChildrenVisibility();
+        onNotificationUpdated();
+    }
+
     private static class NotificationViewState extends ExpandableViewState {
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index ecc996c57ac6..27db2bafd509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -303,7 +303,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu
 
         @Override
         public boolean suppressAwakeInterruptions(NotificationEntry entry) {
-            return isDeviceInVrMode();
+            return isDeviceInVrMode() || entry.getSbn().getIsContentSecure();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/libremobileos/AppLockManagerServiceInternal.java b/services/core/java/com/android/server/libremobileos/AppLockManagerServiceInternal.java
new file mode 100644
index 000000000000..a54739c2aaa6
--- /dev/null
+++ b/services/core/java/com/android/server/libremobileos/AppLockManagerServiceInternal.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2023 The LibreMobileOS Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.libremobileos;
+
+import android.content.Intent;
+
+import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
+
+import java.util.Set;
+
+/**
+ * Internal class for system server to manage app lock.
+ *
+ * @hide
+ */
+public interface AppLockManagerServiceInternal {
+
+    /**
+     * Whether user has to unlock this application in order to
+     * open it.
+     *
+     * @param packageName the package name of the app to check.
+     * @param userId the user id given by the caller.
+     * @return true if user has to unlock, false otherwise.
+     */
+    boolean requireUnlock(String packageName, int userId);
+
+    /**
+     * Report that password for user has changed.
+     *
+     * @param userId the user for which password has changed.
+     */
+    void reportPasswordChanged(int userId);
+
+    /**
+     * Check whether notification content should be hidden for a package.
+     *
+     * @param packageName the package to check for.
+     * @param userId the user id given by the caller.
+     * @return true if notification should be hidden, false otherwise.
+     */
+    boolean shouldRedactNotification(String packageName, int userId);
+
+    /**
+     * Notify that the device is locked for current user.
+     */
+    void notifyDeviceLocked(boolean locked, int userId);
+
+    /**
+     * Whether to intercept the activity launch from a package. Used
+     * to show confirm credentials prompt.
+     *
+     * @param info [ActivityInterceptorInfo] of intercepted activity.
+     * @return [Intent] which will be fired. Return null if activity
+     *    shouldn't be intercepted.
+     */
+    Intent interceptActivity(ActivityInterceptorInfo info);
+
+    /**
+     * Get the list of applications hidden from launcher.
+     *
+     * @param userId the user id given of the caller.
+     * @return a hash set of package names.
+     */
+    Set<String> getHiddenPackages(int userId);
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ad17ebbe46ec..4a00528ad710 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -146,6 +146,7 @@ import com.android.internal.widget.VerifyCredentialResponse;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
 import com.android.server.locksettings.SyntheticPasswordManager.SyntheticPassword;
@@ -2332,6 +2333,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                     PasswordMetrics.computeForCredential(newCredential),
                     userId);
             LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId);
+            LocalServices.getService(AppLockManagerServiceInternal.class).reportPasswordChanged(userId);
         });
     }
 
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index b8900d7acee5..373c2a9553d8 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -89,7 +89,8 @@ public class BubbleExtractor implements NotificationSignalExtractor {
         NotificationChannel recordChannel = record.getChannel();
         if (!userEnabledBubbles
                 || appPreference == BUBBLE_PREFERENCE_NONE
-                || !notifCanPresentAsBubble) {
+                || !notifCanPresentAsBubble
+                || record.getSbn().getIsContentSecure()) {
             record.setAllowBubble(false);
             if (!notifCanPresentAsBubble) {
                 // clear out bubble metadata since it can't be used
@@ -143,10 +144,9 @@ public class BubbleExtractor implements NotificationSignalExtractor {
      */
     @VisibleForTesting
     boolean canPresentAsBubble(NotificationRecord r) {
-        if (!mSupportsBubble) {
+        if (!mSupportsBubble || r.isBubbleUpSuppressedByAppLock()) {
             return false;
         }
-
         Notification notification = r.getNotification();
         Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
         String pkg = r.getSbn().getPackageName();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index c240bcbce911..ebf6c8c657ae 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -52,4 +52,7 @@ public interface NotificationManagerInternal {
     void sendReviewPermissionsNotification();
 
     void cleanupHistoryFiles();
+
+    void updateSecureNotifications(String pkg, boolean isContentSecure,
+        boolean isBubbleUpSuppressed, int userId);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2b42800fc33b..a85617f689cb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -43,6 +43,7 @@ import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_
 import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
@@ -314,6 +315,7 @@ import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.job.JobSchedulerInternal;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
@@ -708,6 +710,8 @@ public class NotificationManagerService extends SystemService {
 
     private LineageNotificationLights mLineageNotificationLights;
 
+    private AppLockManagerServiceInternal mAppLockManagerService = null;
+
     static class Archive {
         final SparseArray<Boolean> mEnabled;
         final int mBufferSize;
@@ -2807,6 +2811,7 @@ public class NotificationManagerService extends SystemService {
             maybeShowInitialReviewPermissionsNotification();
         } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
             mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
+            mAppLockManagerService = LocalServices.getService(AppLockManagerServiceInternal.class);
         } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
             mPreferencesHelper.updateFixedImportance(mUm.getUsers());
             mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers());
@@ -3687,8 +3692,8 @@ public class NotificationManagerService extends SystemService {
         public int getBubblePreferenceForPackage(String pkg, int uid) {
             enforceSystemOrSystemUIOrSamePackage(pkg,
                     "Caller not system or systemui or same package");
-
-            if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
+            final int userId = UserHandle.getUserId(uid);
+            if (UserHandle.getCallingUserId() != userId) {
                 getContext().enforceCallingPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
                         "getBubblePreferenceForPackage for uid " + uid);
@@ -4493,7 +4498,8 @@ public class NotificationManagerService extends SystemService {
                             sbn.getOpPkg(),
                             sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
                             notification,
-                            sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
+                            sbn.getUser(), sbn.getOverrideGroupKey(),
+                            sbn.getPostTime(), sbn.getIsContentSecure());
                 }
             }
             return null;
@@ -6120,6 +6126,8 @@ public class NotificationManagerService extends SystemService {
                             0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
                             pkg, appInfo.uid);
                 }
+                final boolean isContentSecure = mAppLockManagerService != null &&
+                    mAppLockManagerService.shouldRedactNotification(pkg, userId);
                 final StatusBarNotification summarySbn =
                         new StatusBarNotification(adjustedSbn.getPackageName(),
                                 adjustedSbn.getOpPkg(),
@@ -6127,13 +6135,16 @@ public class NotificationManagerService extends SystemService {
                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
                                 adjustedSbn.getInitialPid(), summaryNotification,
                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
-                                System.currentTimeMillis());
+                                System.currentTimeMillis(), isContentSecure);
                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
                         notificationRecord.getChannel());
                 summaryRecord.setImportanceFixed(isPermissionFixed);
                 summaryRecord.setIsAppImportanceLocked(
                         notificationRecord.getIsAppImportanceLocked());
                 summaries.put(pkg, summarySbn.getKey());
+                summaryRecord.setBubbleUpSuppressedByAppLock(
+                    mAppLockManagerService != null &&
+                    mAppLockManagerService.requireUnlock(pkg, userId));
             }
             if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
                     summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
@@ -6608,6 +6619,32 @@ public class NotificationManagerService extends SystemService {
             checkCallerIsSystem();
             mHistoryManager.cleanupHistoryFiles();
         }
+
+        public void updateSecureNotifications(String pkg, boolean isContentSecure,
+                boolean isBubbleUpSuppressed, int userId) {
+            mHandler.post(() -> updateSecureNotificationsInternal(pkg, isContentSecure,
+                isBubbleUpSuppressed, userId));
+        }
+
+        private void updateSecureNotificationsInternal(String pkg, boolean isContentSecure,
+                boolean isBubbleUpSuppressed, int userId) {
+            synchronized (mNotificationLock) {
+                for (int i = 0; i < mNotificationList.size(); i++) {
+                    final NotificationRecord nr = mNotificationList.get(i);
+                    final StatusBarNotification sbn = nr.getSbn();
+                    if (UserHandle.getUserId(sbn.getUid()) == userId
+                            && sbn.getPackageName().equals(pkg)) {
+                        if (sbn.getIsContentSecure() != isContentSecure ||
+                                nr.isBubbleUpSuppressedByAppLock() != isBubbleUpSuppressed) {
+                            sbn.setIsContentSecure(isContentSecure);
+                            nr.setBubbleUpSuppressedByAppLock(isBubbleUpSuppressed);
+                            mListeners.notifyPostedLocked(nr, nr);
+                        }
+                    }
+                }
+            }
+            mRankingHandler.requestSort();
+        }
     };
 
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
@@ -6770,9 +6807,11 @@ public class NotificationManagerService extends SystemService {
 
         mUsageStats.registerEnqueuedByApp(pkg);
 
+        final boolean isContentSecure = mAppLockManagerService != null &&
+            mAppLockManagerService.shouldRedactNotification(pkg, userId);
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
-                user, null, System.currentTimeMillis());
+                user, null, System.currentTimeMillis(), isContentSecure);
 
         // setup local book-keeping
         String channelId = notification.getChannelId();
@@ -6813,6 +6852,8 @@ public class NotificationManagerService extends SystemService {
         r.setPostSilently(postSilently);
         r.setFlagBubbleRemoved(false);
         r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
+        r.setBubbleUpSuppressedByAppLock(mAppLockManagerService != null &&
+            mAppLockManagerService.requireUnlock(pkg, userId));
         boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
         r.setImportanceFixed(isImportanceFixed);
 
@@ -9037,7 +9078,8 @@ public class NotificationManagerService extends SystemService {
                         r.getRankingScore(),
                         r.isConversation(),
                         r.getProposedImportance(),
-                        r.hasSensitiveContent());
+                        r.hasSensitiveContent(),
+                        r.isBubbleUpSuppressedByAppLock());
                 extractorDataBefore.put(r.getKey(), extractorData);
                 mRankingHelper.extractSignals(r);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 3f0b2b4f5ecc..58de9df5c099 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -216,6 +216,8 @@ public final class NotificationRecord {
     private int mProposedImportance = IMPORTANCE_UNSPECIFIED;
     private boolean mSensitiveContent = false;
 
+    private boolean mIsBubbleUpSuppressedByAppLock = false;
+
     public NotificationRecord(Context context, StatusBarNotification sbn,
             NotificationChannel channel) {
         this.sbn = sbn;
@@ -1647,6 +1649,14 @@ public final class NotificationRecord {
         return mKeyguardManager;
     }
 
+    public void setBubbleUpSuppressedByAppLock(boolean suppressed) {
+        mIsBubbleUpSuppressedByAppLock = suppressed;
+    }
+
+    public boolean isBubbleUpSuppressedByAppLock() {
+        return mIsBubbleUpSuppressedByAppLock;
+    }
+
     @VisibleForTesting
     static final class Light {
         public final int color;
diff --git a/services/core/java/com/android/server/notification/NotificationRecordExtractorData.java b/services/core/java/com/android/server/notification/NotificationRecordExtractorData.java
index 3f4f7d3bbc38..3e883e7df0e7 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordExtractorData.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordExtractorData.java
@@ -41,6 +41,7 @@ public final class NotificationRecordExtractorData {
     private final ArrayList<Notification.Action> mSystemSmartActions;
     private final ArrayList<CharSequence> mSmartReplies;
     private final int mImportance;
+    private final boolean mIsBubbleUpSuppressedByAppLock;
 
     // These fields may not trigger a reranking but diffs here may be logged.
     private final float mRankingScore;
@@ -54,7 +55,8 @@ public final class NotificationRecordExtractorData {
             Integer userSentiment, Integer suppressVisually,
             ArrayList<Notification.Action> systemSmartActions,
             ArrayList<CharSequence> smartReplies, int importance, float rankingScore,
-            boolean isConversation, int proposedImportance, boolean sensitiveContent) {
+            boolean isConversation, int proposedImportance, boolean sensitiveContent,
+            boolean isBubbleUpSuppressedByAppLock) {
         mPosition = position;
         mVisibility = visibility;
         mShowBadge = showBadge;
@@ -73,6 +75,7 @@ public final class NotificationRecordExtractorData {
         mIsConversation = isConversation;
         mProposedImportance = proposedImportance;
         mSensitiveContent = sensitiveContent;
+        mIsBubbleUpSuppressedByAppLock = isBubbleUpSuppressedByAppLock;
     }
 
     // Returns whether the provided NotificationRecord differs from the cached data in any way.
@@ -93,7 +96,8 @@ public final class NotificationRecordExtractorData {
                 || !Objects.equals(mSmartReplies, r.getSmartReplies())
                 || mImportance != r.getImportance()
                 || mProposedImportance != r.getProposedImportance()
-                || mSensitiveContent != r.hasSensitiveContent();
+                || mSensitiveContent != r.hasSensitiveContent()
+                || mIsBubbleUpSuppressedByAppLock != r.isBubbleUpSuppressedByAppLock();
     }
 
     // Returns whether the NotificationRecord has a change from this data for which we should
@@ -117,6 +121,7 @@ public final class NotificationRecordExtractorData {
                 || !r.rankingScoreMatches(mRankingScore)
                 || mIsConversation != r.isConversation()
                 || mProposedImportance != r.getProposedImportance()
-                || mSensitiveContent != r.hasSensitiveContent();
+                || mSensitiveContent != r.hasSensitiveContent()
+                || mIsBubbleUpSuppressedByAppLock != r.isBubbleUpSuppressedByAppLock();
     }
 }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index fbdf750235cc..65ad39adf303 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -109,6 +109,7 @@ import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -127,6 +128,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -224,6 +226,8 @@ public class LauncherAppsService extends SystemService {
         @NonNull
         private final RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>();
 
+        private AppLockManagerServiceInternal mAppLockManagerInternal;
+
         public LauncherAppsImpl(Context context) {
             mContext = context;
             mIPM = AppGlobals.getPackageManager();
@@ -688,8 +692,16 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
+        private AppLockManagerServiceInternal getAppLockManagerService() {
+            if (mAppLockManagerInternal == null) {
+                mAppLockManagerInternal = LocalServices.getService(AppLockManagerServiceInternal.class);
+            }
+            return mAppLockManagerInternal;
+        }
+
         private List<LauncherActivityInfoInternal> queryIntentLauncherActivities(
                 Intent intent, int callingUid, UserHandle user) {
+            final Set<String> hiddenApps = getAppLockManagerService().getHiddenPackages(user.getIdentifier());
             final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities(intent,
                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                     PackageManager.MATCH_DIRECT_BOOT_AWARE
@@ -704,6 +716,10 @@ public class LauncherAppsService extends SystemService {
                     // should not happen
                     continue;
                 }
+                if (hiddenApps.contains(packageName)) {
+                    if (DEBUG) Slog.d(TAG, "Skipping package " + packageName);
+                    continue;
+                }
                 final IncrementalStatesInfo incrementalStatesInfo =
                         mPackageManagerInternal.getIncrementalStatesInfo(packageName, callingUid,
                                 user.getIdentifier());
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index bed69fc635b8..e53be756cc61 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -86,6 +86,7 @@ import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -258,6 +259,8 @@ public class TrustManagerService extends SystemService {
         }
     }
 
+    private AppLockManagerServiceInternal mAppLockManagerService = null;
+
     public TrustManagerService(Context context) {
         this(context, new Injector(new LockPatternUtils(context), Looper.myLooper()));
     }
@@ -1003,7 +1006,15 @@ public class TrustManagerService extends SystemService {
             }
 
             setDeviceLockedForUser(id, deviceLocked);
+            getAppLockManagerService().notifyDeviceLocked(deviceLocked, id);
+        }
+    }
+
+    private AppLockManagerServiceInternal getAppLockManagerService() {
+        if (mAppLockManagerService == null) {
+            mAppLockManagerService = LocalServices.getService(AppLockManagerServiceInternal.class);
         }
+        return mAppLockManagerService;
     }
 
     private void setDeviceLockedForUser(@UserIdInt int userId, boolean locked) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1eb56f1b7d1c..3903ebeaa42f 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -64,6 +64,7 @@ import com.android.internal.app.SuspendedAppActivity;
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
 
 /**
@@ -221,6 +222,9 @@ class ActivityStartInterceptor {
         if (interceptLockedManagedProfileIfNeeded()) {
             return true;
         }
+        if (interceptLockedAppIfNeeded()) {
+            return true;
+        }
 
         final SparseArray<ActivityInterceptorCallback> callbacks =
                 mService.getActivityInterceptorCallbacks();
@@ -529,4 +533,41 @@ class ActivityStartInterceptor {
         }
         return true;
     }
+
+    private AppLockManagerServiceInternal getAppLockManagerService() {
+        return mService.getAppLockManagerService();
+    }
+
+    private boolean interceptLockedAppIfNeeded() {
+        if (getAppLockManagerService() == null) return false;
+        final Intent interceptingIntent = getAppLockManagerService().interceptActivity(getInterceptorInfo(null));
+        if (interceptingIntent == null) return false;
+        mIntent = interceptingIntent;
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+        final TaskFragment taskFragment = getLaunchTaskFragment();
+        // If we are intercepting and there was a task, convert it into an extra for the
+        // ConfirmCredentials intent and unassign it, as otherwise the task will move to
+        // front even if ConfirmCredentials is cancelled.
+        if (mInTask != null) {
+            mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
+            mInTask = null;
+        } else if (taskFragment != null) {
+            // If the original intent is started to an embedded TaskFragment, append its parent task
+            // id to extra. It is to embed back the original intent to the TaskFragment with the
+            // same task.
+            final Task parentTask = taskFragment.getTask();
+            if (parentTask != null) {
+                mIntent.putExtra(EXTRA_TASK_ID, parentTask.mTaskId);
+            }
+        }
+        if (mActivityOptions == null) {
+            mActivityOptions = ActivityOptions.makeBasic();
+        }
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
+                mRealCallingUid, mRealCallingPid);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index a2547fd437d1..fb3e04a7d12a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -778,4 +778,6 @@ public abstract class ActivityTaskManagerInternal {
      * @param token The activity token.
      */
     public abstract int getDisplayId(IBinder token);
+
+    public abstract boolean isVisibleActivity(IBinder activityToken);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 358c73a238c2..71a27c22a0c9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -272,6 +272,7 @@ import com.android.server.am.PendingIntentController;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.am.UserState;
 import com.android.server.firewall.IntentFirewall;
+import com.android.server.libremobileos.AppLockManagerServiceInternal;
 import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.sdksandbox.SdkSandboxManagerLocal;
@@ -848,6 +849,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         }
     };
 
+    private AppLockManagerServiceInternal mAppLockManagerService = null;
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public ActivityTaskManagerService(Context context) {
         mContext = context;
@@ -1790,6 +1793,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
 
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
+
         final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -3821,6 +3825,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                     Slog.w(TAG, "takeTaskSnapshot: taskId=" + taskId + " not found or not visible");
                     return null;
                 }
+
+                final Task rootTask = task.getRootTask();
+                final String packageName =
+                    rootTask != null && rootTask.realActivity != null
+                        ? rootTask.realActivity.getPackageName()
+                        : null;
+                if (packageName != null && getAppLockManagerService().requireUnlock(
+                        packageName, task.mUserId)) {
+                    return null;
+                }
+                
                 if (updateCache) {
                     return mWindowManager.mTaskSnapshotController.recordSnapshot(task,
                             true /* snapshotHome */);
@@ -5282,6 +5297,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         return mWallpaperManagerInternal;
     }
 
+    AppLockManagerServiceInternal getAppLockManagerService() {
+        if (mAppLockManagerService == null) {
+            mAppLockManagerService = LocalServices.getService(AppLockManagerServiceInternal.class);
+        }
+        return mAppLockManagerService;
+    }
+
     AppWarnings getAppWarningsLocked() {
         return mAppWarnings;
     }
@@ -7162,6 +7184,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
         public void unregisterTaskStackListener(ITaskStackListener listener) {
             ActivityTaskManagerService.this.unregisterTaskStackListener(listener);
         }
+
+        @Override
+        public boolean isVisibleActivity(IBinder activityToken) {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken);
+                return r != null && r.isInterestingToUserLocked();
+            }
+        }
     }
 
     public boolean shouldForceLongScreen(String packageName) {
-- 
GitLab