mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2025-01-18 10:57:10 -05:00
20.0: June 2024 ASB picks
Signed-off-by: Tavi <tavi@divested.dev>
This commit is contained in:
parent
0d7fbddc87
commit
7f00fd1dde
@ -1,162 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Valentin Iftime <valiiftime@google.com>
|
||||
Date: Mon, 16 Oct 2023 09:29:17 +0200
|
||||
Subject: [PATCH] Prioritize system toasts
|
||||
|
||||
Insert toasts from system packages at the front of the queue
|
||||
to ensure that apps can't spam with toast to delay system toasts from showing.
|
||||
Also increase Clipboard paste warning toasts length to LENGTH_LONG.
|
||||
|
||||
Test: atest NotificationManagerServiceTest
|
||||
Bug: 293301736
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:58d89b491668663963e66906196fd93b9c73ee80)
|
||||
Merged-In: I13547f853476bc88d12026c545aba9f857ce8724
|
||||
Change-Id: I13547f853476bc88d12026c545aba9f857ce8724
|
||||
---
|
||||
.../server/clipboard/ClipboardService.java | 2 +-
|
||||
.../NotificationManagerService.java | 32 ++++++++-
|
||||
.../NotificationManagerServiceTest.java | 68 +++++++++++++++++++
|
||||
3 files changed, 99 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
|
||||
index 093ecd57124f..18f397551be8 100644
|
||||
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
|
||||
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
|
||||
@@ -1006,7 +1006,7 @@ public class ClipboardService extends SystemService {
|
||||
getContext().getString(R.string.pasted_from_clipboard, callingAppLabel);
|
||||
Slog.i(TAG, message);
|
||||
Toast.makeText(
|
||||
- getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
|
||||
+ getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// do nothing
|
||||
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
index 1044611e1dad..438d7f67d775 100755
|
||||
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
@@ -3224,8 +3224,19 @@ public class NotificationManagerService extends SystemService {
|
||||
null /* options */);
|
||||
record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token,
|
||||
text, callback, duration, windowToken, displayId, textCallback);
|
||||
- mToastQueue.add(record);
|
||||
- index = mToastQueue.size() - 1;
|
||||
+
|
||||
+ // Insert system toasts at the front of the queue
|
||||
+ int systemToastInsertIdx = mToastQueue.size();
|
||||
+ if (isSystemToast) {
|
||||
+ systemToastInsertIdx = getInsertIndexForSystemToastLocked();
|
||||
+ }
|
||||
+ if (systemToastInsertIdx < mToastQueue.size()) {
|
||||
+ index = systemToastInsertIdx;
|
||||
+ mToastQueue.add(index, record);
|
||||
+ } else {
|
||||
+ mToastQueue.add(record);
|
||||
+ index = mToastQueue.size() - 1;
|
||||
+ }
|
||||
keepProcessAliveForToastIfNeededLocked(callingPid);
|
||||
}
|
||||
// If it's at index 0, it's the current toast. It doesn't matter if it's
|
||||
@@ -3241,6 +3252,23 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
+ @GuardedBy("mToastQueue")
|
||||
+ private int getInsertIndexForSystemToastLocked() {
|
||||
+ // If there are other system toasts: insert after the last one
|
||||
+ int idx = 0;
|
||||
+ for (ToastRecord r : mToastQueue) {
|
||||
+ if (idx == 0 && mIsCurrentToastShown) {
|
||||
+ idx++;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!r.isSystemToast) {
|
||||
+ return idx;
|
||||
+ }
|
||||
+ idx++;
|
||||
+ }
|
||||
+ return idx;
|
||||
+ }
|
||||
+
|
||||
private boolean checkCanEnqueueToast(String pkg, int callingUid,
|
||||
boolean isAppRenderedToast, boolean isSystemToast) {
|
||||
final boolean isPackageSuspended = isPackagePaused(pkg);
|
||||
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
index dff3a1623403..afe3f4e93521 100755
|
||||
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
@@ -6125,6 +6125,74 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size());
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void testPrioritizeSystemToasts() throws Exception {
|
||||
+ // Insert non-system toasts
|
||||
+ final String testPackage = "testPackageName";
|
||||
+ assertEquals(0, mService.mToastQueue.size());
|
||||
+ mService.isSystemUid = false;
|
||||
+ mService.isSystemAppId = false;
|
||||
+ setToastRateIsWithinQuota(true);
|
||||
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
|
||||
+
|
||||
+ // package is not suspended
|
||||
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(false);
|
||||
+
|
||||
+ INotificationManager nmService = (INotificationManager) mService.mService;
|
||||
+
|
||||
+ // Enqueue maximum number of toasts for test package
|
||||
+ for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
|
||||
+ nmService.enqueueTextToast(testPackage, new Binder(), "Text", 2000, 0, null);
|
||||
+ }
|
||||
+
|
||||
+ // Enqueue system toast
|
||||
+ final String testPackageSystem = "testPackageNameSystem";
|
||||
+ mService.isSystemUid = true;
|
||||
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false);
|
||||
+ when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(false);
|
||||
+
|
||||
+ nmService.enqueueToast(testPackageSystem, new Binder(), new TestableToastCallback(), 2000, 0);
|
||||
+
|
||||
+ // System toast is inserted at the front of the queue, behind current showing toast
|
||||
+ assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg);
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception {
|
||||
+ // Insert system toasts
|
||||
+ final String testPackageSystem1 = "testPackageNameSystem1";
|
||||
+ assertEquals(0, mService.mToastQueue.size());
|
||||
+ mService.isSystemUid = true;
|
||||
+ setToastRateIsWithinQuota(true);
|
||||
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false);
|
||||
+
|
||||
+ // package is not suspended
|
||||
+ when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(false);
|
||||
+
|
||||
+ INotificationManager nmService = (INotificationManager) mService.mService;
|
||||
+
|
||||
+ // Enqueue maximum number of toasts for test package
|
||||
+ for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) {
|
||||
+ nmService.enqueueTextToast(testPackageSystem1, new Binder(), "Text", 2000, 0, null);
|
||||
+ }
|
||||
+
|
||||
+ // Enqueue another system toast
|
||||
+ final String testPackageSystem2 = "testPackageNameSystem2";
|
||||
+ mService.isSystemUid = true;
|
||||
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false);
|
||||
+ when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(false);
|
||||
+
|
||||
+ nmService.enqueueToast(testPackageSystem2, new Binder(), new TestableToastCallback(), 2000, 0);
|
||||
+
|
||||
+ // System toast is inserted at the back of the queue, after the other system toasts
|
||||
+ assertEquals(testPackageSystem2,
|
||||
+ mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg);
|
||||
+ }
|
||||
+
|
||||
private void setAppInForegroundForToasts(int uid, boolean inForeground) {
|
||||
int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE;
|
||||
when(mActivityManager.getUidImportance(mUid)).thenReturn(importance);
|
225
Patches/LineageOS-20.0/ASB-2024-06/fwb-01.patch
Normal file
225
Patches/LineageOS-20.0/ASB-2024-06/fwb-01.patch
Normal file
@ -0,0 +1,225 @@
|
||||
From 42c9c06f9c0f8d7212284c6555e3ffd25bd4ddbf Mon Sep 17 00:00:00 2001
|
||||
From: Pinyao Ting <pinyaoting@google.com>
|
||||
Date: Thu, 30 Nov 2023 23:12:39 +0000
|
||||
Subject: [PATCH] Added throttle when reporting shortcut usage
|
||||
|
||||
Bug: 304290201
|
||||
Test: manual
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bd88f35c6797b1795d1150af92760531ff73f14f)
|
||||
Merged-In: I96370cbd4f6a55f894c1a93307e5f82dfd394652
|
||||
Change-Id: I96370cbd4f6a55f894c1a93307e5f82dfd394652
|
||||
---
|
||||
.../android/server/pm/ShortcutPackage.java | 32 +++++++++++
|
||||
.../android/server/pm/ShortcutService.java | 18 ++----
|
||||
.../server/pm/ShortcutManagerTest1.java | 55 ++++++++++++++++++-
|
||||
.../server/pm/ShortcutManagerTest2.java | 2 +
|
||||
4 files changed, 92 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
|
||||
index 5a662d9f3139..3b3c11e1209d 100644
|
||||
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
|
||||
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
|
||||
@@ -33,6 +33,7 @@
|
||||
import android.app.appsearch.SearchResults;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
import android.app.appsearch.SetSchemaRequest;
|
||||
+import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -47,6 +48,7 @@
|
||||
import android.os.Binder;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.StrictMode;
|
||||
+import android.os.SystemClock;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -160,6 +162,9 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
private static final String KEY_BITMAPS = "bitmaps";
|
||||
private static final String KEY_BITMAP_BYTES = "bitmapBytes";
|
||||
|
||||
+ @VisibleForTesting
|
||||
+ public static final int REPORT_USAGE_BUFFER_SIZE = 3;
|
||||
+
|
||||
private final Executor mExecutor;
|
||||
|
||||
/**
|
||||
@@ -195,6 +200,9 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
|
||||
private long mLastKnownForegroundElapsedTime;
|
||||
|
||||
+ @GuardedBy("mLock")
|
||||
+ private List<Long> mLastReportedTime = new ArrayList<>();
|
||||
+
|
||||
@GuardedBy("mLock")
|
||||
private boolean mIsAppSearchSchemaUpToDate;
|
||||
|
||||
@@ -1677,6 +1685,30 @@ public boolean hasNonManifestShortcuts() {
|
||||
return condition[0];
|
||||
}
|
||||
|
||||
+ void reportShortcutUsed(@NonNull final UsageStatsManagerInternal usageStatsManagerInternal,
|
||||
+ @NonNull final String shortcutId) {
|
||||
+ synchronized (mLock) {
|
||||
+ final long currentTS = SystemClock.elapsedRealtime();
|
||||
+ final ShortcutService s = mShortcutUser.mService;
|
||||
+ if (mLastReportedTime.isEmpty()
|
||||
+ || mLastReportedTime.size() < REPORT_USAGE_BUFFER_SIZE) {
|
||||
+ mLastReportedTime.add(currentTS);
|
||||
+ } else if (currentTS - mLastReportedTime.get(0) > s.mSaveDelayMillis) {
|
||||
+ mLastReportedTime.remove(0);
|
||||
+ mLastReportedTime.add(currentTS);
|
||||
+ } else {
|
||||
+ return;
|
||||
+ }
|
||||
+ final long token = s.injectClearCallingIdentity();
|
||||
+ try {
|
||||
+ usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId,
|
||||
+ getUser().getUserId());
|
||||
+ } finally {
|
||||
+ s.injectRestoreCallingIdentity(token);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
|
||||
pw.println();
|
||||
|
||||
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
|
||||
index 7fd32d2a6b1b..84eb799e31ff 100644
|
||||
--- a/services/core/java/com/android/server/pm/ShortcutService.java
|
||||
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
|
||||
@@ -365,7 +365,7 @@ public boolean test(PackageInfo pi) {
|
||||
private CompressFormat mIconPersistFormat;
|
||||
private int mIconPersistQuality;
|
||||
|
||||
- private int mSaveDelayMillis;
|
||||
+ int mSaveDelayMillis;
|
||||
|
||||
private final IPackageManager mIPackageManager;
|
||||
private final PackageManagerInternal mPackageManagerInternal;
|
||||
@@ -2269,7 +2269,7 @@ public void pushDynamicShortcut(String packageName, ShortcutInfo shortcut,
|
||||
|
||||
packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
|
||||
|
||||
- reportShortcutUsedInternal(packageName, shortcut.getId(), userId);
|
||||
+ ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId());
|
||||
|
||||
verifyStates();
|
||||
}
|
||||
@@ -2676,25 +2676,17 @@ public void reportShortcutUsed(String packageName, String shortcutId, int userId
|
||||
Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d",
|
||||
shortcutId, packageName, userId));
|
||||
}
|
||||
+ final ShortcutPackage ps;
|
||||
synchronized (mLock) {
|
||||
throwIfUserLockedL(userId);
|
||||
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
|
||||
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
|
||||
if (ps.findShortcutById(shortcutId) == null) {
|
||||
Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
|
||||
packageName, shortcutId));
|
||||
return;
|
||||
}
|
||||
}
|
||||
- reportShortcutUsedInternal(packageName, shortcutId, userId);
|
||||
- }
|
||||
-
|
||||
- private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) {
|
||||
- final long token = injectClearCallingIdentity();
|
||||
- try {
|
||||
- mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
|
||||
- } finally {
|
||||
- injectRestoreCallingIdentity(token);
|
||||
- }
|
||||
+ ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcutId);
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
|
||||
index 867890f938ba..0f00fb877afe 100644
|
||||
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
|
||||
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
|
||||
@@ -402,8 +402,8 @@ public void testAddDynamicShortcuts() {
|
||||
|
||||
public void testPushDynamicShortcut() {
|
||||
// Change the max number of shortcuts.
|
||||
- mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5");
|
||||
-
|
||||
+ mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5,"
|
||||
+ + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
|
||||
final ShortcutInfo s1 = makeShortcut("s1");
|
||||
@@ -541,6 +541,57 @@ public void testPushDynamicShortcut() {
|
||||
eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0));
|
||||
}
|
||||
|
||||
+ public void testPushDynamicShortcut_CallsToUsageStatsManagerAreThrottled()
|
||||
+ throws InterruptedException {
|
||||
+ mService.updateConfigurationLocked(
|
||||
+ ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=500");
|
||||
+
|
||||
+ // Verify calls to UsageStatsManagerInternal#reportShortcutUsage are throttled.
|
||||
+ setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
+ for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) {
|
||||
+ final ShortcutInfo si = makeShortcut("s" + i);
|
||||
+ mManager.pushDynamicShortcut(si);
|
||||
+ }
|
||||
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
|
||||
+ eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0));
|
||||
+ Mockito.reset(mMockUsageStatsManagerInternal);
|
||||
+ for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) {
|
||||
+ final ShortcutInfo si = makeShortcut("s" + i);
|
||||
+ mManager.pushDynamicShortcut(si);
|
||||
+ }
|
||||
+ verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
|
||||
+ any(), any(), anyInt());
|
||||
+
|
||||
+ // Verify pkg2 isn't blocked by pkg1, but consecutive calls from pkg2 are throttled as well.
|
||||
+ setCaller(CALLING_PACKAGE_2, USER_0);
|
||||
+ for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) {
|
||||
+ final ShortcutInfo si = makeShortcut("s" + i);
|
||||
+ mManager.pushDynamicShortcut(si);
|
||||
+ }
|
||||
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
|
||||
+ eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0));
|
||||
+ Mockito.reset(mMockUsageStatsManagerInternal);
|
||||
+ for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) {
|
||||
+ final ShortcutInfo si = makeShortcut("s" + i);
|
||||
+ mManager.pushDynamicShortcut(si);
|
||||
+ }
|
||||
+ verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
|
||||
+ any(), any(), anyInt());
|
||||
+
|
||||
+ Mockito.reset(mMockUsageStatsManagerInternal);
|
||||
+ // Let time passes which resets the throttle
|
||||
+ Thread.sleep(505);
|
||||
+ // Verify UsageStatsManagerInternal#reportShortcutUsed can be called again
|
||||
+ setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
+ mManager.pushDynamicShortcut(makeShortcut("s10"));
|
||||
+ setCaller(CALLING_PACKAGE_2, USER_0);
|
||||
+ mManager.pushDynamicShortcut(makeShortcut("s10"));
|
||||
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
|
||||
+ eq(CALLING_PACKAGE_1), any(), eq(USER_0));
|
||||
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
|
||||
+ eq(CALLING_PACKAGE_2), any(), eq(USER_0));
|
||||
+ }
|
||||
+
|
||||
public void testUnlimitedCalls() {
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
|
||||
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
|
||||
index 86d4655e9d3a..ea134dc66e3f 100644
|
||||
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
|
||||
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
|
||||
@@ -2175,6 +2175,8 @@ public void testThrottling_resetByInternalCall() throws Exception {
|
||||
|
||||
public void testReportShortcutUsed() {
|
||||
mRunningUsers.put(USER_10, true);
|
||||
+ mService.updateConfigurationLocked(
|
||||
+ ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
|
||||
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
|
||||
reset(mMockUsageStatsManagerInternal);
|
134
Patches/LineageOS-20.0/ASB-2024-06/fwb-02.patch
Normal file
134
Patches/LineageOS-20.0/ASB-2024-06/fwb-02.patch
Normal file
@ -0,0 +1,134 @@
|
||||
From c0c16283997bbca63edc79d820652587cbde15bb Mon Sep 17 00:00:00 2001
|
||||
From: Valentin Iftime <valiiftime@google.com>
|
||||
Date: Thu, 1 Feb 2024 13:58:49 +0100
|
||||
Subject: [PATCH] Verify URI permission for channel sound update from
|
||||
NotificationListenerService
|
||||
|
||||
Check that a privileged NotificationListenerService (CDM) has the permission to access the sound URI
|
||||
when updating a notification channel.
|
||||
|
||||
Test: atest com.android.server.notification.NotificationManagerServiceTest#testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission
|
||||
Bug: 317357401
|
||||
(cherry picked from commit 9b7bbbf5ad542ecf9ecbf8cd819b468791b443c0)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2f26c0def503d3b8032c99adc8a11be87e35cdeb)
|
||||
Merged-In: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
|
||||
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
|
||||
---
|
||||
.../NotificationManagerService.java | 22 +++++++
|
||||
.../NotificationManagerServiceTest.java | 63 +++++++++++++++++++
|
||||
2 files changed, 85 insertions(+)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
index ecd446519c09..4d1abc61aa73 100755
|
||||
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||
@@ -5705,6 +5705,10 @@ public void updateNotificationChannelFromPrivilegedListener(INotificationListene
|
||||
Objects.requireNonNull(user);
|
||||
|
||||
verifyPrivilegedListener(token, user, false);
|
||||
+
|
||||
+ final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
|
||||
+ pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true);
|
||||
+ verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel);
|
||||
updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
|
||||
}
|
||||
|
||||
@@ -5796,6 +5800,24 @@ private void verifyPrivilegedListener(INotificationListener token, UserHandle us
|
||||
}
|
||||
}
|
||||
|
||||
+ private void verifyPrivilegedListenerUriPermission(int sourceUid,
|
||||
+ @NonNull NotificationChannel updateChannel,
|
||||
+ @Nullable NotificationChannel originalChannel) {
|
||||
+ // Check that the NLS has the required permissions to access the channel
|
||||
+ final Uri soundUri = updateChannel.getSound();
|
||||
+ final Uri originalSoundUri =
|
||||
+ (originalChannel != null) ? originalChannel.getSound() : null;
|
||||
+ if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
|
||||
+ Binder.withCleanCallingIdentity(() -> {
|
||||
+ mUgmInternal.checkGrantUriPermission(sourceUid, null,
|
||||
+ ContentProvider.getUriWithoutUserId(soundUri),
|
||||
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
|
||||
+ ContentProvider.getUserIdFromUri(soundUri,
|
||||
+ UserHandle.getUserId(sourceUid)));
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
|
||||
int uid = INVALID_UID;
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
index 4f0a7ca0ad51..755bc1d35cf3 100755
|
||||
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||
@@ -3319,6 +3319,69 @@ public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws
|
||||
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
|
||||
+ throws Exception {
|
||||
+ mService.setPreferencesHelper(mPreferencesHelper);
|
||||
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
|
||||
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
||||
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
||||
+ .thenReturn(mTestNotificationChannel);
|
||||
+
|
||||
+ final Uri soundUri = Uri.parse("content://media/test/sound/uri");
|
||||
+ final NotificationChannel updatedNotificationChannel = new NotificationChannel(
|
||||
+ TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
|
||||
+ updatedNotificationChannel.setSound(soundUri,
|
||||
+ updatedNotificationChannel.getAudioAttributes());
|
||||
+
|
||||
+ doThrow(new SecurityException("no access")).when(mUgmInternal)
|
||||
+ .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
|
||||
+ anyInt(), eq(Process.myUserHandle().getIdentifier()));
|
||||
+
|
||||
+ assertThrows(SecurityException.class,
|
||||
+ () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, PKG,
|
||||
+ Process.myUserHandle(), updatedNotificationChannel));
|
||||
+
|
||||
+ verify(mPreferencesHelper, never()).updateNotificationChannel(
|
||||
+ anyString(), anyInt(), any(), anyBoolean());
|
||||
+
|
||||
+ verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
|
||||
+ eq(Process.myUserHandle()), eq(mTestNotificationChannel),
|
||||
+ eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
|
||||
+ throws Exception {
|
||||
+ mService.setPreferencesHelper(mPreferencesHelper);
|
||||
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
||||
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
|
||||
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
||||
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
||||
+ .thenReturn(mTestNotificationChannel);
|
||||
+
|
||||
+ final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
|
||||
+ final NotificationChannel updatedNotificationChannel = new NotificationChannel(
|
||||
+ TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
|
||||
+ updatedNotificationChannel.setSound(soundUri,
|
||||
+ updatedNotificationChannel.getAudioAttributes());
|
||||
+
|
||||
+ doThrow(new SecurityException("no access")).when(mUgmInternal)
|
||||
+ .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
|
||||
+ anyInt(), eq(Process.myUserHandle().getIdentifier()));
|
||||
+
|
||||
+ mBinderService.updateNotificationChannelFromPrivilegedListener(
|
||||
+ null, PKG, Process.myUserHandle(), updatedNotificationChannel);
|
||||
+
|
||||
+ verify(mPreferencesHelper, times(1)).updateNotificationChannel(
|
||||
+ anyString(), anyInt(), any(), anyBoolean());
|
||||
+
|
||||
+ verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
|
||||
+ eq(Process.myUserHandle()), eq(mTestNotificationChannel),
|
||||
+ eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
|
||||
+ }
|
||||
+
|
||||
@Test
|
||||
public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
463
Patches/LineageOS-20.0/ASB-2024-06/fwb-03.patch
Normal file
463
Patches/LineageOS-20.0/ASB-2024-06/fwb-03.patch
Normal file
@ -0,0 +1,463 @@
|
||||
From fcb02396749ec9318803887febffea13f726dfc2 Mon Sep 17 00:00:00 2001
|
||||
From: Valentin Iftime <valiiftime@google.com>
|
||||
Date: Thu, 22 Feb 2024 10:51:58 +0100
|
||||
Subject: [PATCH] Check for NLS bind permission when rebinding services
|
||||
|
||||
Also, after updating packages with NLS components, check
|
||||
the approved services and remove from approved list if missing permissions.
|
||||
|
||||
Test: atest ManagedServicesTest
|
||||
Bug: 321707289
|
||||
|
||||
(cherry picked from commit 24b13a64f9f5e5aa7f45a2132806d6c74e2c62dc)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f126be35f4b9f179dbb957ec56ca80b12f47abdc)
|
||||
Merged-In: I11901755ec430c6e3145def9d67e4e63cda00806
|
||||
Change-Id: I11901755ec430c6e3145def9d67e4e63cda00806
|
||||
---
|
||||
.../server/notification/ManagedServices.java | 193 ++++++++++--------
|
||||
.../notification/ManagedServicesTest.java | 54 +++++
|
||||
2 files changed, 164 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
|
||||
index d0cfa164b5af..c3691e717e9b 100644
|
||||
--- a/services/core/java/com/android/server/notification/ManagedServices.java
|
||||
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
|
||||
@@ -132,7 +132,6 @@ abstract public class ManagedServices {
|
||||
|
||||
// contains connections to all connected services, including app services
|
||||
// and system services
|
||||
- @GuardedBy("mMutex")
|
||||
private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
|
||||
/**
|
||||
* The services that have been bound by us. If the service is also connected, it will also
|
||||
@@ -151,15 +150,13 @@ abstract public class ManagedServices {
|
||||
= new ArraySet<>();
|
||||
// Just the packages from mEnabledServicesForCurrentProfiles
|
||||
private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
|
||||
- // Per user id, list of enabled packages that have nevertheless asked not to be run
|
||||
- private final android.util.SparseSetArray<ComponentName> mSnoozing =
|
||||
- new android.util.SparseSetArray<>();
|
||||
+ // List of enabled packages that have nevertheless asked not to be run
|
||||
+ private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
|
||||
|
||||
// List of approved packages or components (by user, then by primary/secondary) that are
|
||||
// allowed to be bound as managed services. A package or component appearing in this list does
|
||||
// not mean that we are currently bound to said package/component.
|
||||
- protected final ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved =
|
||||
- new ArrayMap<>();
|
||||
+ protected ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
|
||||
|
||||
// List of packages or components (by user) that are configured to be enabled/disabled
|
||||
// explicitly by the user
|
||||
@@ -318,7 +315,6 @@ ArrayMap<Boolean, ArrayList<ComponentName>> resetComponents(String packageName,
|
||||
return changes;
|
||||
}
|
||||
|
||||
- @GuardedBy("mApproved")
|
||||
private boolean clearUserSetFlagLocked(ComponentName component, int userId) {
|
||||
String approvedValue = getApprovedValue(component.flattenToString());
|
||||
ArraySet<String> userSet = mUserSetServices.get(userId);
|
||||
@@ -379,8 +375,8 @@ public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
pw.println(" " + cmpt);
|
||||
}
|
||||
|
||||
+ pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
|
||||
synchronized (mMutex) {
|
||||
- pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
|
||||
for (ManagedServiceInfo info : mServices) {
|
||||
if (filter != null && !filter.matches(info.component)) continue;
|
||||
pw.println(" " + info.component
|
||||
@@ -390,15 +386,10 @@ public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
}
|
||||
}
|
||||
|
||||
- synchronized (mSnoozing) {
|
||||
- pw.println(" Snoozed " + getCaption() + "s ("
|
||||
- + mSnoozing.size() + "):");
|
||||
- for (int i = 0; i < mSnoozing.size(); i++) {
|
||||
- pw.println(" User: " + mSnoozing.keyAt(i));
|
||||
- for (ComponentName name : mSnoozing.valuesAt(i)) {
|
||||
- pw.println(" " + name.flattenToShortString());
|
||||
- }
|
||||
- }
|
||||
+ pw.println(" Snoozed " + getCaption() + "s (" +
|
||||
+ mSnoozingForCurrentProfiles.size() + "):");
|
||||
+ for (ComponentName name : mSnoozingForCurrentProfiles) {
|
||||
+ pw.println(" " + name.flattenToShortString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,16 +431,8 @@ public void dump(ProtoOutputStream proto, DumpFilter filter) {
|
||||
}
|
||||
}
|
||||
|
||||
- synchronized (mSnoozing) {
|
||||
- for (int i = 0; i < mSnoozing.size(); i++) {
|
||||
- long token = proto.start(ManagedServicesProto.SNOOZED);
|
||||
- proto.write(ManagedServicesProto.SnoozedServices.USER_ID,
|
||||
- mSnoozing.keyAt(i));
|
||||
- for (ComponentName name : mSnoozing.valuesAt(i)) {
|
||||
- name.dumpDebug(proto, ManagedServicesProto.SnoozedServices.SNOOZED);
|
||||
- }
|
||||
- proto.end(token);
|
||||
- }
|
||||
+ for (ComponentName name : mSnoozingForCurrentProfiles) {
|
||||
+ name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,6 +901,23 @@ protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId)
|
||||
return false;
|
||||
}
|
||||
|
||||
+ protected boolean isPackageOrComponentAllowedWithPermission(ComponentName component,
|
||||
+ int userId) {
|
||||
+ if (!(isPackageOrComponentAllowed(component.flattenToString(), userId)
|
||||
+ || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return componentHasBindPermission(component, userId);
|
||||
+ }
|
||||
+
|
||||
+ private boolean componentHasBindPermission(ComponentName component, int userId) {
|
||||
+ ServiceInfo info = getServiceInfo(component, userId);
|
||||
+ if (info == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return mConfig.bindPermission.equals(info.permission);
|
||||
+ }
|
||||
+
|
||||
boolean isPackageOrComponentUserSet(String pkgOrComponent, int userId) {
|
||||
synchronized (mApproved) {
|
||||
ArraySet<String> services = mUserSetServices.get(userId);
|
||||
@@ -975,6 +975,7 @@ public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] u
|
||||
for (int uid : uidList) {
|
||||
if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
|
||||
anyServicesInvolved = true;
|
||||
+ trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -992,9 +993,6 @@ public void onUserRemoved(int user) {
|
||||
synchronized (mApproved) {
|
||||
mApproved.remove(user);
|
||||
}
|
||||
- synchronized (mSnoozing) {
|
||||
- mSnoozing.remove(user);
|
||||
- }
|
||||
rebindServices(true, user);
|
||||
}
|
||||
|
||||
@@ -1014,12 +1012,10 @@ private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
|
||||
return null;
|
||||
}
|
||||
final IBinder token = service.asBinder();
|
||||
- synchronized (mMutex) {
|
||||
- final int nServices = mServices.size();
|
||||
- for (int i = 0; i < nServices; i++) {
|
||||
- final ManagedServiceInfo info = mServices.get(i);
|
||||
- if (info.service.asBinder() == token) return info;
|
||||
- }
|
||||
+ final int N = mServices.size();
|
||||
+ for (int i = 0; i < N; i++) {
|
||||
+ final ManagedServiceInfo info = mServices.get(i);
|
||||
+ if (info.service.asBinder() == token) return info;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1094,17 +1090,15 @@ protected void registerGuestService(ManagedServiceInfo guest) {
|
||||
}
|
||||
|
||||
protected void setComponentState(ComponentName component, int userId, boolean enabled) {
|
||||
- synchronized (mSnoozing) {
|
||||
- boolean previous = !mSnoozing.contains(userId, component);
|
||||
- if (previous == enabled) {
|
||||
- return;
|
||||
- }
|
||||
+ boolean previous = !mSnoozingForCurrentProfiles.contains(component);
|
||||
+ if (previous == enabled) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- if (enabled) {
|
||||
- mSnoozing.remove(userId, component);
|
||||
- } else {
|
||||
- mSnoozing.add(userId, component);
|
||||
- }
|
||||
+ if (enabled) {
|
||||
+ mSnoozingForCurrentProfiles.remove(component);
|
||||
+ } else {
|
||||
+ mSnoozingForCurrentProfiles.add(component);
|
||||
}
|
||||
|
||||
// State changed
|
||||
@@ -1113,8 +1107,7 @@ protected void setComponentState(ComponentName component, int userId, boolean en
|
||||
|
||||
synchronized (mMutex) {
|
||||
if (enabled) {
|
||||
- if (isPackageOrComponentAllowed(component.flattenToString(), userId)
|
||||
- || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
|
||||
+ if (isPackageOrComponentAllowedWithPermission(component, userId)) {
|
||||
registerServiceLocked(component, userId);
|
||||
} else {
|
||||
Slog.d(TAG, component + " no longer has permission to be bound");
|
||||
@@ -1252,6 +1245,33 @@ private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, S
|
||||
return removed;
|
||||
}
|
||||
|
||||
+ private void trimApprovedListsForInvalidServices(String packageName, int userId) {
|
||||
+ synchronized (mApproved) {
|
||||
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
|
||||
+ if (approvedByType == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ for (int i = 0; i < approvedByType.size(); i++) {
|
||||
+ final ArraySet<String> approved = approvedByType.valueAt(i);
|
||||
+ for (int j = approved.size() - 1; j >= 0; j--) {
|
||||
+ final String approvedPackageOrComponent = approved.valueAt(j);
|
||||
+ if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
|
||||
+ final ComponentName component = ComponentName.unflattenFromString(
|
||||
+ approvedPackageOrComponent);
|
||||
+ if (component != null && !componentHasBindPermission(component, userId)) {
|
||||
+ approved.removeAt(j);
|
||||
+ if (DEBUG) {
|
||||
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
|
||||
+ + " from approved list; no bind permission found "
|
||||
+ + mConfig.bindPermission);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
protected String getPackageName(String packageOrComponent) {
|
||||
final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
|
||||
if (component != null) {
|
||||
@@ -1317,10 +1337,7 @@ protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componen
|
||||
}
|
||||
|
||||
final Set<ComponentName> add = new HashSet<>(userComponents);
|
||||
- ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
|
||||
- if (snoozed != null) {
|
||||
- add.removeAll(snoozed);
|
||||
- }
|
||||
+ add.removeAll(mSnoozingForCurrentProfiles);
|
||||
|
||||
componentsToBind.put(userId, add);
|
||||
|
||||
@@ -1438,28 +1455,20 @@ private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
|
||||
final int userId = componentsToBind.keyAt(i);
|
||||
final Set<ComponentName> add = componentsToBind.get(userId);
|
||||
for (ComponentName component : add) {
|
||||
- try {
|
||||
- ServiceInfo info = mPm.getServiceInfo(component,
|
||||
- PackageManager.GET_META_DATA
|
||||
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
|
||||
- userId);
|
||||
- if (info == null) {
|
||||
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
|
||||
- + ": service not found");
|
||||
- continue;
|
||||
- }
|
||||
- if (!mConfig.bindPermission.equals(info.permission)) {
|
||||
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
|
||||
- + ": it does not require the permission " + mConfig.bindPermission);
|
||||
- continue;
|
||||
- }
|
||||
- Slog.v(TAG,
|
||||
- "enabling " + getCaption() + " for " + userId + ": " + component);
|
||||
- registerService(info, userId);
|
||||
- } catch (RemoteException e) {
|
||||
- e.rethrowFromSystemServer();
|
||||
+ ServiceInfo info = getServiceInfo(component, userId);
|
||||
+ if (info == null) {
|
||||
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
|
||||
+ + ": service not found");
|
||||
+ continue;
|
||||
}
|
||||
+ if (!mConfig.bindPermission.equals(info.permission)) {
|
||||
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
|
||||
+ + ": it does not require the permission " + mConfig.bindPermission);
|
||||
+ continue;
|
||||
+ }
|
||||
+ Slog.v(TAG,
|
||||
+ "enabling " + getCaption() + " for " + userId + ": " + component);
|
||||
+ registerService(info, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1484,8 +1493,7 @@ void registerService(final ComponentName cn, final int userId) {
|
||||
void reregisterService(final ComponentName cn, final int userId) {
|
||||
// If rebinding a package that died, ensure it still has permission
|
||||
// after the rebind delay
|
||||
- if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
|
||||
- || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
|
||||
+ if (isPackageOrComponentAllowedWithPermission(cn, userId)) {
|
||||
registerService(cn, userId);
|
||||
}
|
||||
}
|
||||
@@ -1499,12 +1507,10 @@ public void registerSystemService(final ComponentName name, final int userid) {
|
||||
}
|
||||
}
|
||||
|
||||
- @GuardedBy("mMutex")
|
||||
private void registerServiceLocked(final ComponentName name, final int userid) {
|
||||
registerServiceLocked(name, userid, false /* isSystem */);
|
||||
}
|
||||
|
||||
- @GuardedBy("mMutex")
|
||||
private void registerServiceLocked(final ComponentName name, final int userid,
|
||||
final boolean isSystem) {
|
||||
if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
|
||||
@@ -1590,9 +1596,12 @@ public void onBindingDied(ComponentName name) {
|
||||
unbindService(this, name, userid);
|
||||
if (!mServicesRebinding.contains(servicesBindingTag)) {
|
||||
mServicesRebinding.add(servicesBindingTag);
|
||||
- mHandler.postDelayed(() ->
|
||||
- reregisterService(name, userid),
|
||||
- ON_BINDING_DIED_REBIND_DELAY_MS);
|
||||
+ mHandler.postDelayed(new Runnable() {
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ reregisterService(name, userid);
|
||||
+ }
|
||||
+ }, ON_BINDING_DIED_REBIND_DELAY_MS);
|
||||
} else {
|
||||
Slog.v(TAG, getCaption() + " not rebinding in user " + userid
|
||||
+ " as a previous rebind attempt was made: " + name);
|
||||
@@ -1635,7 +1644,6 @@ private void unregisterService(ComponentName name, int userid) {
|
||||
}
|
||||
}
|
||||
|
||||
- @GuardedBy("mMutex")
|
||||
private void unregisterServiceLocked(ComponentName name, int userid) {
|
||||
final int N = mServices.size();
|
||||
for (int i = N - 1; i >= 0; i--) {
|
||||
@@ -1670,7 +1678,6 @@ private ManagedServiceInfo removeServiceImpl(IInterface service, final int useri
|
||||
return serviceInfo;
|
||||
}
|
||||
|
||||
- @GuardedBy("mMutex")
|
||||
private ManagedServiceInfo removeServiceLocked(int i) {
|
||||
final ManagedServiceInfo info = mServices.remove(i);
|
||||
onServiceRemovedLocked(info);
|
||||
@@ -1724,6 +1731,19 @@ private void unbindService(ServiceConnection connection, ComponentName component
|
||||
}
|
||||
}
|
||||
|
||||
+ private ServiceInfo getServiceInfo(ComponentName component, int userId) {
|
||||
+ try {
|
||||
+ return mPm.getServiceInfo(component,
|
||||
+ PackageManager.GET_META_DATA
|
||||
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
|
||||
+ userId);
|
||||
+ } catch (RemoteException e) {
|
||||
+ e.rethrowFromSystemServer();
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
public class ManagedServiceInfo implements IBinder.DeathRecipient {
|
||||
public IInterface service;
|
||||
public ComponentName component;
|
||||
@@ -1823,7 +1843,7 @@ public boolean isEnabledForCurrentProfiles() {
|
||||
* from receiving events from the profile.
|
||||
*/
|
||||
public boolean isPermittedForProfile(int userId) {
|
||||
- if (!mUserProfiles.isProfileUser(userId)) {
|
||||
+ if (!mUserProfiles.isManagedProfile(userId)) {
|
||||
return true;
|
||||
}
|
||||
DevicePolicyManager dpm =
|
||||
@@ -1899,6 +1919,13 @@ public boolean isCurrentProfile(int userId) {
|
||||
}
|
||||
}
|
||||
|
||||
+ public boolean isManagedProfile(int userId) {
|
||||
+ synchronized (mCurrentProfiles) {
|
||||
+ UserInfo user = mCurrentProfiles.get(userId);
|
||||
+ return user != null && user.isManagedProfile();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public boolean isProfileUser(int userId) {
|
||||
synchronized (mCurrentProfiles) {
|
||||
UserInfo user = mCurrentProfiles.get(userId);
|
||||
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
|
||||
index 8b1384ed894f..7c7bb509ebb4 100644
|
||||
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
|
||||
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
|
||||
@@ -33,8 +33,10 @@
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.eq;
|
||||
+import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
+import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -1117,6 +1119,58 @@ public void testUpgradeAppBindsNewServices() throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void testUpgradeAppNoPermissionNoRebind() throws Exception {
|
||||
+ Context context = spy(getContext());
|
||||
+ doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
|
||||
+
|
||||
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
|
||||
+ mIpm,
|
||||
+ APPROVAL_BY_COMPONENT);
|
||||
+
|
||||
+ List<String> packages = new ArrayList<>();
|
||||
+ packages.add("package");
|
||||
+ addExpectedServices(service, packages, 0);
|
||||
+
|
||||
+ final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
|
||||
+ final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
|
||||
+
|
||||
+ // Both components are approved initially
|
||||
+ mExpectedPrimaryComponentNames.clear();
|
||||
+ mExpectedPrimaryPackages.clear();
|
||||
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
|
||||
+ mExpectedSecondaryComponentNames.clear();
|
||||
+ mExpectedSecondaryPackages.clear();
|
||||
+
|
||||
+ loadXml(service);
|
||||
+
|
||||
+ //Component package/C1 loses bind permission
|
||||
+ when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
|
||||
+ (Answer<ServiceInfo>) invocation -> {
|
||||
+ ComponentName invocationCn = invocation.getArgument(0);
|
||||
+ if (invocationCn != null) {
|
||||
+ ServiceInfo serviceInfo = new ServiceInfo();
|
||||
+ serviceInfo.packageName = invocationCn.getPackageName();
|
||||
+ serviceInfo.name = invocationCn.getClassName();
|
||||
+ if (invocationCn.equals(unapprovedComponent)) {
|
||||
+ serviceInfo.permission = "none";
|
||||
+ } else {
|
||||
+ serviceInfo.permission = service.getConfig().bindPermission;
|
||||
+ }
|
||||
+ serviceInfo.metaData = null;
|
||||
+ return serviceInfo;
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+ );
|
||||
+
|
||||
+ // Trigger package update
|
||||
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
|
||||
+
|
||||
+ assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
|
||||
+ assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
|
||||
+ }
|
||||
+
|
||||
@Test
|
||||
public void testSetPackageOrComponentEnabled() throws Exception {
|
||||
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
|
31
Patches/LineageOS-20.0/ASB-2024-06/fwb-04.patch
Normal file
31
Patches/LineageOS-20.0/ASB-2024-06/fwb-04.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From 88ea616cf95aff9169daec33a0a3d93a30b15727 Mon Sep 17 00:00:00 2001
|
||||
From: Yi-an Chen <theianchen@google.com>
|
||||
Date: Wed, 21 Feb 2024 01:56:22 +0000
|
||||
Subject: [PATCH] Fix error handling for non-dynamic permissions
|
||||
|
||||
We only allow removing dynamic permissions. When removePermission() is
|
||||
called for a non-dynamic permission, in addition to logging it, we
|
||||
should also return early to avoid the removePermission() call.
|
||||
|
||||
Test: manual
|
||||
Bug: 321555066
|
||||
Fixes: 321711213
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:528a87e90ff9354581d54fd37fbe9f95cccbcdb1)
|
||||
Merged-In: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
|
||||
Change-Id: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
|
||||
---
|
||||
.../server/pm/permission/PermissionManagerServiceImpl.java | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
|
||||
index 5dc7e23c01e2..1ec3403a9d46 100644
|
||||
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
|
||||
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
|
||||
@@ -681,6 +681,7 @@ public void removePermission(String permName) {
|
||||
// TODO: switch this back to SecurityException
|
||||
Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
|
||||
+ permName);
|
||||
+ return;
|
||||
}
|
||||
mRegistry.removePermission(permName);
|
||||
}
|
71
Patches/LineageOS-20.0/ASB-2024-06/fwb-05.patch
Normal file
71
Patches/LineageOS-20.0/ASB-2024-06/fwb-05.patch
Normal file
@ -0,0 +1,71 @@
|
||||
From 091715c8307fed95ba63870f0c54e74208a78332 Mon Sep 17 00:00:00 2001
|
||||
From: Lokesh Kumar Goel <lokeshgoel@google.com>
|
||||
Date: Tue, 27 Feb 2024 23:05:05 +0000
|
||||
Subject: [PATCH] Fix vulnerability in AttributionSource due to incorrect
|
||||
Binder call
|
||||
|
||||
AttributionSource uses Binder.getCallingUid to verify the UID of the
|
||||
caller from another process. However, getCallingUid does not always
|
||||
behave as expected. If the AttributionSource is unparceled outside a
|
||||
transaction thread, which is quite possible, getCallingUid will return
|
||||
the UID of the current process instead. If this is a system process,
|
||||
the UID check gets bypassed entirely, meaning any uid can be provided.
|
||||
|
||||
This patch fixes the vulnerability by emptying out the state of the
|
||||
AttributionSource, so that the service checking its credentials will
|
||||
fail to give permission to the app.
|
||||
|
||||
Bug: 267231571
|
||||
Test: v2/android-virtual-infra/test_mapping/presubmit-avd
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5d79e535b9a802680062545e15fc1faaf779c0bf)
|
||||
Merged-In: I3f228064fbd62e1c907f1ebe870cb61102f788f0
|
||||
Change-Id: I3f228064fbd62e1c907f1ebe870cb61102f788f0
|
||||
---
|
||||
.../android/content/AttributionSource.java | 20 ++++++++++++++++---
|
||||
1 file changed, 17 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
|
||||
index 3f2fa2188d24..16b18c85e790 100644
|
||||
--- a/core/java/android/content/AttributionSource.java
|
||||
+++ b/core/java/android/content/AttributionSource.java
|
||||
@@ -31,6 +31,7 @@
|
||||
import android.os.Process;
|
||||
import android.permission.PermissionManager;
|
||||
import android.util.ArraySet;
|
||||
+import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.Immutable;
|
||||
|
||||
@@ -87,6 +88,8 @@
|
||||
*/
|
||||
@Immutable
|
||||
public final class AttributionSource implements Parcelable {
|
||||
+ private static final String TAG = "AttributionSource";
|
||||
+
|
||||
private static final String DESCRIPTOR = "android.content.AttributionSource";
|
||||
|
||||
private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
|
||||
@@ -154,9 +157,20 @@ public AttributionSource(@NonNull AttributionSource current, @Nullable Attributi
|
||||
AttributionSource(@NonNull Parcel in) {
|
||||
this(AttributionSourceState.CREATOR.createFromParcel(in));
|
||||
|
||||
- // Since we just unpacked this object as part of it transiting a Binder
|
||||
- // call, this is the perfect time to enforce that its UID and PID can be trusted
|
||||
- enforceCallingUidAndPid();
|
||||
+ if (!Binder.isDirectlyHandlingTransaction()) {
|
||||
+ Log.e(TAG, "Unable to verify calling UID #" + mAttributionSourceState.uid + " PID #"
|
||||
+ + mAttributionSourceState.pid + " when not handling Binder transaction; "
|
||||
+ + "clearing.");
|
||||
+ mAttributionSourceState.pid = -1;
|
||||
+ mAttributionSourceState.uid = -1;
|
||||
+ mAttributionSourceState.packageName = null;
|
||||
+ mAttributionSourceState.attributionTag = null;
|
||||
+ mAttributionSourceState.next = null;
|
||||
+ } else {
|
||||
+ // Since we just unpacked this object as part of it transiting a Binder
|
||||
+ // call, this is the perfect time to enforce that its UID and PID can be trusted
|
||||
+ enforceCallingUidAndPid();
|
||||
+ }
|
||||
}
|
||||
|
||||
/** @hide */
|
70
Patches/LineageOS-20.0/ASB-2024-06/fwb-06.patch
Normal file
70
Patches/LineageOS-20.0/ASB-2024-06/fwb-06.patch
Normal file
@ -0,0 +1,70 @@
|
||||
From b403e48e6aff45880c2970102555cc77cdcfe322 Mon Sep 17 00:00:00 2001
|
||||
From: Riddle Hsu <riddlehsu@google.com>
|
||||
Date: Tue, 6 Feb 2024 17:19:37 +0800
|
||||
Subject: [PATCH] Hide window immediately if itself doesn't run hide animation
|
||||
|
||||
The condition was overextended in commit 9bca6b4 which checks if the
|
||||
parent container of the window is animating. That causes the window to
|
||||
wait for animation finish to update visibility, but the animation
|
||||
finish callback won't happen because itself is not animating. Then the
|
||||
window that should be hidden remains on screen.
|
||||
|
||||
Bug: 302431573
|
||||
Test: atest WindowStateTests#testIsOnScreen_hiddenByPolicy
|
||||
(cherry picked from commit 9add9281ffc120c81a7d125892803f1beb5ddcb3)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:10a7f0914c87f4af521b5cbb13e84a83dacebf82)
|
||||
Merged-In: Iafc2b2c2a24d8fc8d147354ef2f0b4afeeb510c5
|
||||
Change-Id: Iafc2b2c2a24d8fc8d147354ef2f0b4afeeb510c5
|
||||
---
|
||||
.../com/android/server/wm/WindowState.java | 6 ++++--
|
||||
.../android/server/wm/WindowStateTests.java | 20 +++++++++++++++++++
|
||||
2 files changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
|
||||
index 6d6e84f611cf..0ba2f2f2f418 100644
|
||||
--- a/services/core/java/com/android/server/wm/WindowState.java
|
||||
+++ b/services/core/java/com/android/server/wm/WindowState.java
|
||||
@@ -3296,8 +3296,10 @@ boolean hide(boolean doAnimation, boolean requestAnim) {
|
||||
return false;
|
||||
}
|
||||
if (doAnimation) {
|
||||
- mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
|
||||
- if (!isAnimating(TRANSITION | PARENTS)) {
|
||||
+ // If a hide animation is applied, then let onAnimationFinished
|
||||
+ // -> checkPolicyVisibilityChange hide the window. Otherwise make doAnimation false
|
||||
+ // to commit invisible immediately.
|
||||
+ if (!mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false /* isEntrance */)) {
|
||||
doAnimation = false;
|
||||
}
|
||||
}
|
||||
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
|
||||
index 219f4415c623..44ae8dde9bde 100644
|
||||
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
|
||||
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
|
||||
@@ -227,6 +227,26 @@ public void testIsOnScreen_hiddenByPolicy() {
|
||||
assertTrue(window.isOnScreen());
|
||||
window.hide(false /* doAnimation */, false /* requestAnim */);
|
||||
assertFalse(window.isOnScreen());
|
||||
+
|
||||
+ // Verifies that a window without animation can be hidden even if its parent is animating.
|
||||
+ window.show(false /* doAnimation */, false /* requestAnim */);
|
||||
+ assertTrue(window.isVisibleByPolicy());
|
||||
+ window.getParent().startAnimation(mTransaction, mock(AnimationAdapter.class),
|
||||
+ false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
|
||||
+ window.mAttrs.windowAnimations = 0;
|
||||
+ window.hide(true /* doAnimation */, true /* requestAnim */);
|
||||
+ assertFalse(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
|
||||
+ assertFalse(window.isVisibleByPolicy());
|
||||
+ assertFalse(window.isOnScreen());
|
||||
+
|
||||
+ // Verifies that a window with animation can be hidden after the hide animation is finished.
|
||||
+ window.show(false /* doAnimation */, false /* requestAnim */);
|
||||
+ window.mAttrs.windowAnimations = android.R.style.Animation_Dialog;
|
||||
+ window.hide(true /* doAnimation */, true /* requestAnim */);
|
||||
+ assertTrue(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
|
||||
+ assertTrue(window.isVisibleByPolicy());
|
||||
+ window.cancelAnimation();
|
||||
+ assertFalse(window.isVisibleByPolicy());
|
||||
}
|
||||
|
||||
@Test
|
43
Patches/LineageOS-20.0/ASB-2024-06/fwb-07.patch
Normal file
43
Patches/LineageOS-20.0/ASB-2024-06/fwb-07.patch
Normal file
@ -0,0 +1,43 @@
|
||||
From ac134a1b6a0ace6bf43e83d414f6433f3cf40e53 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Dementyev <dementyev@google.com>
|
||||
Date: Tue, 26 Mar 2024 10:31:44 -0700
|
||||
Subject: [PATCH] Add more checkKeyIntent checks to AccountManagerService.
|
||||
|
||||
Another verification is needed after Bundle modification.
|
||||
Bug: 321941232
|
||||
Test: manual
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:36db8a1d61a881f89fdd3911886adcda6e1f0d7f)
|
||||
Merged-In: I9e45d758a2320328da5664b6341eafe6f285f297
|
||||
Change-Id: I9e45d758a2320328da5664b6341eafe6f285f297
|
||||
---
|
||||
.../android/server/accounts/AccountManagerService.java | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
|
||||
index 1c3564bfdba2..bc13f106ce6e 100644
|
||||
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
|
||||
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
|
||||
@@ -3561,6 +3561,11 @@ public void onResult(Bundle result) {
|
||||
|
||||
// Strip auth token from result.
|
||||
result.remove(AccountManager.KEY_AUTHTOKEN);
|
||||
+ if (!checkKeyIntent(Binder.getCallingUid(), result)) {
|
||||
+ onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
|
||||
+ "invalid intent in bundle returned");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
@@ -5146,6 +5151,11 @@ public void onResult(Bundle result) {
|
||||
} else {
|
||||
if (mStripAuthTokenFromResult) {
|
||||
result.remove(AccountManager.KEY_AUTHTOKEN);
|
||||
+ if (!checkKeyIntent(Binder.getCallingUid(), result)) {
|
||||
+ onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
|
||||
+ "invalid intent in bundle returned");
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, getClass().getSimpleName()
|
70
Patches/LineageOS-20.0/ASB-2024-06/fwb-08.patch
Normal file
70
Patches/LineageOS-20.0/ASB-2024-06/fwb-08.patch
Normal file
@ -0,0 +1,70 @@
|
||||
From 5dd0b87bc501c83abbe2462d17fcc7f9f3dfab4d Mon Sep 17 00:00:00 2001
|
||||
From: Haoran Zhang <haoranzhang@google.com>
|
||||
Date: Wed, 13 Mar 2024 17:08:00 +0000
|
||||
Subject: [PATCH] [DO NOT MERGE][Autofill Framework] Add in check for intent
|
||||
filter when setting/updating service
|
||||
|
||||
For test, I registered two tests around on ABTD. CtsAutoFillServiceTestCases module is passing except three known failures:
|
||||
|
||||
Test run link:
|
||||
- https://android-build.corp.google.com/builds/abtd/run/L33300030002610600
|
||||
- https://android-build.corp.google.com/builds/abtd/run/L58100030002616607
|
||||
|
||||
|
||||
Bug: b/324874908
|
||||
Test: atest CtsAutoFillServiceTestCases
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:141d9d050346bfc4673c429382deb1b3d210f6ad)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ee20adb4b4b2065e040167a4354c4fabaf06e35d)
|
||||
Merged-In: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
||||
Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
||||
---
|
||||
.../autofill/AutofillManagerServiceImpl.java | 27 +++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
|
||||
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
||||
index 20b2a74f5be5..2cda39d4b065 100644
|
||||
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
||||
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
||||
@@ -32,8 +32,10 @@
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.content.ComponentName;
|
||||
+import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
+import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.metrics.LogMaker;
|
||||
@@ -239,6 +241,31 @@ protected boolean updateLocked(boolean disabled) {
|
||||
@Override // from PerUserSystemService
|
||||
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
||||
throws NameNotFoundException {
|
||||
+ final List<ResolveInfo> resolveInfos =
|
||||
+ getContext().getPackageManager().queryIntentServicesAsUser(
|
||||
+ new Intent(AutofillService.SERVICE_INTERFACE),
|
||||
+ // The MATCH_INSTANT flag is added because curret autofill CTS module is
|
||||
+ // defined in one apk, which makes the test autofill service installed in a
|
||||
+ // instant app when the CTS tests are running in instant app mode.
|
||||
+ // TODO: Remove MATCH_INSTANT flag after completing refactoring the CTS module
|
||||
+ // to make the test autofill service a separate apk.
|
||||
+ PackageManager.GET_META_DATA | PackageManager.MATCH_INSTANT,
|
||||
+ mUserId);
|
||||
+ boolean serviceHasAutofillIntentFilter = false;
|
||||
+ for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||
+ if (serviceInfo.getComponentName().equals(serviceComponent)) {
|
||||
+ serviceHasAutofillIntentFilter = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!serviceHasAutofillIntentFilter) {
|
||||
+ Slog.w(TAG,
|
||||
+ "Autofill service from '" + serviceComponent.getPackageName() + "' does"
|
||||
+ + "not have intent filter " + AutofillService.SERVICE_INTERFACE);
|
||||
+ throw new SecurityException("Service does not declare intent filter "
|
||||
+ + AutofillService.SERVICE_INTERFACE);
|
||||
+ }
|
||||
mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
|
||||
return mInfo.getServiceInfo();
|
||||
}
|
47
Patches/LineageOS-20.0/ASB-2024-06/fwb-09.patch
Normal file
47
Patches/LineageOS-20.0/ASB-2024-06/fwb-09.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From d0df12d2f498f441d87852580a89f8588380d902 Mon Sep 17 00:00:00 2001
|
||||
From: Hans Boehm <hboehm@google.com>
|
||||
Date: Tue, 2 Jan 2024 16:53:13 -0800
|
||||
Subject: [PATCH] Check hidden API exemptions
|
||||
|
||||
Refuse to deal with newlines and null characters in
|
||||
HiddenApiSettings.update(). Also disallow nulls in process start
|
||||
arguments.
|
||||
|
||||
Bug: 316153291
|
||||
Test: Treehugger for now
|
||||
(cherry picked from commit 7ba059e2cf0a2c20f9a849719cdc32b12c933a44)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:60669aa49aba34c0950d6246bd95b54f91a3c8e8)
|
||||
Merged-In: I83cd60e46407a4a082f9f3c80e937dbd522dbac4
|
||||
Change-Id: I83cd60e46407a4a082f9f3c80e937dbd522dbac4
|
||||
---
|
||||
core/java/android/os/ZygoteProcess.java | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
|
||||
index bf2898137967..63bcf5f119e1 100644
|
||||
--- a/core/java/android/os/ZygoteProcess.java
|
||||
+++ b/core/java/android/os/ZygoteProcess.java
|
||||
@@ -431,6 +431,8 @@ private Process.ProcessStartResult zygoteSendArgsAndGetResult(
|
||||
throw new ZygoteStartFailedEx("Embedded newlines not allowed");
|
||||
} else if (arg.indexOf('\r') >= 0) {
|
||||
throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
|
||||
+ } else if (arg.indexOf('\u0000') >= 0) {
|
||||
+ throw new ZygoteStartFailedEx("Embedded nulls not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,6 +974,14 @@ private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfE
|
||||
return true;
|
||||
}
|
||||
|
||||
+ for (/* NonNull */ String s : mApiDenylistExemptions) {
|
||||
+ // indexOf() is intrinsified and faster than contains().
|
||||
+ if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) {
|
||||
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character");
|
||||
+ mApiDenylistExemptions = Collections.emptyList();
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
try {
|
||||
state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
|
||||
state.mZygoteOutputWriter.newLine();
|
61
Patches/LineageOS-20.0/ASB-2024-06/fwb-10.patch
Normal file
61
Patches/LineageOS-20.0/ASB-2024-06/fwb-10.patch
Normal file
@ -0,0 +1,61 @@
|
||||
From cbf4c6352bf85e4d8289d6bc1135d66c95f0e1e1 Mon Sep 17 00:00:00 2001
|
||||
From: Guojing Yuan <guojing@google.com>
|
||||
Date: Thu, 14 Dec 2023 19:30:04 +0000
|
||||
Subject: [PATCH] [CDM][CMD] Check permissions for CDM shell commands
|
||||
|
||||
Override handleShellCommand instead of onShellCommand because
|
||||
Binder.onShellCommand checks the necessary permissions of the caller.
|
||||
|
||||
Bug: 313428840
|
||||
|
||||
Test: manually tested CDM shell commands
|
||||
(cherry picked from commit 1761a0fee9c2cd9787bbb7fbdbe30b4c2b03396e)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1ae3b43c248cdf5ee63311f06acd0ee19d93f0cd)
|
||||
Merged-In: I5539b3594feb5544c458c0fd1061b51a0a808900
|
||||
Change-Id: I5539b3594feb5544c458c0fd1061b51a0a808900
|
||||
---
|
||||
.../CompanionDeviceManagerService.java | 20 ++++++++-----------
|
||||
1 file changed, 8 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
||||
index 41546d2bdc38..05c29d7e446a 100644
|
||||
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
||||
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
||||
@@ -75,12 +75,11 @@
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
+import android.os.ParcelFileDescriptor;
|
||||
import android.os.PowerWhitelistManager;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
-import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
-import android.os.ShellCallback;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -827,16 +826,13 @@ public boolean canPairWithoutPrompt(String packageName, String macAddress, int u
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||
- String[] args, ShellCallback callback, ResultReceiver resultReceiver)
|
||||
- throws RemoteException {
|
||||
- enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
|
||||
-
|
||||
- final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
|
||||
- CompanionDeviceManagerService.this,
|
||||
- mAssociationStore,
|
||||
- mDevicePresenceMonitor);
|
||||
- cmd.exec(this, in, out, err, args, callback, resultReceiver);
|
||||
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
|
||||
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
|
||||
+ @NonNull String[] args) {
|
||||
+ return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this,
|
||||
+ mAssociationStore, mDevicePresenceMonitor)
|
||||
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
|
||||
+ err.getFileDescriptor(), args);
|
||||
}
|
||||
|
||||
@Override
|
912
Patches/LineageOS-20.0/ASB-2024-06/fwb-11.patch
Normal file
912
Patches/LineageOS-20.0/ASB-2024-06/fwb-11.patch
Normal file
@ -0,0 +1,912 @@
|
||||
From d444b292de11e14d41a5ce1897cd32360d065671 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= <matiashe@google.com>
|
||||
Date: Fri, 22 Mar 2024 14:26:23 +0100
|
||||
Subject: [PATCH] Resolve message/conversation image Uris with the correct user
|
||||
id
|
||||
|
||||
Bug: 317503801
|
||||
Test: atest ExpandableNotificationRowTest
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:83975c515773d345c64cadac1cd639ae5c4a8397)
|
||||
Merged-In: I11c5b39f2d9d8f0788acab43640a6d4abcd5a179
|
||||
Change-Id: I11c5b39f2d9d8f0788acab43640a6d4abcd5a179
|
||||
---
|
||||
.../row/ExpandableNotificationRow.java | 13 +-
|
||||
.../row/NotificationInlineImageResolver.java | 7 +-
|
||||
.../row/ExpandableNotificationRowTest.java | 554 +++++-------------
|
||||
.../systemui/SysuiTestableContext.java | 22 +
|
||||
4 files changed, 194 insertions(+), 402 deletions(-)
|
||||
|
||||
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 11598e0c1f51..1cec84a5b02d 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
|
||||
@@ -45,6 +45,7 @@
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.Trace;
|
||||
+import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
@@ -1669,8 +1670,6 @@ void logSkipAttachingKeepInParentChild(
|
||||
*/
|
||||
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
- mImageResolver = new NotificationInlineImageResolver(context,
|
||||
- new NotificationInlineImageCache());
|
||||
float radius = getResources().getDimension(R.dimen.notification_corner_radius_small);
|
||||
mSmallRoundness = radius / getMaxRadius();
|
||||
initDimens();
|
||||
@@ -1706,6 +1705,8 @@ public void initialize(
|
||||
FeatureFlags featureFlags,
|
||||
IStatusBarService statusBarService) {
|
||||
mEntry = entry;
|
||||
+ mImageResolver = new NotificationInlineImageResolver(userContextForEntry(mContext, entry),
|
||||
+ new NotificationInlineImageCache());
|
||||
mAppName = appName;
|
||||
if (mMenuRow == null) {
|
||||
mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier);
|
||||
@@ -1743,6 +1744,14 @@ public void initialize(
|
||||
mFeatureFlags = featureFlags;
|
||||
}
|
||||
|
||||
+ private static Context userContextForEntry(Context base, NotificationEntry entry) {
|
||||
+ if (base.getUserId() == entry.getSbn().getNormalizedUserId()) {
|
||||
+ return base;
|
||||
+ }
|
||||
+ return base.createContextAsUser(
|
||||
+ UserHandle.of(entry.getSbn().getNormalizedUserId()), /* flags= */ 0);
|
||||
+ }
|
||||
+
|
||||
private void initDimens() {
|
||||
mMaxSmallHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
|
||||
R.dimen.notification_min_height_legacy);
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
|
||||
index c620f448b3b7..3e932aa616b8 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
|
||||
@@ -66,7 +66,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
|
||||
* @param imageCache The implementation of internal cache.
|
||||
*/
|
||||
public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
|
||||
- mContext = context.getApplicationContext();
|
||||
+ mContext = context;
|
||||
mImageCache = imageCache;
|
||||
|
||||
if (mImageCache != null) {
|
||||
@@ -76,6 +76,11 @@ public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
|
||||
updateMaxImageSizes();
|
||||
}
|
||||
|
||||
+ @VisibleForTesting
|
||||
+ public Context getContext() {
|
||||
+ return mContext;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* Check if this resolver has its internal cache implementation.
|
||||
* @return True if has its internal cache, false otherwise.
|
||||
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
|
||||
index 957b0f10ec1f..67aae77eee36 100644
|
||||
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
|
||||
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
|
||||
@@ -23,11 +23,14 @@
|
||||
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
|
||||
import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
|
||||
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL;
|
||||
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG;
|
||||
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
+import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
@@ -38,37 +41,29 @@
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
-import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
-import android.graphics.Color;
|
||||
-import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
-import android.graphics.drawable.AnimationDrawable;
|
||||
-import android.graphics.drawable.Drawable;
|
||||
+import android.content.Context;
|
||||
+import android.os.UserHandle;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
-import android.widget.ImageView;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.R;
|
||||
-import com.android.internal.widget.CachingIconView;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
-import com.android.systemui.flags.FakeFeatureFlags;
|
||||
-import com.android.systemui.flags.Flags;
|
||||
+import com.android.systemui.SysuiTestableContext;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
|
||||
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
||||
-import com.android.systemui.statusbar.notification.SourceType;
|
||||
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
|
||||
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
|
||||
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
|
||||
|
||||
import org.junit.Assert;
|
||||
@@ -80,16 +75,20 @@
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
-import java.util.Arrays;
|
||||
import java.util.List;
|
||||
-import java.util.function.Consumer;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class ExpandableNotificationRowTest extends SysuiTestCase {
|
||||
|
||||
+ private ExpandableNotificationRow mGroupRow;
|
||||
+ private ExpandableNotificationRow mNotifRow;
|
||||
+ private ExpandableNotificationRow mPublicRow;
|
||||
+
|
||||
private NotificationTestHelper mNotificationTestHelper;
|
||||
+ boolean mHeadsUpAnimatingAway = false;
|
||||
+
|
||||
@Rule public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Before
|
||||
@@ -100,109 +99,87 @@ public void setUp() throws Exception {
|
||||
mDependency,
|
||||
TestableLooper.get(this));
|
||||
mNotificationTestHelper.setDefaultInflationFlags(FLAG_CONTENT_VIEW_ALL);
|
||||
+ // create a standard private notification row
|
||||
+ Notification normalNotif = mNotificationTestHelper.createNotification();
|
||||
+ normalNotif.publicVersion = null;
|
||||
+ mNotifRow = mNotificationTestHelper.createRow(normalNotif);
|
||||
+ // create a notification row whose public version is identical
|
||||
+ Notification publicNotif = mNotificationTestHelper.createNotification();
|
||||
+ publicNotif.publicVersion = mNotificationTestHelper.createNotification();
|
||||
+ mPublicRow = mNotificationTestHelper.createRow(publicNotif);
|
||||
+ // create a group row
|
||||
+ mGroupRow = mNotificationTestHelper.createGroup();
|
||||
+ mGroupRow.setHeadsUpAnimatingAwayListener(
|
||||
+ animatingAway -> mHeadsUpAnimatingAway = animatingAway);
|
||||
|
||||
- FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
|
||||
- fakeFeatureFlags.set(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE, true);
|
||||
- fakeFeatureFlags.set(Flags.SENSITIVE_REVEAL_ANIM, false);
|
||||
- mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags);
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testUpdateBackgroundColors_isRecursive() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- group.setTintColor(Color.RED);
|
||||
- group.getChildNotificationAt(0).setTintColor(Color.GREEN);
|
||||
- group.getChildNotificationAt(1).setTintColor(Color.BLUE);
|
||||
-
|
||||
- assertThat(group.getCurrentBackgroundTint()).isEqualTo(Color.RED);
|
||||
- assertThat(group.getChildNotificationAt(0).getCurrentBackgroundTint())
|
||||
- .isEqualTo(Color.GREEN);
|
||||
- assertThat(group.getChildNotificationAt(1).getCurrentBackgroundTint())
|
||||
- .isEqualTo(Color.BLUE);
|
||||
-
|
||||
- group.updateBackgroundColors();
|
||||
-
|
||||
- int resetTint = group.getCurrentBackgroundTint();
|
||||
- assertThat(resetTint).isNotEqualTo(Color.RED);
|
||||
- assertThat(group.getChildNotificationAt(0).getCurrentBackgroundTint())
|
||||
- .isEqualTo(resetTint);
|
||||
- assertThat(group.getChildNotificationAt(1).getCurrentBackgroundTint())
|
||||
- .isEqualTo(resetTint);
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws Exception {
|
||||
+ public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws InterruptedException {
|
||||
// GIVEN a sensitive notification row that's currently redacted
|
||||
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
- measureAndLayout(row);
|
||||
- row.setHideSensitiveForIntrinsicHeight(true);
|
||||
- row.setSensitive(true, true);
|
||||
- assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout());
|
||||
- assertThat(row.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ measureAndLayout(mNotifRow);
|
||||
+ mNotifRow.setHideSensitiveForIntrinsicHeight(true);
|
||||
+ mNotifRow.setSensitive(true, true);
|
||||
+ assertThat(mNotifRow.getShowingLayout()).isSameInstanceAs(mNotifRow.getPublicLayout());
|
||||
+ assertThat(mNotifRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
|
||||
// GIVEN that the row has a height change listener
|
||||
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
|
||||
- row.setOnHeightChangedListener(listener);
|
||||
+ mNotifRow.setOnHeightChangedListener(listener);
|
||||
|
||||
// WHEN the row is set to no longer be sensitive
|
||||
- row.setSensitive(false, true);
|
||||
+ mNotifRow.setSensitive(false, true);
|
||||
|
||||
// VERIFY that the height change listener is invoked
|
||||
- assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPrivateLayout());
|
||||
- assertThat(row.getIntrinsicHeight()).isGreaterThan(0);
|
||||
- verify(listener).onHeightChanged(eq(row), eq(false));
|
||||
+ assertThat(mNotifRow.getShowingLayout()).isSameInstanceAs(mNotifRow.getPrivateLayout());
|
||||
+ assertThat(mNotifRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ verify(listener).onHeightChanged(eq(mNotifRow), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testSetSensitiveOnGroupRowNotifiesOfHeightChange() throws Exception {
|
||||
+ public void testSetSensitiveOnGroupRowNotifiesOfHeightChange() {
|
||||
// GIVEN a sensitive group row that's currently redacted
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- measureAndLayout(group);
|
||||
- group.setHideSensitiveForIntrinsicHeight(true);
|
||||
- group.setSensitive(true, true);
|
||||
- assertThat(group.getShowingLayout()).isSameInstanceAs(group.getPublicLayout());
|
||||
- assertThat(group.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ measureAndLayout(mGroupRow);
|
||||
+ mGroupRow.setHideSensitiveForIntrinsicHeight(true);
|
||||
+ mGroupRow.setSensitive(true, true);
|
||||
+ assertThat(mGroupRow.getShowingLayout()).isSameInstanceAs(mGroupRow.getPublicLayout());
|
||||
+ assertThat(mGroupRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
|
||||
// GIVEN that the row has a height change listener
|
||||
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
|
||||
- group.setOnHeightChangedListener(listener);
|
||||
+ mGroupRow.setOnHeightChangedListener(listener);
|
||||
|
||||
// WHEN the row is set to no longer be sensitive
|
||||
- group.setSensitive(false, true);
|
||||
+ mGroupRow.setSensitive(false, true);
|
||||
|
||||
// VERIFY that the height change listener is invoked
|
||||
- assertThat(group.getShowingLayout()).isSameInstanceAs(group.getPrivateLayout());
|
||||
- assertThat(group.getIntrinsicHeight()).isGreaterThan(0);
|
||||
- verify(listener).onHeightChanged(eq(group), eq(false));
|
||||
+ assertThat(mGroupRow.getShowingLayout()).isSameInstanceAs(mGroupRow.getPrivateLayout());
|
||||
+ assertThat(mGroupRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ verify(listener).onHeightChanged(eq(mGroupRow), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange() throws Exception {
|
||||
- // create a notification row whose public version is identical
|
||||
- Notification publicNotif = mNotificationTestHelper.createNotification();
|
||||
- publicNotif.publicVersion = mNotificationTestHelper.createNotification();
|
||||
- ExpandableNotificationRow publicRow = mNotificationTestHelper.createRow(publicNotif);
|
||||
-
|
||||
+ public void testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange() {
|
||||
// GIVEN a sensitive public row that's currently redacted
|
||||
- measureAndLayout(publicRow);
|
||||
- publicRow.setHideSensitiveForIntrinsicHeight(true);
|
||||
- publicRow.setSensitive(true, true);
|
||||
- assertThat(publicRow.getShowingLayout()).isSameInstanceAs(publicRow.getPublicLayout());
|
||||
- assertThat(publicRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ measureAndLayout(mPublicRow);
|
||||
+ mPublicRow.setHideSensitiveForIntrinsicHeight(true);
|
||||
+ mPublicRow.setSensitive(true, true);
|
||||
+ assertThat(mPublicRow.getShowingLayout()).isSameInstanceAs(mPublicRow.getPublicLayout());
|
||||
+ assertThat(mPublicRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
|
||||
// GIVEN that the row has a height change listener
|
||||
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
|
||||
- publicRow.setOnHeightChangedListener(listener);
|
||||
+ mPublicRow.setOnHeightChangedListener(listener);
|
||||
|
||||
// WHEN the row is set to no longer be sensitive
|
||||
- publicRow.setSensitive(false, true);
|
||||
+ mPublicRow.setSensitive(false, true);
|
||||
|
||||
// VERIFY that the height change listener is not invoked, because the height didn't change
|
||||
- assertThat(publicRow.getShowingLayout()).isSameInstanceAs(publicRow.getPrivateLayout());
|
||||
- assertThat(publicRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
- assertThat(publicRow.getPrivateLayout().getMinHeight())
|
||||
- .isEqualTo(publicRow.getPublicLayout().getMinHeight());
|
||||
- verify(listener, never()).onHeightChanged(eq(publicRow), eq(false));
|
||||
+ assertThat(mPublicRow.getShowingLayout()).isSameInstanceAs(mPublicRow.getPrivateLayout());
|
||||
+ assertThat(mPublicRow.getIntrinsicHeight()).isGreaterThan(0);
|
||||
+ assertThat(mPublicRow.getPrivateLayout().getMinHeight())
|
||||
+ .isEqualTo(mPublicRow.getPublicLayout().getMinHeight());
|
||||
+ verify(listener, never()).onHeightChanged(eq(mPublicRow), eq(false));
|
||||
}
|
||||
|
||||
private void measureAndLayout(ExpandableNotificationRow row) {
|
||||
@@ -219,44 +196,39 @@ private void measureAndLayout(ExpandableNotificationRow row) {
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testGroupSummaryNotShowingIconWhenPublic() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- group.setSensitive(true, true);
|
||||
- group.setHideSensitiveForIntrinsicHeight(true);
|
||||
- assertTrue(group.isSummaryWithChildren());
|
||||
- assertFalse(group.isShowingIcon());
|
||||
+ public void testGroupSummaryNotShowingIconWhenPublic() {
|
||||
+ mGroupRow.setSensitive(true, true);
|
||||
+ mGroupRow.setHideSensitiveForIntrinsicHeight(true);
|
||||
+ assertTrue(mGroupRow.isSummaryWithChildren());
|
||||
+ assertFalse(mGroupRow.isShowingIcon());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testNotificationHeaderVisibleWhenAnimating() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- group.setSensitive(true, true);
|
||||
- group.setHideSensitive(true, false, 0, 0);
|
||||
- group.setHideSensitive(false, true, 0, 0);
|
||||
- assertEquals(View.VISIBLE, group.getChildrenContainer().getVisibleWrapper()
|
||||
+ public void testNotificationHeaderVisibleWhenAnimating() {
|
||||
+ mGroupRow.setSensitive(true, true);
|
||||
+ mGroupRow.setHideSensitive(true, false, 0, 0);
|
||||
+ mGroupRow.setHideSensitive(false, true, 0, 0);
|
||||
+ assertEquals(View.VISIBLE, mGroupRow.getChildrenContainer().getVisibleWrapper()
|
||||
.getNotificationHeader().getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testUserLockedResetEvenWhenNoChildren() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- group.setUserLocked(true);
|
||||
- group.setUserLocked(false);
|
||||
+ public void testUserLockedResetEvenWhenNoChildren() {
|
||||
+ mGroupRow.setUserLocked(true);
|
||||
+ mGroupRow.removeAllChildren();
|
||||
+ mGroupRow.setUserLocked(false);
|
||||
assertFalse("The childrencontainer should not be userlocked but is, the state "
|
||||
- + "seems out of sync.", group.getChildrenContainer().isUserLocked());
|
||||
+ + "seems out of sync.", mGroupRow.getChildrenContainer().isUserLocked());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testReinflatedOnDensityChange() throws Exception {
|
||||
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
+ public void testReinflatedOnDensityChange() {
|
||||
+ mGroupRow.setUserLocked(true);
|
||||
+ mGroupRow.removeAllChildren();
|
||||
+ mGroupRow.setUserLocked(false);
|
||||
NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
|
||||
- row.setChildrenContainer(mockContainer);
|
||||
-
|
||||
- row.onDensityOrFontScaleChanged();
|
||||
-
|
||||
+ mGroupRow.setChildrenContainer(mockContainer);
|
||||
+ mGroupRow.onDensityOrFontScaleChanged();
|
||||
verify(mockContainer).reInflateViews(any(), any());
|
||||
}
|
||||
|
||||
@@ -269,6 +241,17 @@ public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
|
||||
verify(row).updateShelfIconColor();
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void setNeedsRedactionFreesViewWhenFalse() throws Exception {
|
||||
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
|
||||
+ row.setNeedsRedaction(true);
|
||||
+ row.getPublicLayout().setVisibility(View.GONE);
|
||||
+
|
||||
+ row.setNeedsRedaction(false);
|
||||
+ TestableLooper.get(this).processAllMessages();
|
||||
+ assertNull(row.getPublicLayout().getContractedChild());
|
||||
+ }
|
||||
+
|
||||
@Test
|
||||
public void testAboveShelfChangedListenerCalled() throws Exception {
|
||||
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
@@ -298,73 +281,64 @@ public void testAboveShelfChangedListenerCalledHeadsUpGoingAway() throws Excepti
|
||||
@Test
|
||||
public void testAboveShelfChangedListenerCalledWhenGoingBelow() throws Exception {
|
||||
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
+ row.setHeadsUp(true);
|
||||
AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);
|
||||
row.setAboveShelfChangedListener(listener);
|
||||
- Mockito.reset(listener);
|
||||
- row.setHeadsUp(true);
|
||||
row.setAboveShelf(false);
|
||||
verify(listener).onAboveShelfStateChanged(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClickSound() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- assertTrue("Should play sounds by default.", group.isSoundEffectsEnabled());
|
||||
+ assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled());
|
||||
StatusBarStateController mock = mNotificationTestHelper.getStatusBarStateController();
|
||||
when(mock.isDozing()).thenReturn(true);
|
||||
- group.setSecureStateProvider(()-> false);
|
||||
+ mGroupRow.setSecureStateProvider(()-> false);
|
||||
assertFalse("Shouldn't play sounds when dark and trusted.",
|
||||
- group.isSoundEffectsEnabled());
|
||||
- group.setSecureStateProvider(()-> true);
|
||||
+ mGroupRow.isSoundEffectsEnabled());
|
||||
+ mGroupRow.setSecureStateProvider(()-> true);
|
||||
assertTrue("Should always play sounds when not trusted.",
|
||||
- group.isSoundEffectsEnabled());
|
||||
+ mGroupRow.isSoundEffectsEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testSetDismissed_longPressListenerRemoved() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
+ public void testSetDismissed_longPressListenerRemoved() {
|
||||
ExpandableNotificationRow.LongPressListener listener =
|
||||
mock(ExpandableNotificationRow.LongPressListener.class);
|
||||
- group.setLongPressListener(listener);
|
||||
- group.doLongClickCallback(0, 0);
|
||||
- verify(listener, times(1)).onLongPress(eq(group), eq(0), eq(0),
|
||||
+ mGroupRow.setLongPressListener(listener);
|
||||
+ mGroupRow.doLongClickCallback(0,0);
|
||||
+ verify(listener, times(1)).onLongPress(eq(mGroupRow), eq(0), eq(0),
|
||||
any(NotificationMenuRowPlugin.MenuItem.class));
|
||||
reset(listener);
|
||||
|
||||
- group.dismiss(true);
|
||||
- group.doLongClickCallback(0, 0);
|
||||
- verify(listener, times(0)).onLongPress(eq(group), eq(0), eq(0),
|
||||
+ mGroupRow.dismiss(true);
|
||||
+ mGroupRow.doLongClickCallback(0,0);
|
||||
+ verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0),
|
||||
any(NotificationMenuRowPlugin.MenuItem.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testFeedback_noHeader() throws Exception {
|
||||
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
+ public void testFeedback_noHeader() {
|
||||
// public notification is custom layout - no header
|
||||
- groupRow.setSensitive(true, true);
|
||||
- groupRow.setOnFeedbackClickListener(null);
|
||||
- groupRow.setFeedbackIcon(null);
|
||||
+ mGroupRow.setSensitive(true, true);
|
||||
+ mGroupRow.setOnFeedbackClickListener(null);
|
||||
+ mGroupRow.setFeedbackIcon(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testFeedback_header() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
+ public void testFeedback_header() {
|
||||
NotificationContentView publicLayout = mock(NotificationContentView.class);
|
||||
- group.setPublicLayout(publicLayout);
|
||||
+ mGroupRow.setPublicLayout(publicLayout);
|
||||
NotificationContentView privateLayout = mock(NotificationContentView.class);
|
||||
- group.setPrivateLayout(privateLayout);
|
||||
+ mGroupRow.setPrivateLayout(privateLayout);
|
||||
NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
|
||||
when(mockContainer.getNotificationChildCount()).thenReturn(1);
|
||||
- group.setChildrenContainer(mockContainer);
|
||||
+ mGroupRow.setChildrenContainer(mockContainer);
|
||||
|
||||
final boolean show = true;
|
||||
final FeedbackIcon icon = new FeedbackIcon(
|
||||
R.drawable.ic_feedback_alerted, R.string.notification_feedback_indicator_alerted);
|
||||
- group.setFeedbackIcon(icon);
|
||||
+ mGroupRow.setFeedbackIcon(icon);
|
||||
|
||||
verify(mockContainer, times(1)).setFeedbackIcon(icon);
|
||||
verify(privateLayout, times(1)).setFeedbackIcon(icon);
|
||||
@@ -372,49 +346,43 @@ public void testFeedback_header() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testFeedbackOnClick() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
+ public void testFeedbackOnClick() {
|
||||
ExpandableNotificationRow.CoordinateOnClickListener l = mock(
|
||||
ExpandableNotificationRow.CoordinateOnClickListener.class);
|
||||
View view = mock(View.class);
|
||||
|
||||
- group.setOnFeedbackClickListener(l);
|
||||
+ mGroupRow.setOnFeedbackClickListener(l);
|
||||
|
||||
- group.getFeedbackOnClickListener().onClick(view);
|
||||
+ mGroupRow.getFeedbackOnClickListener().onClick(view);
|
||||
verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testHeadsUpAnimatingAwayListener() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- Consumer<Boolean> headsUpListener = mock(Consumer.class);
|
||||
- AboveShelfChangedListener aboveShelfChangedListener = mock(AboveShelfChangedListener.class);
|
||||
- group.setHeadsUpAnimatingAwayListener(headsUpListener);
|
||||
- group.setAboveShelfChangedListener(aboveShelfChangedListener);
|
||||
-
|
||||
- group.setHeadsUpAnimatingAway(true);
|
||||
- verify(headsUpListener).accept(true);
|
||||
- verify(aboveShelfChangedListener).onAboveShelfStateChanged(true);
|
||||
-
|
||||
- group.setHeadsUpAnimatingAway(false);
|
||||
- verify(headsUpListener).accept(false);
|
||||
- verify(aboveShelfChangedListener).onAboveShelfStateChanged(false);
|
||||
+ public void testHeadsUpAnimatingAwayListener() {
|
||||
+ mGroupRow.setHeadsUpAnimatingAway(true);
|
||||
+ Assert.assertEquals(true, mHeadsUpAnimatingAway);
|
||||
+ mGroupRow.setHeadsUpAnimatingAway(false);
|
||||
+ Assert.assertEquals(false, mHeadsUpAnimatingAway);
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testGetNumUniqueChildren_defaultChannel() throws Exception {
|
||||
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
|
||||
+ public void testIsBlockingHelperShowing_isCorrectlyUpdated() {
|
||||
+ mGroupRow.setBlockingHelperShowing(true);
|
||||
+ assertTrue(mGroupRow.isBlockingHelperShowing());
|
||||
|
||||
- assertEquals(1, groupRow.getNumUniqueChannels());
|
||||
+ mGroupRow.setBlockingHelperShowing(false);
|
||||
+ assertFalse(mGroupRow.isBlockingHelperShowing());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testGetNumUniqueChildren_multiChannel() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
+ public void testGetNumUniqueChildren_defaultChannel() {
|
||||
+ assertEquals(1, mGroupRow.getNumUniqueChannels());
|
||||
+ }
|
||||
|
||||
+ @Test
|
||||
+ public void testGetNumUniqueChildren_multiChannel() {
|
||||
List<ExpandableNotificationRow> childRows =
|
||||
- group.getChildrenContainer().getAttachedChildren();
|
||||
+ mGroupRow.getChildrenContainer().getAttachedChildren();
|
||||
// Give each child a unique channel id/name.
|
||||
int i = 0;
|
||||
for (ExpandableNotificationRow childRow : childRows) {
|
||||
@@ -426,29 +394,25 @@ public void testGetNumUniqueChildren_multiChannel() throws Exception {
|
||||
i++;
|
||||
}
|
||||
|
||||
- assertEquals(3, group.getNumUniqueChannels());
|
||||
+ assertEquals(3, mGroupRow.getNumUniqueChannels());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIconScrollXAfterTranslationAndReset() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- group.setDismissUsingRowTranslationX(false);
|
||||
- group.setTranslation(50);
|
||||
- assertEquals(50, -group.getEntry().getIcons().getShelfIcon().getScrollX());
|
||||
+ mGroupRow.setDismissUsingRowTranslationX(false);
|
||||
+ mGroupRow.setTranslation(50);
|
||||
+ assertEquals(50, -mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX());
|
||||
|
||||
- group.resetTranslation();
|
||||
- assertEquals(0, group.getEntry().getIcons().getShelfIcon().getScrollX());
|
||||
+ mGroupRow.resetTranslation();
|
||||
+ assertEquals(0, mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX());
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testIsExpanded_userExpanded() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
-
|
||||
- group.setExpandable(true);
|
||||
- Assert.assertFalse(group.isExpanded());
|
||||
- group.setUserExpanded(true);
|
||||
- Assert.assertTrue(group.isExpanded());
|
||||
+ public void testIsExpanded_userExpanded() {
|
||||
+ mGroupRow.setExpandable(true);
|
||||
+ Assert.assertFalse(mGroupRow.isExpanded());
|
||||
+ mGroupRow.setUserExpanded(true);
|
||||
+ Assert.assertTrue(mGroupRow.isExpanded());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -492,230 +456,22 @@ public void testCannotDismissOngoing() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testAddChildNotification() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(0);
|
||||
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
|
||||
+ public void imageResolver_sameNotificationUser_usesContext() throws Exception {
|
||||
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
|
||||
+ USER_HANDLE.getUid(1234), USER_HANDLE);
|
||||
|
||||
- group.addChildNotification(child);
|
||||
-
|
||||
- Assert.assertEquals(child, group.getChildNotificationAt(0));
|
||||
- Assert.assertEquals(group, child.getNotificationParent());
|
||||
- Assert.assertTrue(child.isChildInGroup());
|
||||
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testAddChildNotification_childSkipped() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(0);
|
||||
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
|
||||
- child.setKeepInParentForDismissAnimation(true);
|
||||
-
|
||||
- group.addChildNotification(child);
|
||||
-
|
||||
- Assert.assertTrue(group.getAttachedChildren().isEmpty());
|
||||
- Assert.assertNotEquals(group, child.getNotificationParent());
|
||||
- verify(mNotificationTestHelper.getMockLogger()).logSkipAttachingKeepInParentChild(
|
||||
- /*child=*/ child.getEntry(),
|
||||
- /*newParent=*/ group.getEntry()
|
||||
- );
|
||||
- }
|
||||
+ public void imageResolver_differentNotificationUser_createsUserContext() throws Exception {
|
||||
+ UserHandle user = new UserHandle(33);
|
||||
+ Context userContext = new SysuiTestableContext(mContext);
|
||||
+ mContext.prepareCreateContextAsUser(user, userContext);
|
||||
|
||||
- @Test
|
||||
- public void testRemoveChildNotification() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
|
||||
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
|
||||
- child.setKeepInParentForDismissAnimation(true);
|
||||
-
|
||||
- group.removeChildNotification(child);
|
||||
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
|
||||
+ user.getUid(1234), user);
|
||||
|
||||
- Assert.assertNull(child.getParent());
|
||||
- Assert.assertNull(child.getNotificationParent());
|
||||
- Assert.assertFalse(child.keepInParentForDismissAnimation());
|
||||
- verifyNoMoreInteractions(mNotificationTestHelper.getMockLogger());
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testRemoveChildrenWithKeepInParent_removesChildWithKeepInParent() throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
|
||||
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
|
||||
- child.setKeepInParentForDismissAnimation(true);
|
||||
-
|
||||
- group.removeChildrenWithKeepInParent();
|
||||
-
|
||||
- Assert.assertNull(child.getParent());
|
||||
- Assert.assertNull(child.getNotificationParent());
|
||||
- Assert.assertFalse(child.keepInParentForDismissAnimation());
|
||||
- verify(mNotificationTestHelper.getMockLogger()).logKeepInParentChildDetached(
|
||||
- /*child=*/ child.getEntry(),
|
||||
- /*oldParent=*/ group.getEntry()
|
||||
- );
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testRemoveChildrenWithKeepInParent_skipsChildrenWithoutKeepInParent()
|
||||
- throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
|
||||
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
|
||||
-
|
||||
- group.removeChildrenWithKeepInParent();
|
||||
-
|
||||
- Assert.assertEquals(group, child.getNotificationParent());
|
||||
- Assert.assertFalse(child.keepInParentForDismissAnimation());
|
||||
- verify(mNotificationTestHelper.getMockLogger(), never()).logKeepInParentChildDetached(
|
||||
- /*child=*/ any(),
|
||||
- /*oldParent=*/ any()
|
||||
- );
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void applyRoundnessAndInv_should_be_immediately_applied_on_childrenContainer_legacy()
|
||||
- throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- group.useRoundnessSourceTypes(false);
|
||||
- Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
|
||||
- Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
|
||||
-
|
||||
- group.requestBottomRoundness(1f, SourceType.from(""), false);
|
||||
-
|
||||
- Assert.assertEquals(1f, group.getBottomRoundness(), 0.001f);
|
||||
- Assert.assertEquals(1f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_childrenContainer()
|
||||
- throws Exception {
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- group.useRoundnessSourceTypes(true);
|
||||
- Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
|
||||
- Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
|
||||
-
|
||||
- group.requestBottomRoundness(1f, SourceType.from(""), false);
|
||||
-
|
||||
- Assert.assertEquals(1f, group.getBottomRoundness(), 0.001f);
|
||||
- Assert.assertEquals(1f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testSetContentAnimationRunning_Run() throws Exception {
|
||||
- // Create views for the notification row.
|
||||
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
- NotificationContentView publicLayout = mock(NotificationContentView.class);
|
||||
- row.setPublicLayout(publicLayout);
|
||||
- NotificationContentView privateLayout = mock(NotificationContentView.class);
|
||||
- row.setPrivateLayout(privateLayout);
|
||||
-
|
||||
- row.setAnimationRunning(true);
|
||||
- verify(publicLayout, times(1)).setContentAnimationRunning(true);
|
||||
- verify(privateLayout, times(1)).setContentAnimationRunning(true);
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testSetContentAnimationRunning_Stop() throws Exception {
|
||||
- // Create views for the notification row.
|
||||
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
- NotificationContentView publicLayout = mock(NotificationContentView.class);
|
||||
- row.setPublicLayout(publicLayout);
|
||||
- NotificationContentView privateLayout = mock(NotificationContentView.class);
|
||||
- row.setPrivateLayout(privateLayout);
|
||||
-
|
||||
- row.setAnimationRunning(false);
|
||||
- verify(publicLayout, times(1)).setContentAnimationRunning(false);
|
||||
- verify(privateLayout, times(1)).setContentAnimationRunning(false);
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- public void testSetContentAnimationRunningInGroupChild_Run() throws Exception {
|
||||
- // Creates parent views on groupRow.
|
||||
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
|
||||
- NotificationContentView publicParentLayout = mock(NotificationContentView.class);
|
||||
- groupRow.setPublicLayout(publicParentLayout);
|
||||
- NotificationContentView privateParentLayout = mock(NotificationContentView.class);
|
||||
- groupRow.setPrivateLayout(privateParentLayout);
|
||||
-
|
||||
- // Create child views on row.
|
||||
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
|
||||
- NotificationContentView publicChildLayout = mock(NotificationContentView.class);
|
||||
- row.setPublicLayout(publicChildLayout);
|
||||
- NotificationContentView privateChildLayout = mock(NotificationContentView.class);
|
||||
- row.setPrivateLayout(privateChildLayout);
|
||||
- when(row.isGroupExpanded()).thenReturn(true);
|
||||
- setMockChildrenContainer(groupRow, row);
|
||||
-
|
||||
- groupRow.setAnimationRunning(true);
|
||||
- verify(publicParentLayout, times(1)).setContentAnimationRunning(true);
|
||||
- verify(privateParentLayout, times(1)).setContentAnimationRunning(true);
|
||||
- // The child layouts should be started too.
|
||||
- verify(publicChildLayout, times(1)).setContentAnimationRunning(true);
|
||||
- verify(privateChildLayout, times(1)).setContentAnimationRunning(true);
|
||||
- }
|
||||
-
|
||||
-
|
||||
- @Test
|
||||
- public void testSetIconAnimationRunningGroup_Run() throws Exception {
|
||||
- // Create views for a group row.
|
||||
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
|
||||
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
|
||||
- NotificationContentView publicParentLayout = mock(NotificationContentView.class);
|
||||
- group.setPublicLayout(publicParentLayout);
|
||||
- NotificationContentView privateParentLayout = mock(NotificationContentView.class);
|
||||
- group.setPrivateLayout(privateParentLayout);
|
||||
- when(group.isGroupExpanded()).thenReturn(true);
|
||||
-
|
||||
- // Add the child to the group.
|
||||
- NotificationContentView publicChildLayout = mock(NotificationContentView.class);
|
||||
- child.setPublicLayout(publicChildLayout);
|
||||
- NotificationContentView privateChildLayout = mock(NotificationContentView.class);
|
||||
- child.setPrivateLayout(privateChildLayout);
|
||||
- when(child.isGroupExpanded()).thenReturn(true);
|
||||
-
|
||||
- NotificationChildrenContainer mockContainer =
|
||||
- setMockChildrenContainer(group, child);
|
||||
-
|
||||
- // Mock the children view wrappers, and give them each an icon.
|
||||
- NotificationViewWrapper mockViewWrapper = mock(NotificationViewWrapper.class);
|
||||
- when(mockContainer.getNotificationViewWrapper()).thenReturn(mockViewWrapper);
|
||||
- CachingIconView mockIcon = mock(CachingIconView.class);
|
||||
- when(mockViewWrapper.getIcon()).thenReturn(mockIcon);
|
||||
-
|
||||
- NotificationViewWrapper mockLowPriorityViewWrapper = mock(NotificationViewWrapper.class);
|
||||
- when(mockContainer.getLowPriorityViewWrapper()).thenReturn(mockLowPriorityViewWrapper);
|
||||
- CachingIconView mockLowPriorityIcon = mock(CachingIconView.class);
|
||||
- when(mockLowPriorityViewWrapper.getIcon()).thenReturn(mockLowPriorityIcon);
|
||||
-
|
||||
- // Give the icon image views drawables, so we can make sure they animate.
|
||||
- // We use both AnimationDrawables and AnimatedVectorDrawables to ensure both work.
|
||||
- AnimationDrawable drawable = mock(AnimationDrawable.class);
|
||||
- AnimatedVectorDrawable vectorDrawable = mock(AnimatedVectorDrawable.class);
|
||||
- setDrawableIconsInImageView(mockIcon, drawable, vectorDrawable);
|
||||
-
|
||||
- AnimationDrawable lowPriDrawable = mock(AnimationDrawable.class);
|
||||
- AnimatedVectorDrawable lowPriVectorDrawable = mock(AnimatedVectorDrawable.class);
|
||||
- setDrawableIconsInImageView(mockLowPriorityIcon, lowPriDrawable, lowPriVectorDrawable);
|
||||
-
|
||||
- group.setAnimationRunning(true);
|
||||
- verify(drawable, times(1)).start();
|
||||
- verify(vectorDrawable, times(1)).start();
|
||||
- verify(lowPriDrawable, times(1)).start();
|
||||
- verify(lowPriVectorDrawable, times(1)).start();
|
||||
- }
|
||||
-
|
||||
- private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
|
||||
- Drawable rightIconDrawable) {
|
||||
- ImageView iconView = mock(ImageView.class);
|
||||
- when(icon.findViewById(com.android.internal.R.id.icon)).thenReturn(iconView);
|
||||
- when(iconView.getDrawable()).thenReturn(iconDrawable);
|
||||
-
|
||||
- ImageView rightIconView = mock(ImageView.class);
|
||||
- when(icon.findViewById(com.android.internal.R.id.right_icon)).thenReturn(rightIconView);
|
||||
- when(rightIconView.getDrawable()).thenReturn(rightIconDrawable);
|
||||
- }
|
||||
-
|
||||
- private NotificationChildrenContainer setMockChildrenContainer(
|
||||
- ExpandableNotificationRow parentRow, ExpandableNotificationRow childRow) {
|
||||
- List<ExpandableNotificationRow> rowList = Arrays.asList(childRow);
|
||||
- NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
|
||||
- when(mockContainer.getNotificationChildCount()).thenReturn(1);
|
||||
- when(mockContainer.getAttachedChildren()).thenReturn(rowList);
|
||||
- parentRow.setChildrenContainer(mockContainer);
|
||||
- return mockContainer;
|
||||
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(userContext);
|
||||
}
|
||||
}
|
||||
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
|
||||
index 0674ea855d7f..fd2914e02a76 100644
|
||||
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
|
||||
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
+import android.annotation.NonNull;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -28,12 +29,15 @@
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SysuiTestableContext extends TestableContext {
|
||||
|
||||
@GuardedBy("mRegisteredReceivers")
|
||||
private final Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
|
||||
+ private final Map<UserHandle, Context> mContextForUser = new HashMap<>();
|
||||
|
||||
public SysuiTestableContext(Context base) {
|
||||
super(base);
|
||||
@@ -146,4 +150,22 @@ public void unregisterReceiver(BroadcastReceiver receiver) {
|
||||
}
|
||||
super.unregisterReceiver(receiver);
|
||||
}
|
||||
+
|
||||
+ /**
|
||||
+ * Sets a Context object that will be returned as the result of {@link #createContextAsUser}
|
||||
+ * for a specific {@code user}.
|
||||
+ */
|
||||
+ public void prepareCreateContextAsUser(UserHandle user, Context context) {
|
||||
+ mContextForUser.put(user, context);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @NonNull
|
||||
+ public Context createContextAsUser(UserHandle user, int flags) {
|
||||
+ Context userContext = mContextForUser.get(user);
|
||||
+ if (userContext != null) {
|
||||
+ return userContext;
|
||||
+ }
|
||||
+ return super.createContextAsUser(user, flags);
|
||||
+ }
|
||||
}
|
59
Patches/LineageOS-20.0/ASB-2024-06/fwb-12.patch
Normal file
59
Patches/LineageOS-20.0/ASB-2024-06/fwb-12.patch
Normal file
@ -0,0 +1,59 @@
|
||||
From e3979baab5718a69f6d58040ba42f67b4fd73d35 Mon Sep 17 00:00:00 2001
|
||||
From: Ameer Armaly <aarmaly@google.com>
|
||||
Date: Fri, 8 Mar 2024 19:41:06 +0000
|
||||
Subject: [PATCH] [RESTRICT AUTOMERGE] AccessibilityManagerService: remove
|
||||
uninstalled services from enabled list after service update.
|
||||
|
||||
Bug: 326485767
|
||||
Test: atest AccessibilityEndToEndTest#testUpdateServiceWithoutIntent_disablesService
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:766911c3312573196b33efd1c3c29ccece806846)
|
||||
Merged-In: I958d58953b300c8093335a22e207baac471ae9f9
|
||||
Change-Id: I958d58953b300c8093335a22e207baac471ae9f9
|
||||
---
|
||||
.../AccessibilityManagerService.java | 22 +++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
|
||||
index 3818a884c94a..8271aed181c9 100644
|
||||
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
|
||||
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
|
||||
@@ -2161,10 +2161,13 @@ private void updateServicesLocked(AccessibilityUserState userState) {
|
||||
boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
|
||||
.isUserUnlockingOrUnlocked(userState.mUserId);
|
||||
|
||||
+ // Store the list of installed services.
|
||||
+ mTempComponentNameSet.clear();
|
||||
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
|
||||
AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
|
||||
ComponentName componentName = ComponentName.unflattenFromString(
|
||||
installedService.getId());
|
||||
+ mTempComponentNameSet.add(componentName);
|
||||
|
||||
AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
|
||||
|
||||
@@ -2215,6 +2218,25 @@ this, getTraceManager(), mWindowManagerService,
|
||||
audioManager.setAccessibilityServiceUids(mTempIntArray);
|
||||
}
|
||||
mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
|
||||
+ // If any services have been removed, remove them from the enabled list and the touch
|
||||
+ // exploration granted list.
|
||||
+ boolean anyServiceRemoved =
|
||||
+ userState.mEnabledServices.removeIf((comp) -> !mTempComponentNameSet.contains(comp))
|
||||
+ || userState.mTouchExplorationGrantedServices.removeIf(
|
||||
+ (comp) -> !mTempComponentNameSet.contains(comp));
|
||||
+ if (anyServiceRemoved) {
|
||||
+ // Update the enabled services setting.
|
||||
+ persistComponentNamesToSettingLocked(
|
||||
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
+ userState.mEnabledServices,
|
||||
+ userState.mUserId);
|
||||
+ // Update the touch exploration granted services setting.
|
||||
+ persistComponentNamesToSettingLocked(
|
||||
+ Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
|
||||
+ userState.mTouchExplorationGrantedServices,
|
||||
+ userState.mUserId);
|
||||
+ }
|
||||
+ mTempComponentNameSet.clear();
|
||||
updateAccessibilityEnabledSettingLocked(userState);
|
||||
}
|
||||
|
274
Patches/LineageOS-20.0/ASB-2024-06/fwb-13.patch
Normal file
274
Patches/LineageOS-20.0/ASB-2024-06/fwb-13.patch
Normal file
@ -0,0 +1,274 @@
|
||||
From 56ef52af608d4c74da25da50023b63fb3680159f Mon Sep 17 00:00:00 2001
|
||||
From: Beth Thibodeau <ethibodeau@google.com>
|
||||
Date: Tue, 19 Mar 2024 16:49:51 -0500
|
||||
Subject: [PATCH] Update media_controls_lock_screen setting behavior
|
||||
|
||||
When the setting is disabled, hide the media carousel everywhere when
|
||||
the device is on lockscreen, not just in the keyguard layout
|
||||
|
||||
Bug: 314333719
|
||||
Test: manual
|
||||
Test: atest MediaHierarchyManagerTest
|
||||
Flag: NONE
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a441f4acd62cce1059818ce8e9b7ab93b0079e50)
|
||||
Merged-In: I4f618e4013db894291e6fca9d49bceb1cb7e4bd9
|
||||
Change-Id: I4f618e4013db894291e6fca9d49bceb1cb7e4bd9
|
||||
---
|
||||
.../controls/ui/KeyguardMediaController.kt | 40 -------------------
|
||||
.../controls/ui/MediaHierarchyManager.kt | 27 +++++++++----
|
||||
.../systemui/media/controls/ui/MediaHost.kt | 4 +-
|
||||
.../ui/KeyguardMediaControllerTest.kt | 28 -------------
|
||||
4 files changed, 22 insertions(+), 77 deletions(-)
|
||||
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
|
||||
index 30ee147e302a..2a2882cf7108 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
|
||||
@@ -18,16 +18,10 @@ package com.android.systemui.media.controls.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
-import android.database.ContentObserver
|
||||
-import android.net.Uri
|
||||
-import android.os.Handler
|
||||
-import android.os.UserHandle
|
||||
-import android.provider.Settings
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
-import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
@@ -36,7 +30,6 @@ import com.android.systemui.statusbar.notification.stack.MediaContainerView
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.LargeScreenUtils
|
||||
-import com.android.systemui.util.settings.SecureSettings
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
@@ -52,8 +45,6 @@ constructor(
|
||||
private val bypassController: KeyguardBypassController,
|
||||
private val statusBarStateController: SysuiStatusBarStateController,
|
||||
private val context: Context,
|
||||
- private val secureSettings: SecureSettings,
|
||||
- @Main private val handler: Handler,
|
||||
configurationController: ConfigurationController,
|
||||
) {
|
||||
|
||||
@@ -77,26 +68,6 @@ constructor(
|
||||
}
|
||||
)
|
||||
|
||||
- val settingsObserver: ContentObserver =
|
||||
- object : ContentObserver(handler) {
|
||||
- override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
- if (uri == lockScreenMediaPlayerUri) {
|
||||
- allowMediaPlayerOnLockScreen =
|
||||
- secureSettings.getBoolForUser(
|
||||
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
|
||||
- true,
|
||||
- UserHandle.USER_CURRENT
|
||||
- )
|
||||
- refreshMediaPosition()
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- secureSettings.registerContentObserverForUser(
|
||||
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
|
||||
- settingsObserver,
|
||||
- UserHandle.USER_ALL
|
||||
- )
|
||||
-
|
||||
// First let's set the desired state that we want for this host
|
||||
mediaHost.expansion = MediaHostState.EXPANDED
|
||||
mediaHost.showsOnlyActiveMedia = true
|
||||
@@ -133,16 +104,6 @@ constructor(
|
||||
private set
|
||||
private var splitShadeContainer: ViewGroup? = null
|
||||
|
||||
- /** Track the media player setting status on lock screen. */
|
||||
- private var allowMediaPlayerOnLockScreen: Boolean =
|
||||
- secureSettings.getBoolForUser(
|
||||
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
|
||||
- true,
|
||||
- UserHandle.USER_CURRENT
|
||||
- )
|
||||
- private val lockScreenMediaPlayerUri =
|
||||
- secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
|
||||
-
|
||||
/**
|
||||
* Attaches media container in single pane mode, situated at the top of the notifications list
|
||||
*/
|
||||
@@ -202,7 +163,6 @@ constructor(
|
||||
mediaHost.visible &&
|
||||
!bypassController.bypassEnabled &&
|
||||
keyguardOrUserSwitcher &&
|
||||
- allowMediaPlayerOnLockScreen &&
|
||||
shouldBeVisibleForSplitShade()
|
||||
if (visible) {
|
||||
showMediaPlayer()
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
|
||||
index 54237ce7cf25..f0ff1292311d 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
|
||||
@@ -104,7 +104,7 @@ constructor(
|
||||
) {
|
||||
|
||||
/** Track the media player setting status on lock screen. */
|
||||
- private var allowMediaPlayerOnLockScreen: Boolean = true
|
||||
+ private var allowMediaPlayerOnLockScreen: Boolean = getMediaLockScreenSetting()
|
||||
private val lockScreenMediaPlayerUri =
|
||||
secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
|
||||
|
||||
@@ -462,6 +462,7 @@ constructor(
|
||||
}
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
|
||||
isVisibleToUser()
|
||||
+ mediaCarouselController.updateHostVisibility()
|
||||
}
|
||||
|
||||
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
||||
@@ -538,7 +539,6 @@ constructor(
|
||||
mediaCarouselController.updateHostVisibility = {
|
||||
mediaHosts.forEach { it?.updateViewVisibility() }
|
||||
}
|
||||
-
|
||||
panelEventsEvents.addShadeStateEventsListener(
|
||||
object : ShadeStateEventsListener {
|
||||
override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
|
||||
@@ -552,12 +552,8 @@ constructor(
|
||||
object : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
if (uri == lockScreenMediaPlayerUri) {
|
||||
- allowMediaPlayerOnLockScreen =
|
||||
- secureSettings.getBoolForUser(
|
||||
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
|
||||
- true,
|
||||
- UserHandle.USER_CURRENT
|
||||
- )
|
||||
+ allowMediaPlayerOnLockScreen = getMediaLockScreenSetting()
|
||||
+ mediaCarouselController.updateHostVisibility()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -568,6 +564,14 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
+ private fun getMediaLockScreenSetting(): Boolean {
|
||||
+ return secureSettings.getBoolForUser(
|
||||
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
|
||||
+ true,
|
||||
+ UserHandle.USER_CURRENT
|
||||
+ )
|
||||
+ }
|
||||
+
|
||||
private fun updateConfiguration() {
|
||||
distanceForFullShadeTransition =
|
||||
context.resources.getDimensionPixelSize(
|
||||
@@ -607,6 +611,13 @@ constructor(
|
||||
mediaCarouselController.closeGuts()
|
||||
}
|
||||
|
||||
+ /** Return true if the carousel should be hidden because lockscreen is currently visible */
|
||||
+ fun isLockedAndHidden(): Boolean {
|
||||
+ return !allowMediaPlayerOnLockScreen &&
|
||||
+ (statusbarState == StatusBarState.SHADE_LOCKED ||
|
||||
+ statusbarState == StatusBarState.KEYGUARD)
|
||||
+ }
|
||||
+
|
||||
private fun createUniqueObjectHost(): UniqueObjectHostView {
|
||||
val viewHost = UniqueObjectHostView(context)
|
||||
viewHost.addOnAttachStateChangeListener(
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
|
||||
index be570b4a1119..26580e54cd62 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
|
||||
@@ -199,7 +199,9 @@ constructor(
|
||||
*/
|
||||
fun updateViewVisibility() {
|
||||
state.visible =
|
||||
- if (showsOnlyActiveMedia) {
|
||||
+ if (mediaHierarchyManager.isLockedAndHidden()) {
|
||||
+ false
|
||||
+ } else if (showsOnlyActiveMedia) {
|
||||
mediaDataManager.hasActiveMediaOrRecommendation()
|
||||
} else {
|
||||
mediaDataManager.hasAnyMediaOrRecommendation()
|
||||
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
|
||||
index b40ebc9bb156..41b3fe65599f 100644
|
||||
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
|
||||
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.systemui.media.controls.ui
|
||||
|
||||
-import android.provider.Settings
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
@@ -32,8 +31,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.animation.UniqueObjectHostView
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
-import com.android.systemui.util.settings.FakeSettings
|
||||
-import com.android.systemui.utils.os.FakeHandler
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
@@ -60,10 +57,7 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
|
||||
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
|
||||
private val hostView = UniqueObjectHostView(context)
|
||||
- private val settings = FakeSettings()
|
||||
private lateinit var keyguardMediaController: KeyguardMediaController
|
||||
- private lateinit var testableLooper: TestableLooper
|
||||
- private lateinit var fakeHandler: FakeHandler
|
||||
private lateinit var statusBarStateListener: StatusBarStateController.StateListener
|
||||
|
||||
@Before
|
||||
@@ -79,16 +73,12 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(mediaHost.hostView).thenReturn(hostView)
|
||||
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
|
||||
- testableLooper = TestableLooper.get(this)
|
||||
- fakeHandler = FakeHandler(testableLooper.looper)
|
||||
keyguardMediaController =
|
||||
KeyguardMediaController(
|
||||
mediaHost,
|
||||
bypassController,
|
||||
statusBarStateController,
|
||||
context,
|
||||
- settings,
|
||||
- fakeHandler,
|
||||
configurationController,
|
||||
)
|
||||
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
|
||||
@@ -117,24 +107,6 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
assertThat(mediaContainerView.visibility).isEqualTo(visibility)
|
||||
}
|
||||
|
||||
- @Test
|
||||
- fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
|
||||
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
|
||||
-
|
||||
- keyguardMediaController.refreshMediaPosition()
|
||||
-
|
||||
- assertThat(mediaContainerView.visibility).isEqualTo(GONE)
|
||||
- }
|
||||
-
|
||||
- @Test
|
||||
- fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
|
||||
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
|
||||
-
|
||||
- keyguardMediaController.refreshMediaPosition()
|
||||
-
|
||||
- assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
|
||||
- }
|
||||
-
|
||||
@Test
|
||||
fun testActivatesSplitShadeContainerInSplitShadeMode() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
64
Patches/LineageOS-20.0/ASB-2024-06/libfmq-01.patch
Normal file
64
Patches/LineageOS-20.0/ASB-2024-06/libfmq-01.patch
Normal file
@ -0,0 +1,64 @@
|
||||
From 9a005ebebfa638ed42415301fec30b16bef30299 Mon Sep 17 00:00:00 2001
|
||||
From: Devin Moore <devinmoore@google.com>
|
||||
Date: Mon, 22 Jan 2024 17:52:16 +0000
|
||||
Subject: [PATCH] Use the values of the ptrs that we check
|
||||
|
||||
Test: fmq_fuzzer
|
||||
Bug: 321326147
|
||||
Bug: 321341508
|
||||
Bug: 321383085
|
||||
(cherry picked from https://android-review.googlesource.com/q/commit:38963310ad5789b625ca0bca9f9c2c8e24666651)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:050952bf5f9bd035e469ce005300115d563e524a)
|
||||
Merged-In: I56fe4fe72180e39ecef066353969c1ae9fbcd44e
|
||||
Change-Id: I56fe4fe72180e39ecef066353969c1ae9fbcd44e
|
||||
---
|
||||
include/fmq/MessageQueueBase.h | 24 ++++++++++++++++++++----
|
||||
1 file changed, 20 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
|
||||
index f4bf7e2..0bf0bb2 100644
|
||||
--- a/include/fmq/MessageQueueBase.h
|
||||
+++ b/include/fmq/MessageQueueBase.h
|
||||
@@ -1034,8 +1034,16 @@ bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t
|
||||
}
|
||||
|
||||
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
|
||||
-size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
|
||||
- return mDesc->getSize() - availableToReadBytes();
|
||||
+inline size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
|
||||
+ size_t queueSizeBytes = mDesc->getSize();
|
||||
+ size_t availableBytes = availableToReadBytes();
|
||||
+ if (queueSizeBytes < availableBytes) {
|
||||
+ hardware::details::logError(
|
||||
+ "The write or read pointer has become corrupted. Reading from the queue is no "
|
||||
+ "longer possible.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return queueSizeBytes - availableBytes;
|
||||
}
|
||||
|
||||
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
|
||||
@@ -1117,13 +1125,21 @@ MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
|
||||
}
|
||||
|
||||
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
|
||||
-size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
|
||||
+inline size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
|
||||
/*
|
||||
* This method is invoked by implementations of both read() and write() and
|
||||
* hence requires a memory_order_acquired load for both mReadPtr and
|
||||
* mWritePtr.
|
||||
*/
|
||||
- return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
|
||||
+ uint64_t writePtr = mWritePtr->load(std::memory_order_acquire);
|
||||
+ uint64_t readPtr = mReadPtr->load(std::memory_order_acquire);
|
||||
+ if (writePtr < readPtr) {
|
||||
+ hardware::details::logError(
|
||||
+ "The write or read pointer has become corrupted. Reading from the queue is no "
|
||||
+ "longer possible.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return writePtr - readPtr;
|
||||
}
|
||||
|
||||
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
|
87
Patches/LineageOS-20.0/ASB-2024-06/statsd-01.patch
Normal file
87
Patches/LineageOS-20.0/ASB-2024-06/statsd-01.patch
Normal file
@ -0,0 +1,87 @@
|
||||
From 7c36c8764f78a135a4d273e8ff7200beef767e18 Mon Sep 17 00:00:00 2001
|
||||
From: Vova Sharaienko <sharaienko@google.com>
|
||||
Date: Wed, 27 Mar 2024 23:21:03 +0000
|
||||
Subject: [PATCH] [libstatssocket] Added validation for adding new data into
|
||||
StatsEvent
|
||||
|
||||
Bug: 330054251
|
||||
Test: atest StatsEventTest#TestHeapBufferOverflowError
|
||||
Ignore-AOSP-First: security
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4f6c56889356a5a422b59c71e9142875d00e43bf)
|
||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e440696c4fd6d44d21451467294b3e31c6867e08)
|
||||
Merged-In: I27c69d9875b494f98a2a961cdd4fe139cd809387
|
||||
Change-Id: I27c69d9875b494f98a2a961cdd4fe139cd809387
|
||||
---
|
||||
lib/libstatssocket/stats_event.c | 3 ++
|
||||
lib/libstatssocket/tests/stats_event_test.cpp | 44 +++++++++++++++++++
|
||||
2 files changed, 47 insertions(+)
|
||||
|
||||
diff --git a/lib/libstatssocket/stats_event.c b/lib/libstatssocket/stats_event.c
|
||||
index 9bb4c52c4..828ff3e4f 100644
|
||||
--- a/lib/libstatssocket/stats_event.c
|
||||
+++ b/lib/libstatssocket/stats_event.c
|
||||
@@ -330,6 +330,9 @@ void AStatsEvent_writeStringArray(AStatsEvent* event, const char* const* element
|
||||
|
||||
// Side-effect: modifies event->errors if field has too many annotations
|
||||
static void increment_annotation_count(AStatsEvent* event) {
|
||||
+ if (event->lastFieldPos >= event->bufSize) {
|
||||
+ return;
|
||||
+ }
|
||||
uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
|
||||
uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
|
||||
uint32_t newAnnotationCount = oldAnnotationCount + 1;
|
||||
diff --git a/lib/libstatssocket/tests/stats_event_test.cpp b/lib/libstatssocket/tests/stats_event_test.cpp
|
||||
index 93a99f1bf..dea81c256 100644
|
||||
--- a/lib/libstatssocket/tests/stats_event_test.cpp
|
||||
+++ b/lib/libstatssocket/tests/stats_event_test.cpp
|
||||
@@ -536,6 +536,50 @@ TEST(StatsEventTest, TestPushOverflowError) {
|
||||
AStatsEvent_release(event);
|
||||
}
|
||||
|
||||
+TEST(StatsEventTest, TestHeapBufferOverflowError) {
|
||||
+ const std::string testString(4039, 'A');
|
||||
+ const std::string testString2(47135, 'B');
|
||||
+
|
||||
+ AStatsEvent* event = AStatsEvent_obtain();
|
||||
+ AStatsEvent_setAtomId(event, 100);
|
||||
+
|
||||
+ AStatsEvent_writeString(event, testString.c_str());
|
||||
+ size_t bufferSize = 0;
|
||||
+ AStatsEvent_getBuffer(event, &bufferSize);
|
||||
+ EXPECT_EQ(bufferSize, 4060);
|
||||
+ uint32_t errors = AStatsEvent_getErrors(event);
|
||||
+ EXPECT_EQ(errors, 0);
|
||||
+
|
||||
+ // expand the buffer and fill with data up to the very last byte
|
||||
+ AStatsEvent_writeString(event, testString2.c_str());
|
||||
+ bufferSize = 0;
|
||||
+ AStatsEvent_getBuffer(event, &bufferSize);
|
||||
+ EXPECT_EQ(bufferSize, 50 * 1024);
|
||||
+
|
||||
+ errors = AStatsEvent_getErrors(event);
|
||||
+ EXPECT_EQ(errors, 0);
|
||||
+
|
||||
+ // this write is no-op due to buffer reached its max capacity
|
||||
+ // should set the overflow flag
|
||||
+ AStatsEvent_writeString(event, testString2.c_str());
|
||||
+ bufferSize = 0;
|
||||
+ AStatsEvent_getBuffer(event, &bufferSize);
|
||||
+ EXPECT_EQ(bufferSize, 50 * 1024);
|
||||
+
|
||||
+ errors = AStatsEvent_getErrors(event);
|
||||
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
|
||||
+
|
||||
+ // here should be crash
|
||||
+ AStatsEvent_addBoolAnnotation(event, 1, false);
|
||||
+
|
||||
+ AStatsEvent_write(event);
|
||||
+
|
||||
+ errors = AStatsEvent_getErrors(event);
|
||||
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
|
||||
+
|
||||
+ AStatsEvent_release(event);
|
||||
+}
|
||||
+
|
||||
TEST(StatsEventTest, TestPullOverflowError) {
|
||||
const uint32_t atomId = 10100;
|
||||
const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
|
@ -1 +1 @@
|
||||
Subproject commit 2fc97e971f72f95e21f7b5685f16a839a77a977a
|
||||
Subproject commit bc2e6dd93df6ce9ad928f8d75bd2584c940461ac
|
@ -95,7 +95,6 @@ applyPatch "$DOS_PATCHES_COMMON/android_build/0001-verity-openssl3.patch"; #Fix
|
||||
sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches.
|
||||
awk -i inplace '!/updatable_apex.mk/' target/product/generic_system.mk; #Disable APEX
|
||||
sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_defaults.mk; #Set the minimum supported target SDK to Pie (GrapheneOS)
|
||||
sed -i 's/2024-04-05/2024-05-05/' core/version_defaults.mk; #Bump Security String #x_asb_2024-05
|
||||
fi;
|
||||
|
||||
if enterAndClear "build/soong"; then
|
||||
@ -125,12 +124,7 @@ sed -i '/LOCAL_MODULE/s/Camera/SecureCamera/' Android.mk; #Change module name
|
||||
sed -i '11iLOCAL_OVERRIDES_PACKAGES := Camera Camera2 LegacyCamera Snap OpenCamera' Android.mk; #Replace the others
|
||||
fi;
|
||||
|
||||
if enterAndClear "external/sonivox"; then
|
||||
applyPatch "$DOS_PATCHES_COMMON/android_external_sonivox/392224.patch"; #T_asb_2024-05 Fix buffer overrun in eas_wtengine
|
||||
fi;
|
||||
|
||||
if enterAndClear "frameworks/base"; then
|
||||
applyPatch "$DOS_PATCHES/android_frameworks_base/392225.patch"; #T_asb_2024-05 Prioritize system toasts
|
||||
git revert --no-edit 83fe523914728a3674debba17a6019cb74803045; #Reverts "Allow signature spoofing for microG Companion/Services" in favor of below patch
|
||||
applyPatch "$DOS_PATCHES/android_frameworks_base/344888-backport.patch"; #fixup! fw/b: Add support for allowing/disallowing apps on cellular, vpn and wifi networks (CalyxOS)
|
||||
applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS)
|
||||
|
@ -94,6 +94,7 @@ applyPatch "$DOS_PATCHES/android_build/0003-Exec_Based_Spawning.patch"; #Add exe
|
||||
applyPatch "$DOS_PATCHES/android_build/0004-Selective_APEX.patch"; #Only enable APEX on 6th/7th gen Pixel devices (GrapheneOS)
|
||||
sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches.
|
||||
sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_util.mk; #Set the minimum supported target SDK to Pie (GrapheneOS)
|
||||
sed -i 's/2024-05-05/2024-06-05/' core/version_defaults.mk; #Bump Security String #x_asb_2024-06
|
||||
fi;
|
||||
|
||||
if enterAndClear "build/soong"; then
|
||||
@ -122,6 +123,7 @@ git am $DOS_PATCHES/ASB-2023-10/av-*.patch;
|
||||
fi;
|
||||
|
||||
if enterAndClear "frameworks/base"; then
|
||||
git am $DOS_PATCHES/ASB-2024-06/fwb-*.patch;
|
||||
git revert --no-edit d36faad3267522c6d3ff91ba9dcca8f6274bccd1; #Reverts "JobScheduler: Respect allow-in-power-save perm" in favor of below patch
|
||||
git revert --no-edit 90d6826548189ca850d91692e71fcc1be426f453; #Reverts "Remove sensitive info from SUPL requests" in favor of below patch
|
||||
git revert --no-edit 6d2955f0bd55e9938d5d49415182c27b50900b95; #Reverts "Allow signature spoofing for microG Companion/Services" in favor of below patch
|
||||
@ -372,6 +374,10 @@ applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0005-Browser_No_Loc
|
||||
applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0006-Location_Indicators.patch"; #SystemUI: Use new privacy indicators for location (GrapheneOS)
|
||||
fi;
|
||||
|
||||
if enterAndClear "packages/modules/StatsD"; then
|
||||
git am $DOS_PATCHES/ASB-2024-06/statsd-*.patch;
|
||||
fi;
|
||||
|
||||
if enterAndClear "packages/modules/Wifi"; then
|
||||
applyPatch "$DOS_PATCHES/android_packages_modules_Wifi/344228.patch"; #wifi: resurrect mWifiLinkLayerStatsSupported counter (sassmann)
|
||||
applyPatch "$DOS_PATCHES/android_packages_modules_Wifi/0001-Random_MAC.patch"; #Add support for always generating new random MAC (GrapheneOS)
|
||||
@ -399,6 +405,10 @@ if enterAndClear "system/extras"; then
|
||||
applyPatch "$DOS_PATCHES/android_system_extras/0001-ext4_pad_filenames.patch"; #FBE: pad filenames more (GrapheneOS)
|
||||
fi;
|
||||
|
||||
if enterAndClear "system/libfmq"; then
|
||||
git am $DOS_PATCHES/ASB-2024-06/libfmq-*.patch;
|
||||
fi;
|
||||
|
||||
if enterAndClear "system/sepolicy"; then
|
||||
applyPatch "$DOS_PATCHES/android_system_sepolicy/0002-protected_files.patch"; #Label protected_{fifos,regular} as proc_security (GrapheneOS)
|
||||
applyPatch "$DOS_PATCHES/android_system_sepolicy/0003-ptrace_scope-1.patch"; #Allow init to control kernel.yama.ptrace_scope (GrapheneOS)
|
||||
|
Loading…
Reference in New Issue
Block a user