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